From d6e283df8ca4713ce3126b33ac6f37a79e0a9fc6 Mon Sep 17 00:00:00 2001 From: raph Date: Mon, 13 Nov 2023 21:43:30 +0100 Subject: [PATCH 01/41] Fix lost sats bug (#2666) --- src/index.rs | 8 +- src/index/updater.rs | 247 ++++++++++++++++++++++--------------------- 2 files changed, 131 insertions(+), 124 deletions(-) diff --git a/src/index.rs b/src/index.rs index 9ce53cfaca..9f56aea601 100644 --- a/src/index.rs +++ b/src/index.rs @@ -2348,7 +2348,9 @@ mod tests { #[test] fn lost_sats_are_tracked_correctly() { - let context = Context::builder().arg("--index-sats").build(); + let context = Context::builder() + .args(["--index-sats", "--first-inscription-height", "10"]) + .build(); assert_eq!(context.index.statistic(Statistic::LostSats), 0); context.mine_blocks(1); @@ -2375,7 +2377,9 @@ mod tests { #[test] fn lost_sat_ranges_are_tracked_correctly() { - let context = Context::builder().arg("--index-sats").build(); + let context = Context::builder() + .args(["--index-sats", "--first-inscription-height", "10"]) + .build(); let null_ranges = || match context.index.list(OutPoint::null()).unwrap().unwrap() { List::Unspent(ranges) => ranges, diff --git a/src/index/updater.rs b/src/index/updater.rs index 4affe64fdf..71521efc63 100644 --- a/src/index/updater.rs +++ b/src/index/updater.rs @@ -410,147 +410,150 @@ impl<'index> Updater<'_> { .map(|unbound_inscriptions| unbound_inscriptions.value()) .unwrap_or(0); - { - let mut inscription_updater = InscriptionUpdater::new( - self.height, - &mut inscription_id_to_children, - &mut inscription_id_to_satpoint, - value_receiver, - &mut inscription_id_to_inscription_entry, - lost_sats, - &mut inscription_number_to_inscription_id, - cursed_inscription_count, - blessed_inscription_count, - &mut sequence_number_to_inscription_id, - &mut outpoint_to_value, - &mut sat_to_inscription_id, - &mut satpoint_to_inscription_id, - block.header.time, - unbound_inscriptions, - value_cache, - )?; - - if self.index.index_sats { - let mut sat_to_satpoint = wtx.open_table(SAT_TO_SATPOINT)?; - let mut outpoint_to_sat_ranges = wtx.open_table(OUTPOINT_TO_SAT_RANGES)?; + let mut inscription_updater = InscriptionUpdater::new( + self.height, + &mut inscription_id_to_children, + &mut inscription_id_to_satpoint, + value_receiver, + &mut inscription_id_to_inscription_entry, + lost_sats, + &mut inscription_number_to_inscription_id, + cursed_inscription_count, + blessed_inscription_count, + &mut sequence_number_to_inscription_id, + &mut outpoint_to_value, + &mut sat_to_inscription_id, + &mut satpoint_to_inscription_id, + block.header.time, + unbound_inscriptions, + value_cache, + )?; - let mut coinbase_inputs = VecDeque::new(); + if self.index.index_sats { + let mut sat_to_satpoint = wtx.open_table(SAT_TO_SATPOINT)?; + let mut outpoint_to_sat_ranges = wtx.open_table(OUTPOINT_TO_SAT_RANGES)?; - let h = Height(self.height); - if h.subsidy() > 0 { - let start = h.starting_sat(); - coinbase_inputs.push_front((start.n(), (start + h.subsidy()).n())); - self.sat_ranges_since_flush += 1; - } + let mut coinbase_inputs = VecDeque::new(); - for (tx_offset, (tx, txid)) in block.txdata.iter().enumerate().skip(1) { - log::trace!("Indexing transaction {tx_offset}…"); + let h = Height(self.height); + if h.subsidy() > 0 { + let start = h.starting_sat(); + coinbase_inputs.push_front((start.n(), (start + h.subsidy()).n())); + self.sat_ranges_since_flush += 1; + } - let mut input_sat_ranges = VecDeque::new(); + for (tx_offset, (tx, txid)) in block.txdata.iter().enumerate().skip(1) { + log::trace!("Indexing transaction {tx_offset}…"); - for input in &tx.input { - let key = input.previous_output.store(); + let mut input_sat_ranges = VecDeque::new(); - let sat_ranges = match self.range_cache.remove(&key) { - Some(sat_ranges) => { - self.outputs_cached += 1; - sat_ranges - } - None => outpoint_to_sat_ranges - .remove(&key)? - .ok_or_else(|| { - anyhow!("Could not find outpoint {} in index", input.previous_output) - })? - .value() - .to_vec(), - }; + for input in &tx.input { + let key = input.previous_output.store(); - for chunk in sat_ranges.chunks_exact(11) { - input_sat_ranges.push_back(SatRange::load(chunk.try_into().unwrap())); + let sat_ranges = match self.range_cache.remove(&key) { + Some(sat_ranges) => { + self.outputs_cached += 1; + sat_ranges } - } - - self.index_transaction_sats( - tx, - *txid, - &mut sat_to_satpoint, - &mut input_sat_ranges, - &mut sat_ranges_written, - &mut outputs_in_block, - &mut inscription_updater, - index_inscriptions, - )?; - - coinbase_inputs.extend(input_sat_ranges); - } + None => outpoint_to_sat_ranges + .remove(&key)? + .ok_or_else(|| anyhow!("Could not find outpoint {} in index", input.previous_output))? + .value() + .to_vec(), + }; - if let Some((tx, txid)) = block.txdata.get(0) { - self.index_transaction_sats( - tx, - *txid, - &mut sat_to_satpoint, - &mut coinbase_inputs, - &mut sat_ranges_written, - &mut outputs_in_block, - &mut inscription_updater, - index_inscriptions, - )?; + for chunk in sat_ranges.chunks_exact(11) { + input_sat_ranges.push_back(SatRange::load(chunk.try_into().unwrap())); + } } - if !coinbase_inputs.is_empty() { - let mut lost_sat_ranges = outpoint_to_sat_ranges - .remove(&OutPoint::null().store())? - .map(|ranges| ranges.value().to_vec()) - .unwrap_or_default(); - - for (start, end) in coinbase_inputs { - if !Sat(start).is_common() { - sat_to_satpoint.insert( - &start, - &SatPoint { - outpoint: OutPoint::null(), - offset: lost_sats, - } - .store(), - )?; - } + self.index_transaction_sats( + tx, + *txid, + &mut sat_to_satpoint, + &mut input_sat_ranges, + &mut sat_ranges_written, + &mut outputs_in_block, + &mut inscription_updater, + index_inscriptions, + )?; + + coinbase_inputs.extend(input_sat_ranges); + } - lost_sat_ranges.extend_from_slice(&(start, end).store()); + if let Some((tx, txid)) = block.txdata.get(0) { + self.index_transaction_sats( + tx, + *txid, + &mut sat_to_satpoint, + &mut coinbase_inputs, + &mut sat_ranges_written, + &mut outputs_in_block, + &mut inscription_updater, + index_inscriptions, + )?; + } - lost_sats += end - start; + if !coinbase_inputs.is_empty() { + let mut lost_sat_ranges = outpoint_to_sat_ranges + .remove(&OutPoint::null().store())? + .map(|ranges| ranges.value().to_vec()) + .unwrap_or_default(); + + for (start, end) in coinbase_inputs { + if !Sat(start).is_common() { + sat_to_satpoint.insert( + &start, + &SatPoint { + outpoint: OutPoint::null(), + offset: lost_sats, + } + .store(), + )?; } - outpoint_to_sat_ranges.insert(&OutPoint::null().store(), lost_sat_ranges.as_slice())?; - } - } else { - for (tx, txid) in block.txdata.iter().skip(1).chain(block.txdata.first()) { - inscription_updater.index_envelopes(tx, *txid, None)?; - } - } - - self.index_block_inscription_numbers( - &mut height_to_last_sequence_number, - &inscription_updater, - index_inscriptions, - )?; + lost_sat_ranges.extend_from_slice(&(start, end).store()); - statistic_to_count.insert(&Statistic::LostSats.key(), &inscription_updater.lost_sats)?; + lost_sats += end - start; + } - statistic_to_count.insert( - &Statistic::CursedInscriptions.key(), - &inscription_updater.cursed_inscription_count, - )?; + outpoint_to_sat_ranges.insert(&OutPoint::null().store(), lost_sat_ranges.as_slice())?; + } + } else { + for (tx, txid) in block.txdata.iter().skip(1).chain(block.txdata.first()) { + inscription_updater.index_envelopes(tx, *txid, None)?; + } + } - statistic_to_count.insert( - &Statistic::BlessedInscriptions.key(), - &inscription_updater.blessed_inscription_count, - )?; + self.index_block_inscription_numbers( + &mut height_to_last_sequence_number, + &inscription_updater, + index_inscriptions, + )?; - statistic_to_count.insert( - &Statistic::UnboundInscriptions.key(), - &inscription_updater.unbound_inscriptions, - )?; - } + statistic_to_count.insert( + &Statistic::LostSats.key(), + &if self.index.index_sats { + lost_sats + } else { + inscription_updater.lost_sats + }, + )?; + + statistic_to_count.insert( + &Statistic::CursedInscriptions.key(), + &inscription_updater.cursed_inscription_count, + )?; + + statistic_to_count.insert( + &Statistic::BlessedInscriptions.key(), + &inscription_updater.blessed_inscription_count, + )?; + + statistic_to_count.insert( + &Statistic::UnboundInscriptions.key(), + &inscription_updater.unbound_inscriptions, + )?; if index.index_runes { let mut outpoint_to_rune_balances = wtx.open_table(OUTPOINT_TO_RUNE_BALANCES)?; From b9cf53d3890cd31d585381cba03e17dee98147f5 Mon Sep 17 00:00:00 2001 From: duttydeedz <142775511+duttydeedz@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:56:20 -0500 Subject: [PATCH 02/41] Add Hindi version of handbook (#2648) --- .github/workflows/ci.yaml | 2 +- docs/po/hi.po | 5215 +++++++++++++++++++++++++++++++++++++ docs/theme/index.hbs | 3 + justfile | 2 +- 4 files changed, 5220 insertions(+), 2 deletions(-) create mode 100644 docs/po/hi.po diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 46864c367f..e1fd0197d6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,7 +14,7 @@ defaults: env: RUSTFLAGS: --deny warnings - LANGUAGES: de fr es pt ru zh ja ko fil ar + LANGUAGES: de fr es pt ru zh ja ko fil ar hi jobs: docs: diff --git a/docs/po/hi.po b/docs/po/hi.po new file mode 100644 index 0000000000..d79a1db059 --- /dev/null +++ b/docs/po/hi.po @@ -0,0 +1,5215 @@ +msgid "" +msgstr "" +"Project-Id-Version: ऑर्डिनल थ्यौरी हस्तपुस्स्तकध\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2023-10-06 10:03+0800\n" +"Last-Translator: duttydeedz @duttydeedz \n" +"Language-Team: Hindi\n" +"Language: Hi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: src/SUMMARY.md:2 src/introduction.md:1 +msgid "Introduction" +msgstr "परिचय" + +#: src/SUMMARY.md:3 +msgid "Overview" +msgstr "अवलोकन" + +#: src/SUMMARY.md:4 src/digital-artifacts.md:1 +msgid "Digital Artifacts" +msgstr "डिजिटल अभिलेख" + +#: src/SUMMARY.md:5 src/SUMMARY.md:13 src/overview.md:221 src/inscriptions.md:1 +msgid "Inscriptions" +msgstr "इंस्‍क्रीप्‍शंस" + +#: src/SUMMARY.md:6 src/inscriptions/provenance.md:1 +msgid "Provenance" +msgstr "उत्‍पति" + +#: src/SUMMARY.md:7 src/inscriptions/recursion.md:1 +msgid "Recursion" +msgstr "रिकर्सन-प्रतिवर्तन" + +#: src/SUMMARY.md:8 +msgid "FAQ" +msgstr "एफएक्‍यू" + +#: src/SUMMARY.md:9 +msgid "Contributing" +msgstr "योगदान" + +#: src/SUMMARY.md:10 src/donate.md:1 +msgid "Donate" +msgstr "दान करें" + +#: src/SUMMARY.md:11 +msgid "Guides" +msgstr "मार्गदर्शक निर्देश" + +#: src/SUMMARY.md:12 +msgid "Explorer" +msgstr "एक्‍सप्‍लोरर" + +#: src/SUMMARY.md:14 src/guides/sat-hunting.md:1 +msgid "Sat Hunting" +msgstr "सैट हंटिंग" + +#: src/SUMMARY.md:15 src/guides/collecting.md:1 +msgid "Collecting" +msgstr "संग्राहक" + +#: src/SUMMARY.md:16 src/guides/sat-hunting.md:239 +msgid "Sparrow Wallet" +msgstr "स्‍पैरो वॉलेट" + +#: src/SUMMARY.md:17 src/guides/testing.md:1 +msgid "Testing" +msgstr "परीक्षण" + +#: src/SUMMARY.md:18 src/guides/moderation.md:1 +msgid "Moderation" +msgstr "मॉडरेशन" + +#: src/SUMMARY.md:19 src/guides/reindexing.md:1 +msgid "Reindexing" +msgstr "रिइंडैक्सिंग" + +#: src/SUMMARY.md:20 +msgid "Bounties" +msgstr "बांउटीज़" + +#: src/SUMMARY.md:21 +msgid "Bounty 0: 100,000 sats Claimed!" +msgstr "बांउटी 0: 100,000 सैट्स दावा किया!" + +#: src/SUMMARY.md:22 +msgid "Bounty 1: 200,000 sats Claimed!" +msgstr "बांउटी 1: 200,000 सैट्स दावा किया!" + +#: src/SUMMARY.md:23 +msgid "Bounty 2: 300,000 sats Claimed!" +msgstr "बांउटी 2: 300,000 सैट्स दावा किया!" + +#: src/SUMMARY.md:24 +msgid "Bounty 3: 400,000 sats" +msgstr "बांउटी 3: 400,000 सैट्स दावा किया!" + +#: src/introduction.md:4 +msgid "" +"This handbook is a guide to ordinal theory. Ordinal theory concerns itself " +"with satoshis, giving them individual identities and allowing them to be " +"tracked, transferred, and imbued with meaning." +msgstr "" +"यह पुस्तिका ऑर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) के लिए एक मार्गदर्शक निदेर्शिका है। ऑर्डिनल थ्‍यौरी अपने आप में " +"सातोशी से संबंधित है, उन्हें व्यक्तिगत पहचान देकर " +"ट्रैक करने, स्थानांतरित करने और अर्थ से व्‍याप्‍त करने में सक्षम करता है।" + +#: src/introduction.md:8 +msgid "" +"Satoshis, not bitcoin, are the atomic, native currency of the Bitcoin " +"network. One bitcoin can be sub-divided into 100,000,000 satoshis, but no " +"further." +msgstr "" +"सातोशी, बिटकॉइन नहीं है, लेकिन यह बिटकॉइन नेटवर्क का न्‍यूनतम अंश और मूल मुद्रा है। " +"बिटकॉइन को अधिक से अधिक 100,000,000 सातोशियों में उप-विभाजित किया जा सकता है, " +"उससे कम नहीं।" + +#: src/introduction.md:11 +msgid "" +"Ordinal theory does not require a sidechain or token aside from Bitcoin, and " +"can be used without any changes to the Bitcoin network. It works right now." +msgstr "" +"ऑर्डिनल थ्‍यौरी में बिटकॉइन को छोड़कर किसी साइडचेन या टोकन की आवश्यकता नहीं होती है, और " +"इसका उपयोग बिना बिटकॉइन नेटवर्क में बदलाव के किया जा सकता है। वर्तमान में यह प्रचलन में है।" + +#: src/introduction.md:14 +msgid "" +"Ordinal theory imbues satoshis with numismatic value, allowing them to be " +"collected and traded as curios." +msgstr "" +"ऑर्डिनल थ्‍यौरी सातोशी का मौद्रिक मूल्य निर्धारित करता है, और उन्हें " +"क्यूरियस के रूप में संग्रह और लेनदेन करने में सक्षम बनाता है।" + +#: src/introduction.md:17 +msgid "" +"Individual satoshis can be inscribed with arbitrary content, creating unique " +"Bitcoin-native digital artifacts that can be held in Bitcoin wallets and " +"transferred using Bitcoin transactions. Inscriptions are as durable, " +"immutable, secure, and decentralized as Bitcoin itself." +msgstr "" +"प्रत्‍येक सातोशी को स्‍वेच्छित विषय-वस्‍तु के साथ इंस्‍क्राइब (उत्‍कीर्ण) किया जा सकता है, इसे अनूठी " +"बिटकॉइन-मूल डिजिटल अभिलेखों में निर्मित किया जाता है, जिन्हें आप अपने बिटकॉइन वॉलेट में संजोकर रख सकते हैं और " +"बिटकॉइन लेनदेन के माध्‍यम से स्थानांतरित कर सकते हैं। यह डिजिटल अभिलेख बिटकॉइन की " +"भांति टिकाऊ, अपरिवर्तनीय, सुरक्षित और विकेंद्रीकृत होते हैं।" + +#: src/introduction.md:22 +msgid "" +"Other, more unusual use-cases are possible: off-chain colored-coins, public " +"key infrastructure with key rotation, a decentralized replacement for the " +"DNS. For now though, such use-cases are speculative, and exist only in the " +"minds of fringe ordinal theorists." +msgstr "" +"अन्य, अधिक असामान्य उपयोग के संभव मामले हैं: ऑफ-चेन रंगीन सिक्के, " +"की (कुंजी) रोटेशन सहित सार्वजनिक की (कुंजी) का बुनियादी ढांचा, " +"डीएनएस के लिए एक विकेन्द्रीकृत प्रतिस्थापन। हालाँकि, अभी के लिए, ऐसे उपयोग के मामले काल्पनिक हैं, " +"और केवल आर्डिनल सिद्धान्‍तवादियों की कल्‍पनाओं में मौजूद हैं।" + +#: src/introduction.md:27 +msgid "For more details on ordinal theory, see the [overview](overview.md)." +msgstr "" +"ऑर्डिनल थ्‍यौरी के बारे में विस्‍तृत जानकारी के लिए [अवलोकन](overview.md) देखें।" + +#: src/introduction.md:29 +msgid "For more details on inscriptions, see [inscriptions](inscriptions.md)." +msgstr "" +"डिजिटल अभिलेखों पर अधिक जानकारी के लिए [इंस्‍क्रि‍प्‍शंस](inscriptions.md) देखें।" + +#: src/introduction.md:31 +msgid "" +"When you're ready to get your hands dirty, a good place to start is with " +"[inscriptions](guides/inscriptions.md), a curious species of digital " +"artifact enabled by ordinal theory." +msgstr "" +"जब आप इसके लिए तैयार हो जाते हैं, बेहतर होगा कि आप इसकी शुरुआत " +"[इंस्‍क्रि‍प्‍शंस](guides/inscriptions.md) से ही करें, जो आर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) " +"द्वारा सक्षम डिजिटल अभिलेखों का एक दुर्लभ प्रकार है ।" + +#: src/introduction.md:35 +msgid "Links" +msgstr "लिंक्‍स" + +#: src/introduction.md:38 +msgid "[GitHub](https://github.com/ordinals/ord/)" +msgstr "[गिटहब](https://github.com/ordinals/ord/)" + +#: src/introduction.md:39 +msgid "[BIP](https://github.com/ordinals/ord/blob/master/bip.mediawiki)" +msgstr "[बीआईपी](https://github.com/ordinals/ord/blob/master/bip.mediawiki)" + +#: src/introduction.md:40 +msgid "[Discord](https://discord.gg/ordinals)" +msgstr "[डिस्कॉर्ड](https://discord.gg/ordinals)" + +#: src/introduction.md:41 +msgid "[Open Ordinals Institute Website](https://ordinals.org/)" +msgstr "[ओपन ऑर्डिनल्स इंस्टिट्यूट वेबसाइट](https://ordinals.org/)" + +#: src/introduction.md:42 +msgid "[Open Ordinals Institute X](https://x.com/ordinalsorg)" +msgstr "[ओपन ऑर्डिनल्स इंस्टिट्यूट एक्स](https://x.com/ordinalsorg)" + +#: src/introduction.md:43 +msgid "[Mainnet Block Explorer](https://ordinals.com)" +msgstr "[मेननेट ब्लॉक एक्सप्लोरर](https://ordinals.com)" + +#: src/introduction.md:44 +msgid "[Signet Block Explorer](https://signet.ordinals.com)" +msgstr "[सिग्नेट ब्लॉक एक्सप्लोरर](https://signet.ordinals.com)" + +#: src/introduction.md:46 +msgid "Videos" +msgstr "वीडियो" + +#: src/introduction.md:49 +msgid "" +"[Ordinal Theory Explained: Satoshi Serial Numbers and NFTs on Bitcoin]" +"(https://www.youtube.com/watch?v=rSS0O2KQpsI)" +msgstr "" +"[ऑर्डिनल थ्यौरी स्पष्ट: सतोशि क्रमांक और बिटकॉइन पर एनएफटी]" +"(https://www.youtube.com/watch?v=rSS0O2KQpsI)" + +#: src/introduction.md:50 +msgid "" +"[Ordinals Workshop with Rodarmor](https://www.youtube.com/watch?" +"v=MC_haVa6N3I)" +msgstr "" +"[ऑर्डिनल्स कार्यशाला रोडआर्मर के साथ](https://www.youtube.com/watch?" +"v=MC_haVa6N3I)" + +#: src/introduction.md:51 +msgid "" +"[Ordinal Art: Mint Your own NFTs on Bitcoin w/ @rodarmor](https://www." +"youtube.com/watch?v=j5V33kV3iqo)" +msgstr "" +"[ऑर्डिनल कला: अपने एनएफटी बिटकॉइन पर मुद्रित करें w/ @rodarmor] (https://www." +"youtube.com/watch?v=j5V33kV3iqo)" + +#: src/overview.md:1 +msgid "Ordinal Theory Overview" +msgstr "आर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) का अवलोकन" + +#: src/overview.md:4 +msgid "" +"Ordinals are a numbering scheme for satoshis that allows tracking and " +"transferring individual sats. These numbers are called [ordinal numbers]" +"(https://ordinals.com). Satoshis are numbered in the order in which they're " +"mined, and transferred from transaction inputs to transaction outputs first-" +"in-first-out. Both the numbering scheme and the transfer scheme rely on " +"_order_, the numbering scheme on the _order_ in which satoshis are mined, " +"and the transfer scheme on the _order_ of transaction inputs and outputs. " +"Thus the name, _ordinals_." +msgstr "" +"ऑर्डिनल्स सातोशी के लिए एक संख्‍याकरण योजना है, जो प्रत्‍येक सैट को ट्रैक और " +"स्थानांतरित करने में सक्षम करती है। इन संख्याओं को आर्डिनल (क्रमसूचक) संख्याएँ कहा जाता है।" +"(https://ordinals.com) सातोशी को माइन (खनन) के क्रम में क्रमबद्ध किया जाता है, " +"और लेन-देन इनपुट से लेन-देन आउटपुट में फर्स्ट-इन-फर्स्ट-आउट (फीफो) स्थानांतरित कर दिया जाता है। " +"नंबरिंग स्कीम और ट्रांसफर स्कीम दोनों _क्रम_ पर निर्भर करती हैं। नंबरिंग स्कीम सातोशी खनन " +"के _क्रम_ पर निर्भर करती है, जबकि ट्रांसफर स्कीम लेनदेन इनपुट और आउटपुट के _क्रम_ पर निर्भर करती है। " +"इस प्रकार इन्‍हें, _ऑर्डिनल्स_ से संबोधित किया जाता है। " + +#: src/overview.md:13 +msgid "" +"Technical details are available in [the BIP](https://github.com/ordinals/ord/" +"blob/master/bip.mediawiki)." +msgstr "" +"इनके तकनीकी विवरण बीआईपी में उपलब्ध हैं। [the BIP](https://github.com/ordinals/ord/" +"blob/master/bip.mediawiki)." + +#: src/overview.md:16 +msgid "" +"Ordinal theory does not require a separate token, another blockchain, or any " +"changes to Bitcoin. It works right now." +msgstr "" +"आर्डिनल थ्‍यौरी के लिए अलग से टोकन, अन्‍य ब्लॉकचेन या " +"बिटकॉइन में किसी भी बदलाव करने की आवश्यकता नहीं होती है। यह तुरन्‍त काम करता है। " + +#: src/overview.md:19 +msgid "Ordinal numbers have a few different representations:" +msgstr "आर्डिनल (क्रमसूचक) संख्याओं के कुछ भिन्न निरूपण होते हैं:" + +#: src/overview.md:21 +msgid "" +"_Integer notation_: [`2099994106992659`](https://ordinals.com/" +"sat/2099994106992659) The ordinal number, assigned according to the order in " +"which the satoshi was mined." +msgstr "" +"_पूर्णांक अंकन_:[`2099994106992659`](https://ordinals.com/sat/2099994106992659) " +"आर्डिनल (क्रमसूचक) संख्या को उस क्रम के अनुसार नियत किया जाता है " +"जिस क्रम में सातोशी को माइन (खनन) किया गया था।" + +#: src/overview.md:26 +msgid "" +"_Decimal notation_: [`3891094.16797`](https://ordinals.com/" +"sat/3891094.16797) The first number is the block height in which the satoshi " +"was mined, the second the offset of the satoshi within the block." +msgstr "" +"_दशमलव अंकन_: [`3891094.16797`](https://ordinals.com/sat/3891094.16797) पहला नंबर " +"ब्लॉक की ऊंचाई होती है जिसमें सातोशी को माइन (खनन) किया गया था, " +"दूसरा ब्लॉक के भीतर सातोशी का ऑफसेट (समायोजन) है।" + +#: src/overview.md:31 +msgid "" +"_Degree notation_: [`3°111094′214″16797‴`](https://ordinals.com/" +"sat/3%C2%B0111094%E2%80%B2214%E2%80%B316797%E2%80%B4). We'll get to that in " +"a moment." +msgstr "" +"_डिग्री संकेतन_: [`3°111094′214″16797‴`](https://ordinals.com/" +"sat/3%C2%B0111094%E2%80%B2214%E2%80%B316797%E2%80%B4). हम शीघ्र उसे हासिल कर लेंगे। " + +#: src/overview.md:35 +msgid "" +"_Percentile notation_: [`99.99971949060254%`](https://ordinals.com/" +"sat/99.99971949060254%25) . The satoshi's position in Bitcoin's supply, " +"expressed as a percentage." +msgstr "" +"_प्रतिशत अंकन_: [`99.99971949060254%`](https://ordinals.com/" +"sat/99.99971949060254%25) . बिटकॉइन की आपूर्ति में सातोशी की स्थिति " +"को प्रतिशत के रूप में व्यक्त किया गया है।" + +#: src/overview.md:39 +msgid "" +"_Name_: [`satoshi`](https://ordinals.com/sat/satoshi). An encoding of the " +"ordinal number using the characters `a` through `z`." +msgstr "" +"_नाम_: [`satoshi`](https://ordinals.com/sat/satoshi). सातोशी आर्डिनल (क्रमसूचक) संख्याओं " +"को A से Z तक वर्णों का उपयोग करके एन्कोड किया जाता है।" + +#: src/overview.md:42 +msgid "" +"Arbitrary assets, such as NFTs, security tokens, accounts, or stablecoins " +"can be attached to satoshis using ordinal numbers as stable identifiers." +msgstr "" +"एनएफटी, सुरक्षा टोकन, खाते या स्‍टेबल कॉइन जैसी स्‍वेच्छित संपत्ति को स्थिर आइडेंटिफॉयर " +"(अभिज्ञापक अथवा सूचकाक्षर/आइडी) के रूप में आर्डिनल (क्रमसूचक) संख्याओं का उपयोग करके " +"सातोशी के साथ जोड़ा जा सकता है।" + +#: src/overview.md:45 +msgid "" +"Ordinals is an open-source project, developed [on GitHub](https://github.com/" +"ordinals/ord). The project consists of a BIP describing the ordinal scheme, " +"an index that communicates with a Bitcoin Core node to track the location of " +"all satoshis, a wallet that allows making ordinal-aware transactions, a " +"block explorer for interactive exploration of the blockchain, functionality " +"for inscribing satoshis with digital artifacts, and this manual." +msgstr "" +"ऑर्डिनल्स गिटहब पर विकसित किया गया एक ओपन-सोर्स प्रोजेक्ट है [on GitHub](https://github.com/" +"ordinals/ord)। प्रोजेक्ट में आर्डिनल (क्रमसूचक) योजना का उल्‍लेख कर बीआईपी, " +"सूचकांक जिसे सभी सातोशी की स्थिति ट्रैक करने के लिए बिटकॉइन कोर नोड के साथ संचार किया जाता है, " +"जो आर्डिनल-जागरूक लेनदेन करने में सक्षम करने वाला एक वॉलेट है, " +"ब्लॉकचेन की संवादात्‍मक जांच-पड़ताल के लिए एक ब्लॉक एक्सप्लोरर, " +"डिजिटल कलाकृतियों के साथ सतोषी की कार्यात्‍मकता, और यह मैनुअल सम्मिलित हैं।" + +#: src/overview.md:52 +msgid "Rarity" +msgstr "दुर्लभता" + +#: src/overview.md:55 +msgid "" +"Humans are collectors, and since satoshis can now be tracked and " +"transferred, people will naturally want to collect them. Ordinal theorists " +"can decide for themselves which sats are rare and desirable, but there are " +"some hints…" +msgstr "" +"मनुष्य की प्रकृति संग्रह करने की होती है, और चूँकि सातोशी को वर्तमान में ट्रैक और " +"स्थानांतरित किया जा सकता है, लोग स्वाभाविक रूप से उन्हें एकत्र करना चाहते हैं। आर्डिनल्‍स थ्‍यौरिस्‍ट " +"(क्रमसूचक सिद्धांतकार) स्वयं निर्णय ले सकते हैं कि कौन से सैट्स दुर्लभ और वांछि‍त हैं, लेकिन इसके लिए नीचे " +"कुछ अप्रत्‍यक्ष रूप से संकेत दिए गये हैं…" + +#: src/overview.md:59 +msgid "" +"Bitcoin has periodic events, some frequent, some more uncommon, and these " +"naturally lend themselves to a system of rarity. These periodic events are:" +msgstr "" +"बिटकॉइन में समय-समय पर घटनाएं घटित होती रहती हैं, उनमें से कुछ गैर-मामूली हैं, " +"जो उन्‍हें स्वाभाविक रूप से दुर्लभ बनाती हैं। इन आवधिक घटनाओं का उल्‍लेख नीचे किया गया हैं:" + +#: src/overview.md:62 +msgid "" +"_Blocks_: A new block is mined approximately every 10 minutes, from now " +"until the end of time." +msgstr "_ब्लॉक्‍स_: अब से लेकर एक निश्चित समय के अंत तक, तकरीबन हर 10 मिनट " +"में एक नये ब्लॉक का खनन किया जाता है।" + +#: src/overview.md:65 +msgid "" +"_Difficulty adjustments_: Every 2016 blocks, or approximately every two " +"weeks, the Bitcoin network responds to changes in hashrate by adjusting the " +"difficulty target which blocks must meet in order to be accepted." +msgstr "" +"_समायोजन करने में कठिनाई_: प्रत्येक 2016 ब्लॉक्‍स, या लगभग हर दो सप्ताह में, " +"बिटकॉइन नेटवर्क कठिन लक्ष्य को समायोजित करके हैश रेट में बदलाव करने का " +"प्रतिक्रिया देता है जिसे स्वीकार करने पर ब्लॉक को पूरा करना होगा।" + +#: src/overview.md:69 +msgid "" +"_Halvings_: Every 210,000 blocks, or roughly every four years, the amount of " +"new sats created in every block is cut in half." +msgstr "" +"_हाल्विंग (अर्धन)_: प्रत्येक 210,000 ब्लॉक, या लगभग हर चार साल में, प्रत्येक ब्लॉक में बनाए गए " +"नए सैट्स की मात्रा आधी कर दी जाती है।" + +#: src/overview.md:72 +msgid "" +"_Cycles_: Every six halvings, something magical happens: the halving and the " +"difficulty adjustment coincide. This is called a conjunction, and the time " +"period between conjunctions a cycle. A conjunction occurs roughly every 24 " +"years. The first conjunction should happen sometime in 2032." +msgstr "" +"_चक्र_: प्रत्‍येक छह अर्धन में, कुछ करिशमा होता है: अर्धन और समायोजन करने में " +"कठिनाई एक साथ घटित होते हैं। इसे संयोजन कहा जाता है और संयोजनों के बीच के समय " +"को चक्र कहते हैं। संयोजन लगभग हर 24 वर्ष में घटित होता है। " +"पहला संयोजन 2032 में किसी समय पर घटित होना चाहिए।" + +#: src/overview.md:77 +msgid "This gives us the following rarity levels:" +msgstr "इससे हमें दुर्लभता के निम्नलिखित स्तर प्राप्‍त होते हैं:" + +#: src/overview.md:79 +msgid "`common`: Any sat that is not the first sat of its block" +msgstr "`कॉमन (सामान्‍य)`: कोई भी ऐसा सैट जो अपने ब्लॉक का पहला सैट नहीं है" + +#: src/overview.md:80 +msgid "`uncommon`: The first sat of each block" +msgstr "`अनकॉमन (असामान्‍य)`: प्रत्येक ब्लॉक का पहला सैट" + +#: src/overview.md:81 +msgid "`rare`: The first sat of each difficulty adjustment period" +msgstr "`रेअर (दुर्लभ)`: प्रत्येक कठिन समायोजन अवधि का पहला सैट" + +#: src/overview.md:82 +msgid "`epic`: The first sat of each halving epoch" +msgstr "`एपिक (भव्‍य)`: प्रत्येक अर्धन युग का पहला सैट" + +#: src/overview.md:83 +msgid "`legendary`: The first sat of each cycle" +msgstr "`लेजन्‍डरी (प्रसिद्ध)`: प्रत्येक चक्र का पहला सैट" + +#: src/overview.md:84 +msgid "`mythic`: The first sat of the genesis block" +msgstr "`मिथिक (काल्‍पनिक)`: उत्पत्ति ब्‍लॉक का पहला सैट" + +#: src/overview.md:86 +msgid "" +"Which brings us to degree notation, which unambiguously represents an " +"ordinal number in a way that makes the rarity of a satoshi easy to see at a " +"glance:" +msgstr "" +"जो हमें डिग्री संकेतन के निकट लाता है, स्पष्ट रूप से एक " +"क्रमसूचक संख्या का प्रतिनिधित्व करता है जिससे सातोशी की दुर्लभता को एक नज़र में देखना बेहद आसान " +"हो जाता है:" + +#: src/overview.md:89 +msgid "" +"```\n" +"A°B′C″D‴\n" +"│ │ │ ╰─ Index of sat in the block\n" +"│ │ ╰─── Index of block in difficulty adjustment period\n" +"│ ╰───── Index of block in halving epoch\n" +"╰─────── Cycle, numbered starting from 0\n" +"```" +msgstr "" +"```\n" +"A°B′C″D‴\n" +"│ │ │ ╰─ ब्लॉक में सैट का सूचकांक\n" +"│ │ ╰─── कठिन समायोजन अवधि में ब्लॉक का सूचकांक\n" +"│ ╰───── अर्धन युग में ब्लॉक का सूचकांक\n" +"╰─────── चक्र, 0 से शुरू होने वाला अनुक्रमांक\n" +"```" + +#: src/overview.md:97 +msgid "" +"Ordinal theorists often use the terms \"hour\", \"minute\", \"second\", and " +"\"third\" for _A_, _B_, _C_, and _D_, respectively." +msgstr "" +"आर्डिनल थ्‍यौरिस्‍ट (क्रमसूचक सिद्धांतकार) अक्सर _A_, _B_, _C_ और _D_ के लिए क्रमशः \"घंटा\", \"मिनट\", " +"\"सेकंड\", और \"तीसरा\" शब्दों का उपयोग करते हैं। " + +#: src/overview.md:100 +msgid "Now for some examples. This satoshi is common:" +msgstr "अब कुछ उदाहरणों के लिए। यह सातोशी सामान्‍य है:" + +#: src/overview.md:102 +msgid "" +"```\n" +"1°1′1″1‴\n" +"│ │ │ ╰─ Not first sat in block\n" +"│ │ ╰─── Not first block in difficulty adjustment period\n" +"│ ╰───── Not first block in halving epoch\n" +"╰─────── Second cycle\n" +"```" +msgstr "" +"```\n" +"1°1′1″1‴\n" +"│ │ │ ╰─ ब्लॉक में पहला सैट नहीं है\n" +"│ │ ╰─── कठिन समायोजन अवधि में पहला ब्लॉक नहीं है\n" +"│ ╰───── अर्धन युग में पहला ब्लॉक नहीं है\n" +"╰─────── दूसरा चक्र\n" +"```" + +#: src/overview.md:111 +msgid "This satoshi is uncommon:" +msgstr "यह सातोशी असामान्‍य है:" + +#: src/overview.md:113 +msgid "" +"```\n" +"1°1′1″0‴\n" +"│ │ │ ╰─ First sat in block\n" +"│ │ ╰─── Not first block in difficulty adjustment period\n" +"│ ╰───── Not first block in halving epoch\n" +"╰─────── Second cycle\n" +"```" +msgstr "" +"```\n" +"1°1′1″0‴\n" +"│ │ │ ╰─ ब्लॉक में पहला सैट है\n" +"│ │ ╰─── कठिन समायोजन अवधि में पहला ब्लॉक नहीं है\n" +"│ ╰───── अर्धन युग में पहला ब्लॉक नहीं है\n" +"╰─────── दूसरा चक्र\n" +"```" + +#: src/overview.md:121 +msgid "This satoshi is rare:" +msgstr "यह सातोशी दुर्लभ है:" + +#: src/overview.md:123 +msgid "" +"```\n" +"1°1′0″0‴\n" +"│ │ │ ╰─ First sat in block\n" +"│ │ ╰─── First block in difficulty adjustment period\n" +"│ ╰───── Not the first block in halving epoch\n" +"╰─────── Second cycle\n" +"```" +msgstr "" +"```\n" +"1°1′0″0‴\n" +"│ │ │ ╰─ ब्लॉक में पहला सैट है\n" +"│ │ ╰─── कठिन समायोजन अवधि में पहला ब्लॉक है\n" +"│ ╰───── अर्धन युग में पहला ब्लॉक नहीं है\n" +"╰─────── दूसरा चक्र\n" +"```" + +#: src/overview.md:131 +msgid "This satoshi is epic:" +msgstr "यह सातोशी भव्‍य है:" + +#: src/overview.md:133 +msgid "" +"```\n" +"1°0′1″0‴\n" +"│ │ │ ╰─ First sat in block\n" +"│ │ ╰─── Not first block in difficulty adjustment period\n" +"│ ╰───── First block in halving epoch\n" +"╰─────── Second cycle\n" +"```" +msgstr "" +"```\n" +"1°0′1″0‴\n" +"│ │ │ ╰─ ब्लॉक में पहला सैट है\n" +"│ │ ╰─── कठिन समायोजन अवधि में पहला ब्लॉक नहीं है\n" +"│ ╰───── अर्धन युग में पहला ब्लॉक है\n" +"╰─────── दूसरा चक्र\n" +"```" + +#: src/overview.md:141 +msgid "This satoshi is legendary:" +msgstr "यह सातोशी प्रसिद्ध है:" + +#: src/overview.md:143 +msgid "" +"```\n" +"1°0′0″0‴\n" +"│ │ │ ╰─ First sat in block\n" +"│ │ ╰─── First block in difficulty adjustment period\n" +"│ ╰───── First block in halving epoch\n" +"╰─────── Second cycle\n" +"```" +msgstr "" +"```\n" +"1°0′0″0‴\n" +"│ │ │ ╰─ ब्लॉक में पहला सैट है\n" +"│ │ ╰─── कठिन समायोजन अवधि में पहला ब्लॉक है\n" +"│ ╰───── अर्धन युग में पहला ब्लॉक है\n" +"╰─────── दूसरा चक्र\n" +"```" + +#: src/overview.md:151 +msgid "And this satoshi is mythic:" +msgstr "और यह सातोशी काल्‍पनिक है:" + +#: src/overview.md:153 +msgid "" +"```\n" +"0°0′0″0‴\n" +"│ │ │ ╰─ First sat in block\n" +"│ │ ╰─── First block in difficulty adjustment period\n" +"│ ╰───── First block in halving epoch\n" +"╰─────── First cycle\n" +"```" +msgstr "" +"```\n" +"0°0′0″0‴\n" +"│ │ │ ╰─ ब्लॉक में पहला सैट है\n" +"│ │ ╰─── कठिन समायोजन अवधि में पहला ब्लॉक है\n" +"│ ╰───── अर्धन युग में पहला ब्लॉक है\n" +"╰─────── दूसरा चक्र\n" +"```" + +#: src/overview.md:161 +msgid "" +"If the block offset is zero, it may be omitted. This is the uncommon satoshi " +"from above:" +msgstr "" +"यदि ब्लॉक ऑफसेट शून्य है, तो इसे छोड़ा जा सकता है। यह उपरोक्‍त से गैर-मामूली " +"सातोशी है:" + +#: src/overview.md:164 +msgid "" +"```\n" +"1°1′1″\n" +"│ │ ╰─ Not first block in difficulty adjustment period\n" +"│ ╰─── Not first block in halving epoch\n" +"╰───── Second cycle\n" +"```" +msgstr "" +"```\n" +"1°1′1″\n" +"│ │ ╰─── कठिन समायोजन अवधि में पहला ब्लॉक नहीं है\n" +"│ ╰───── अर्धन युग में पहला ब्लॉक नहीं है\n" +"╰─────── दूसरा चक्र\n" +"```" + +#: src/overview.md:171 +msgid "Rare Satoshi Supply" +msgstr "दुर्लभ सातोशी आपूर्ति" + +#: src/overview.md:174 +msgid "Total Supply" +msgstr "कुल आपूर्ति" + +#: src/overview.md:176 +msgid "`common`: 2.1 quadrillion" +msgstr "`सामान्य`: 2.1 क्वाड्रिलियन (पद्म)" + +#: src/overview.md:177 +msgid "`uncommon`: 6,929,999" +msgstr "`असामान्य`: 6,929,999" + +#: src/overview.md:178 +msgid "`rare`: 3437" +msgstr "`दुर्लभ`: 3437" + +#: src/overview.md:179 +msgid "`epic`: 32" +msgstr "`भव्‍य`: 32" + +#: src/overview.md:180 +msgid "`legendary`: 5" +msgstr "`प्रसिद्ध`: 5" + +#: src/overview.md:181 src/overview.md:190 +msgid "`mythic`: 1" +msgstr "`काल्‍पनिक`: 1" + +#: src/overview.md:183 +msgid "Current Supply" +msgstr "वर्तमान आपूर्ति" + +#: src/overview.md:185 +msgid "`common`: 1.9 quadrillion" +msgstr "`सामान्य`: 1.9 क्वाड्रिलियन (पद्म)" + +#: src/overview.md:186 +msgid "`uncommon`: 745,855" +msgstr "`असामान्य`: 745,855" + +#: src/overview.md:187 +msgid "`rare`: 369" +msgstr "`दुर्लभ`: 369" + +#: src/overview.md:188 +msgid "`epic`: 3" +msgstr "`भव्‍य`: 3" + +#: src/overview.md:189 +msgid "`legendary`: 0" +msgstr "`प्रसिद्ध`: 0" + +#: src/overview.md:192 +msgid "" +"At the moment, even uncommon satoshis are quite rare. As of this writing, " +"745,855 uncommon satoshis have been mined - one per 25.6 bitcoin in " +"circulation." +msgstr "" +"फिलहाल, यहां तक कि गैर-मामूली सातोशी भी काफी दुर्लभ हैं। इस लेख के समय, " +"745,855 गैर-मामूली सातोशी का खनन किया जा चुका है - प्रचलन में प्रति 25.6 बिटकॉइन " +"में एक।" + +#: src/overview.md:196 +msgid "Names" +msgstr "नाम" + +#: src/overview.md:199 +msgid "" +"Each satoshi has a name, consisting of the letters _A_ through _Z_, that get " +"shorter the further into the future the satoshi was mined. They could start " +"short and get longer, but then all the good, short names would be trapped in " +"the unspendable genesis block." +msgstr "" +"प्रत्येक सातोशी का एक नाम दिया जाता है, जिसमें _A_ से _Z_ अक्षर शामिल होते हैं, जो " +"सातोशी के खनन के साथ भविष्य में छोटे होते जाते हैं। वे छोटे से शुरुआत " +"करते हुए लंबे समय तक बढ़ सकते हैं, लेकिन फिर सभी अच्छे, " +"छोटे नाम अप्राप्य उत्पत्ति ब्लॉक में फंस जाएंगे।" + +#: src/overview.md:204 +msgid "" +"As an example, 1905530482684727°'s name is \"iaiufjszmoba\". The name of the " +"last satoshi to be mined is \"a\". Every combination of 10 characters or " +"less is out there, or will be out there, someday." +msgstr "" +"उदाहरण के तौर पर、1905530482684727° का नाम \"iaiufjszmoba\" है। खनन कि‍ए जाने वाले अंतिम " +"सातोशी का नाम \"a\" है। हर 10 या उससे कम अक्षरों का प्रत्येक संयोजन उपलब्ध है, " +"या किसी दिन वहां पर उपलब्ध होगा।" + +#: src/overview.md:208 +msgid "Exotics" +msgstr "एग्‍जोटिक (असाधारण)" + +#: src/overview.md:211 +msgid "" +"Satoshis may be prized for reasons other than their name or rarity. This " +"might be due to a quality of the number itself, like having an integer " +"square or cube root. Or it might be due to a connection to a historical " +"event, such as satoshis from block 477,120, the block in which SegWit " +"activated, or 2099999997689999°, the last satoshi that will ever be mined." +msgstr "" +"सातोशी को उसके नाम या दुर्लभता छोड़कर अन्य कारणों से भी बहुमूल्य माना जा सकता है। ऐसा संख्या की " +"गुणवत्ता जैसे पूर्णांक वर्ग या घनमूल के कारण हो सकता है। या किसी ऐतिहासिक घटना से जुड़ने के कारण हो " +"सकता है, जैसे सातोशी के 477,120 ब्लॉक से, उस ब्लॉक से जिसमें सेगविट सक्रिय हुआ है, या " +"2099999997689999°, अंतिम सातोशी जि‍सका कभी खनन किया गया है।" + +#: src/overview.md:217 +msgid "" +"Such satoshis are termed \"exotic\". Which satoshis are exotic and what " +"makes them so is subjective. Ordinal theorists are encouraged to seek out " +"exotics based on criteria of their own devising." +msgstr "" +"ऐसे सातोशी को \"एग्‍जोटिक\" कहा जाता है। कौन सा सातोशी एग्‍जोटिक है और क्या " +"उन्हें व्यक्तिपरक बनाता है। आर्डिनल थ्‍यौरिस्‍ट (क्रमसूचक सिद्धांतकारों) को अपने स्वयं के आविष्कार के " +"मानदंडों के आधार पर एग्‍जोटिक वस्तुओं की तलाश करने के लिए प्रोत्साहित किया जाता है।" + +#: src/overview.md:224 +msgid "" +"Satoshis can be inscribed with arbitrary content, creating Bitcoin-native " +"digital artifacts. Inscribing is done by sending the satoshi to be inscribed " +"in a transaction that reveals the inscription content on-chain. This content " +"is then inextricably linked to that satoshi, turning it into an immutable " +"digital artifact that can be tracked, transferred, hoarded, bought, sold, " +"lost, and rediscovered." +msgstr "" +"सातोशी स्‍वेच्छित विषय-वस्‍तु के साथ उत्‍कीर्ण किये जा सकते हैं, जो बिटकॉइन-मूल " +"डिजिटल अभिलेख सृजन कर सकते हैं। लेन-देन में उत्‍कीर्ण किए जाने वाले सातोशी प्रेषित कर " +"अंकित किये जाते हैं, जो ऑन-चेन विषय-वस्‍तु प्रकट करते हैं। यह विषय-वस्‍तु तब उस सातोशी " +"से अविभाज्‍य रूप से जुड़े हुए हैं, जो इसे एक अपरिवर्तनीय डिजिटल अभिलेख में परिवर्तित कर " +"देते हैं जिसे ट्रैक, स्थानांतरित, संचित, खरीदा, बेचा, खोया जा सकता है " +"और फिर से दुबारा खोजा जा सकता है।" + +#: src/overview.md:231 +msgid "Archaeology" +msgstr "पुरातत्त्व अभिलेख" + +#: src/overview.md:234 +msgid "" +"A lively community of archaeologists devoted to cataloging and collecting " +"early NFTs has sprung up. [Here's a great summary of historical NFTs by " +"Chainleft.](https://mirror.xyz/chainleft.eth/MzPWRsesC9mQflxlLo-" +"N29oF4iwCgX3lacrvaG9Kjko)" +msgstr "" +"प्रारंभिक एनएफटी को सूचीबद्ध करने और संग्रह करने के लिए समर्पित पुरातत्वविदों का एक जीवंत " +"समुदाय रातों रात तेजी से उभर रहा है। [यहां चेनलेफ्ट द्वारा ऐतिहासिक एनएफटी के भव्‍य सारांश " +"दिये गये हैं।] (https://mirror.xyz/chainleft.eth/MzPWRsesC9mQflxlLo-" +"N29oF4iwCgX3lacrvaG9Kjko)" + +#: src/overview.md:238 +msgid "" +"A commonly accepted cut-off for early NFTs is March 19th, 2018, the date the " +"first ERC-721 contract, [SU SQUARES](https://tenthousandsu.com/), was " +"deployed on Ethereum." +msgstr "" +"प्रारंभिक एनएफटी के लिए आम तौर पर स्वीकृत अंतिम तिथि 19 मार्च, 2018 है, जिस दिन " +"पहला ईआरसी-721 अनुबंध, [SU SQUARES](https://tenthousandsu.com/), " +"एथेरियम पर तैनात किया गया था।" + +#: src/overview.md:242 +msgid "" +"Whether or not ordinals are of interest to NFT archaeologists is an open " +"question! In one sense, ordinals were created in early 2022, when the " +"Ordinals specification was finalized. In this sense, they are not of " +"historical interest." +msgstr "" +"एनएफटी पुरातत्वविदों के लिए ऑर्डिनल्स का महत्‍व हैं या नहीं, यह एक अनसुलझा मामला है! एक मायने में, " +"ऑर्डिनल्स का सृजन 2022 में हुआ था, जब ऑर्डिनल्स विनिर्देशों को अंतिम रूप दिया गया था। इस प्रकार, " +"उनकी ऐतिहासिक पृष्‍ठभूमि नहीं है।" + +#: src/overview.md:247 +msgid "" +"In another sense though, ordinals were in fact created by Satoshi Nakamoto " +"in 2009 when he mined the Bitcoin genesis block. In this sense, ordinals, " +"and especially early ordinals, are certainly of historical interest." +msgstr "" +"हालाँकि, दूसरे अर्थ में, ऑर्डिनल्स का सृजन वास्तव में सातोशी नाकामोटो द्वारा " +"2009 में किया गया था जब उन्होंने बिटकॉइन जेनेसिस ब्लॉक का खनन किया था। इस सीधा मतलब यह है " +"कि ऑर्डिनल्स, विशेष रूप से प्रारंभिक ऑर्डिनल्स का निश्चित रूप से ऐतिहासिक महत्‍व है।" + +#: src/overview.md:251 +msgid "" +"Many ordinal theorists favor the latter view. This is not least because the " +"ordinals were independently discovered on at least two separate occasions, " +"long before the era of modern NFTs began." +msgstr "" +"बहुत सारे सिद्धांतकार बाद वाले दृष्टिकोण का समर्थन करते हैं। इसे कम कर नहीं आंकना चाहिए क्योंकि " +"आधुनिक एनएफटी का युग शुरू होने से बहुत पहले, कम से कम दो अलग-अलग समयावधि पर ऑर्डिनल्स " +"स्वतंत्र रूप से खोजे गए थे।" + +#: src/overview.md:255 +msgid "" +"On August 21st, 2012, Charlie Lee [posted a proposal to add proof-of-stake " +"to Bitcoin to the Bitcoin Talk forum](https://bitcointalk.org/index.php?" +"topic=102355.0). This wasn't an asset scheme, but did use the ordinal " +"algorithm, and was implemented but never deployed." +msgstr "" +"21 अगस्त 2012 को, चार्ली ली ने [बिटकॉइन टॉक फोरम में बिटकॉइन में हिस्सेदारी की आम सहमति प्रोटोकॉल " +"का प्रमाण जोड़ने का प्रस्ताव पोस्ट किया था।](https://bitcointalk.org/index.php?" +"topic=102355.0) यह कोई परिसंपत्ति योजना नहीं थी, लेकिन इसमें आर्डिनल एल्गोरिदम का उपयोग किया गया था, " +"और इसे कार्यान्वित तो किया गया था लेकिन कभी भी असरदार तरीके के साथ इस्‍तेमाल नहीं किया गया था।" + + +#: src/overview.md:261 +msgid "" +"On October 8th, 2012, jl2012 [posted a scheme to the same forum](https://" +"bitcointalk.org/index.php?topic=117224.0) which uses decimal notation and " +"has all the important properties of ordinals. The scheme was discussed but " +"never implemented." +msgstr "" +"8 अक्टूबर 2012 को, jl2012 ने [उसी मंच पर एक योजना पोस्ट की थी](https://" +"bitcointalk.org/index.php?topic=117224.0) जि‍समें दशमलव नोटेशन अर्थात " +"संकेतन का उपयोग किया गया था और इसमें ऑर्डिनल्स के सभी महत्वपूर्ण गुण शामिल हैं। इस योजना " +"पर गहन चर्चा तो हुई लेकिन इसे कभी लागू नहीं किया जा सका।" + +#: src/overview.md:266 +msgid "" +"These independent inventions of ordinals indicate in some way that ordinals " +"were discovered, or rediscovered, and not invented. The ordinals are an " +"inevitability of the mathematics of Bitcoin, stemming not from their modern " +"documentation, but from their ancient genesis. They are the culmination of a " +"sequence of events set in motion with the mining of the first block, so many " +"years ago." +msgstr "" +"ऑर्डिनल्स के ये स्वतंत्र आविष्कार किसी न किसी तरह से संकेत देते हैं कि ऑर्डिनल्स की खोज की गई थी, या " +"उन्‍हें दुबारा खोजा गया था, लेकिन उनका आविष्कार नहीं किया गया था। आर्डिनल्‍स अनिवार्य रूप से बिटकॉइन " +"का गणित हैं, जो उनके आधुनिक दस्तावेज़ीकरण से नहीं, बल्कि उनकी प्राचीन उत्पत्ति से उत्पन्न हुए हैं। कई " +"साल पहले, वे पहले ब्लॉक के खनन के साथ शुरू हुई घटनाओं के अनुक्रम के परिणाम हैं।" + +#: src/digital-artifacts.md:4 +msgid "" +"Imagine a physical artifact. A rare coin, say, held safe for untold years in " +"the dark, secret clutch of a Viking hoard, now dug from the earth by your " +"grasping hands. It…" +msgstr "" +"एक भौतिक अभिलेख की कल्पना करें। एक दुर्लभ सिक्का, मान लीजिए, जलदस्‍युओं के गिरोह के स्‍याह, गुप्त " +"चंगुल में अनंत काल तक सुरक्षित रखा गया था, जिसे अब आपके लालची हाथों ने जमीन से खोद " +"निकाला है। इसका…" + +#: src/digital-artifacts.md:8 +msgid "" +"…has an owner. You. As long as you keep it safe, nobody can take it from you." +msgstr "" +"…एक मालिक है। वे आप स्‍वयं हैं। जब तक आप इसे सुरक्षित रखेंगे, कोई भी इसे आपसे छीन नहीं सकता।" + +#: src/digital-artifacts.md:10 +msgid "…is complete. It has no missing parts." +msgstr "…संपूर्ण है। इसका कोई भी भाग गायब नहीं है।" + +#: src/digital-artifacts.md:12 +msgid "" +"…can only be changed by you. If you were a trader, and you made your way to " +"18th century China, none but you could stamp it with your chop-mark." +msgstr "" +"…केवल आप ही उसे बदल सकते हैं। यदि आप एक व्यापारी थे, और आपने 18वीं सदी के चीन की ओर रुख " +"किया था, तब आपके अलावा कोई भी उस पर अपनी चिन्‍ह का गढ़कर मुहर नहीं लगा सकता था।" + +#: src/digital-artifacts.md:15 +msgid "" +"…can only be disposed of by you. The sale, trade, or gift is yours to make, " +"to whomever you wish." +msgstr "" +"…केवल आपके द्वारा ही इसे निपटाया जा सकता है। आप ही इसकी बिक्री, व्यवसाय या उपहार दे सकते हैं, " +"आप जैसा भी चाहते हैं।" + +#: src/digital-artifacts.md:18 +msgid "" +"What are digital artifacts? Simply put, they are the digital equivalent of " +"physical artifacts." +msgstr "" +"डिजिटल अभिलेख क्या हैं? साधारण शब्दों में अगर कहें तो, वे भौतिक कलाकृतियों के डिजिटल अभिलेख " +"अर्थात प्रतिरूप हैं।" + +#: src/digital-artifacts.md:21 +msgid "" +"For a digital thing to be a digital artifact, it must be like that coin of " +"yours:" +msgstr "" +"किसी डिजिटल वस्‍तु को डिजिटल अभिलेख बनाने के लिए, यह आपके उस सिक्के की तरह होना " +"चाहिए:" + +#: src/digital-artifacts.md:24 +msgid "" +"Digital artifacts can have owners. A number is not a digital artifact, " +"because nobody can own it." +msgstr "" +"डिजिटल अभिलेखों के मालिक हो सकते हैं। कोई संख्या डिजिटल अभिलेख नहीं हो सकती, " +क्योंकि इसका स्वामी कोई नहीं हो सकता।" + +#: src/digital-artifacts.md:27 +msgid "" +"Digital artifacts are complete. An NFT that points to off-chain content on " +"IPFS or Arweave is incomplete, and thus not a digital artifact." +msgstr "" +"डिजिटल अभिलेख परिपूर्ण हैं। एक एनएफटी जो IPFS या Arweave पर ऑफ-चेन सामग्री को इंगित " +"करता है वह अधूरा है, और इसलिए वह डिजिटल अभिलेख नहीं है।" + +#: src/digital-artifacts.md:30 +msgid "" +"Digital artifacts are permissionless. An NFT which cannot be sold without " +"paying a royalty is not permissionless, and thus not a digital artifact." +msgstr "" +"डिजिटल अभिलेख के लिए अनुमति नहीं चाहिए होती। एक एनएफटी जिसे रॉयल्टी का भुगतान किए बिना बेचा " +"नहीं जा सकता, उसका लेनदेन बिना अनुमति नहीं किया जा सकता, और इस प्रकार वह एक डिजिटल " +"अभिलेख नहीं है।" + +#: src/digital-artifacts.md:33 +msgid "" +"Digital artifacts are uncensorable. Perhaps you can change a database entry " +"on a centralized ledger today, but maybe not tomorrow, and thus one cannot " +"be a digital artifact." +msgstr "" +"डिजिटल अभिलेखों को सेंसर नहीं किया जा सकता। हो सकता है कि आप वर्तमान में एक केंद्रीकृत खाता " +"बही पर डेटाबेस की प्रविष्टि बदल सकते हैं, लेकिन शायद भविष्‍य में ऐसा नहीं कर सकते, और इस प्रकार " +"कोई डिजिटल अभिलेख नहीं हो सकता है।" + +#: src/digital-artifacts.md:37 +msgid "" +"Digital artifacts are immutable. An NFT with an upgrade key is not a digital " +"artifact." +msgstr "" +"डिजिटल अभिलेख अपरिवर्तनीय हैं। अपग्रेड कुंजी वाला एनएफटी एक डिजिटल अभिलेख नहीं है।" + +#: src/digital-artifacts.md:40 +msgid "" +"The definition of a digital artifact is intended to reflect what NFTs " +"_should_ be, sometimes are, and what inscriptions _always_ are, by their " +"very nature." +msgstr "" +"डिजिटल अभिलेख की परिभाषा का उद्देश्य यह प्रतिबिंबित करना है कि एनएफटी _कैसा होना चाहिए_, जो " +"कभी-कभार, और इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) _हमेशा_ अपनी प्रकृति के रहते हैं।" + +#: src/inscriptions.md:4 +msgid "" +"Inscriptions inscribe sats with arbitrary content, creating bitcoin-native " +"digital artifacts, more commonly known as NFTs. Inscriptions do not require " +"a sidechain or separate token." +msgstr "" +"इंस्‍क्रि‍प्‍शंस बिटकॉइन-मूल डिजिटल अभिलेखों को निर्मित करने के लिए सैट्स पर स्‍वेच्छित विषय-वस्‍तु अंकित " +"करते हैं, आमतौर पर यह एनएफटी के रूप में जाने जाते हैं। इंस्‍क्रि‍प्‍शंस के लिए साइडचेन या अलग टोकन की " +"आवश्यकता नहीं होती।" + +#: src/inscriptions.md:8 +msgid "" +"These inscribed sats can then be transferred using bitcoin transactions, " +"sent to bitcoin addresses, and held in bitcoin UTXOs. These transactions, " +"addresses, and UTXOs are normal bitcoin transactions, addresses, and UTXOS " +"in all respects, with the exception that in order to send individual sats, " +"transactions must control the order and value of inputs and outputs " +"according to ordinal theory." +msgstr "" +"इन अंकित सैट्स को बिटकॉइन लेनदेन का उपयोग करके हस्‍तांतरित किया जा सकता है, बिटकॉइन पतों पर " +"प्रेषित किया जा सकता है, और बिटकॉइन यूटीएक्सओ में सहेज कर रखा जा सकता है। ये लेनदेन, पते और " +"यूटीएक्सओ सर्वथा सभी मामलों में सामान्य बिटकॉइन लेनदेन, पते और यूटीएक्सओएस हैं, बशर्ते कि " +"व्यक्तिगत सैट्स प्रेषित करने के लिए, लेनदेन आर्डिनल थ्‍यौरी के अनुरूप इनपुट और आउटपुट के क्रम और " +"मूल्य को नियंत्रित करते हों।" + +#: src/inscriptions.md:15 +msgid "" +"The inscription content model is that of the web. An inscription consists of " +"a content type, also known as a MIME type, and the content itself, which is " +"a byte string. This allows inscription content to be returned from a web " +"server, and for creating HTML inscriptions that use and remix the content of " +"other inscriptions." +msgstr "" +"इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु का मॉडल वेब सदृश है। इंस्‍क्रि‍प्‍शंस में विषय-वस्‍तु के प्रकार सम्मिलित होते हैं, जिन्‍हें " +"माइम प्रकार के रूप में भी जाना जाता है, और विषय-वस्‍तु अपने आप में एक बाइट स्ट्रिंग होती है। यह " +"इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु को वेब सर्वर से वापस लौटने में सक्षम करते हैं, और HTML इंस्‍क्रि‍प्‍शंस स़ृजन करने में " +"सक्षम करती है जो अन्य इंस्‍क्रि‍प्‍शंस की विषय-वस्‍तु का उपयोग और रीमिक्स करती हैं।" + +#: src/inscriptions.md:21 +msgid "" +"Inscription content is entirely on-chain, stored in taproot script-path " +"spend scripts. Taproot scripts have very few restrictions on their content, " +"and additionally receive the witness discount, making inscription content " +"storage relatively economical." +msgstr "" +"इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु पूरी तरह ऑन-चेन (सभी के लिए दृश्‍यमान) होते हैं, जिन्‍हें टैपरूट स्क्रिप्ट-पथ खर्च " +"स्क्रिप्ट में संग्रहीत किया जाता है। टैपरूट स्क्रिप्ट के संदेशों पर बहुत कम प्रतिबंध लगाए जाते हैं, इसके " +"अतिरिक्त, साक्ष्‍य छूट (प्रोत्‍साहन छूट) भी प्राप्त होती है, जिससे इंस्‍क्रि‍प्‍शंस संदेशों का भंडारण अपेक्षाकृत " +"किफायती हो जाता है।" + +#: src/inscriptions.md:26 +msgid "" +"Since taproot script spends can only be made from existing taproot outputs, " +"inscriptions are made using a two-phase commit/reveal procedure. First, in " +"the commit transaction, a taproot output committing to a script containing " +"the inscription content is created. Second, in the reveal transaction, the " +"output created by the commit transaction is spent, revealing the inscription " +"content on-chain." +msgstr "" +"चूँकि टैपरूट स्क्रिप्ट खर्च केवल मौजूदा टैपरूट आउटपुट से ही किये जा सकते हैं, इसलिए इंस्‍क्रि‍प्‍शंस दो-चरण " +"की प्रतिबद्धता/प्रकटीकरण प्रक्रिया का उपयोग करके बनाए जाते हैं। सबसे पहले, प्रतिबद्ध लेनदेन में, " +"इंस्‍क्रि‍प्‍शंस संदेशों का सृजन किया जाता है, स्क्रिप्ट के लिए प्रतिबद्ध एक टैपरूट आउटपुट निर्मित किया जाता है। " +"दूसरा, प्रकट लेन-देन में, प्रतिबद्ध लेन-देन द्वारा निर्मित आउटपुट का खर्च कर दिया जाता है, जो ऑन-चेन पर " +"इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु को प्रकट करता है।" + +#: src/inscriptions.md:33 +msgid "" +"Inscription content is serialized using data pushes within unexecuted " +"conditionals, called \"envelopes\". Envelopes consist of an `OP_FALSE OP_IF " +"… OP_ENDIF` wrapping any number of data pushes. Because envelopes are " +"effectively no-ops, they do not change the semantics of the script in which " +"they are included, and can be combined with any other locking script." +msgstr "" +"\"लिफाफे\" से संबोधित, इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु को अनियोजित नियमबद्धताओं के भीतर आंकड़ों को प्रेरित " +"कर क्रमबद्ध किया जाता है। लिफ़ाफ़ों में OP_FALSE OP_IF … OP_ENDIF सम्मिलित होते हैं, जो किसी भी " +"संख्या में आंकड़ों को प्रेरित कर समेटता है। चूँकि लिफ़ाफ़े प्रभावी रूप से स्‍वचालित (नो-ऑप्‍स) होते हैं, वे उस " +"स्क्रिप्ट के शब्दार्थ को नहीं बदलते हैं जिसमें वे शामिल हैं, और उन्हें किसी अन्य लॉकिंग स्क्रिप्ट (आउटपुट में " +"स्‍थापित खर्च की शर्तें) के साथ जोड़ा जा सकता है।" + +#: src/inscriptions.md:39 +msgid "" +"A text inscription containing the string \"Hello, world!\" is serialized as " +"follows:" +msgstr "" +"एक टेक्‍स्‍ट (मूल शब्‍द) इंस्‍क्रि‍प्‍शंस जिसमें स्ट्रिंग \"हैलो, वर्ल्‍ड!\" सम्मिलित है, उसे निम्नानुसार क्रमबद्ध किया " +"जाता है:" + +#: src/inscriptions.md:42 +msgid "" +"```\n" +"OP_FALSE\n" +"OP_IF\n" +" OP_PUSH \"ord\"\n" +" OP_PUSH 1\n" +" OP_PUSH \"text/plain;charset=utf-8\"\n" +" OP_PUSH 0\n" +" OP_PUSH \"Hello, world!\"\n" +"OP_ENDIF\n" +"```" +msgstr "" + +#: src/inscriptions.md:53 +msgid "" +"First the string `ord` is pushed, to disambiguate inscriptions from other " +"uses of envelopes." +msgstr "" +"सबसे पहले स्ट्रिंग `ऑर्डर` को लिफाफों के अन्य उपयोगों से इंस्‍क्रि‍प्‍शंस को स्पष्ट करने के लिए प्रेरित " +"किया जाता है।" + +#: src/inscriptions.md:56 +msgid "" +"`OP_PUSH 1` indicates that the next push contains the content type, and " +"`OP_PUSH 0`indicates that subsequent data pushes contain the content itself. " +"Multiple data pushes must be used for large inscriptions, as one of " +"taproot's few restrictions is that individual data pushes may not be larger " +"than 520 bytes." +msgstr "" +"`OP_PUSH 1` इंगित करता है कि अगले पुश में विषय-वस्‍तु के प्रकार शामिल हैं, और " +"`OP_PUSH 0` इंगित करता है कि आगामी डेटा पुश में स्‍वयं विषय-वस्‍तु ही शामिल हैं। " +"बड़े इंस्‍क्रि‍प्‍शंस के लिए बहुल डेटा पुश का उपयोग किया जाना चाहिए, क्योंकि " +"टैपरूट के कुछ प्रतिबंधों में से एक यह है कि व्यक्तिगत डेटा " +"पुश 520 बाइट्स से बड़ा नहीं हो सकता है।" + +#: src/inscriptions.md:62 +msgid "" +"The inscription content is contained within the input of a reveal " +"transaction, and the inscription is made on the first sat of its input. This " +"sat can then be tracked using the familiar rules of ordinal theory, allowing " +"it to be transferred, bought, sold, lost to fees, and recovered." +msgstr "" +"इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु प्रकट लेन-देन के इनपुट में निहित होते हैं, और इंस्‍क्रि‍प्‍शंस इसके इनपुट के पहले सैट पर " +"निर्मित किये जाते हैं। इस सैट को क्रमिक सिद्धांत के परिचित नियमों का उपयोग करके ट्रैक किया जा सकता है, " +"जो इसे स्थानांतरित करने, खरीदने, बिक्री करने, फीस में हुई चूक और वसूली करने की अनुमति देता है।" + +#: src/inscriptions.md:67 +msgid "Content" +msgstr "विषय-वस्‍तु" + +#: src/inscriptions.md:70 +msgid "" +"The data model of inscriptions is that of a HTTP response, allowing " +"inscription content to be served by a web server and viewed in a web browser." +msgstr "" +"इंस्‍क्रि‍प्‍शंस का डेटा मॉडल एक HTTP प्रतिक्रिया है, जो इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु को वेब सर्वर द्वारा प्रस्तुत करने " +"और एक वेब ब्राउज़र में देखने की अनुमति देता है।" + +#: src/inscriptions.md:73 +msgid "Fields" +msgstr "फील्‍ड्स" + +#: src/inscriptions.md:76 +msgid "" +"Inscriptions may include fields before an optional body. Each field consists " +"of two data pushes, a tag and a value." +msgstr "" +"वैकल्पिक निकाय से पहले इंस्‍क्रि‍प्‍शंस में फ़ील्ड शामिल हो सकते हैं। प्रत्येक फ़ील्ड में दो डेटा पुश, एक टैग " +"और एक मूल्‍य सम्मिलित होता है।" + +#: src/inscriptions.md:79 +msgid "" +"Currently, the only defined field is `content-type`, with a tag of `1`, " +"whose value is the MIME type of the body." +msgstr "" +"वर्तमान में, `1` टैग के साथ एकमात्र परिभाषित फ़ील्ड `content-type` है, " +"जिसका मूल्‍य बॉडी का MIME प्रकार है।" + +#: src/inscriptions.md:82 +msgid "" +"The beginning of the body and end of fields is indicated with an empty data " +"push." +msgstr "" +"बॉडी का प्रारम्‍भ और फील्‍ड के अंत को रिक्‍त डेटा पुश के साथ दर्शाया गया है।" + +#: src/inscriptions.md:85 +msgid "" +"Unrecognized tags are interpreted differently depending on whether they are " +"even or odd, following the \"it's okay to be odd\" rule used by the " +"Lightning Network." +msgstr "" +"लाइटनिंग नेटवर्क द्वारा उपयोग किए जाने वाले \"विषम होना ठीक है\" नियम का अनुसरण करके सम और विषम " +"पर निर्भर करते हुए अज्ञात टैग्‍स की व्‍याख्‍या अलग-अलग प्रकार से की जा सकती है।" + +#: src/inscriptions.md:89 +msgid "" +"Even tags are used for fields which may affect creation, initial assignment, " +"or transfer of an inscription. Thus, inscriptions with unrecognized even " +"fields must be displayed as \"unbound\", that is, without a location." +msgstr "" +"यहां तक कि टैग का उपयोग उन फ़ील्ड के लिए भी किया जाता है जो किसी इंस्‍क्रि‍प्‍शंस के निर्माण, प्रारंभिक " +"नियत कार्य या स्थानांतरण को प्रभावित कर सकते हैं। इस प्रकार, अज्ञात सम फ़ील्ड वाले इंस्‍क्रि‍प्‍शंस को " +"\"अनबाउंड\" यानि‍ अबाध के रूप में प्रदर्शित किया जाना चाहिए, अर्थात, बिना किसी स्थान के।" + +#: src/inscriptions.md:93 +msgid "" +"Odd tags are used for fields which do not affect creation, initial " +"assignment, or transfer, such as additional metadata, and thus are safe to " +"ignore." +msgstr "" +"पुराने टैग का उपयोग उन फ़ील्ड के लिए किया जाता है जो निर्माण, प्रारंभिक नियत कार्य या स्थानांतरण को " +"प्रभावित नहीं करते हैं, जैसे अतिरिक्त मेटाडेटा, और इस प्रकार इन्‍हें अनदेखा करना सुरक्षित और श्रेयस्‍कर है।" + +#: src/inscriptions.md:96 +msgid "Inscription IDs" +msgstr "इंस्‍क्रि‍प्‍शंस आईडी" + +#: src/inscriptions.md:99 +msgid "" +"The inscriptions are contained within the inputs of a reveal transaction. In " +"order to uniquely identify them they are assigned an ID of the form:" +msgstr "" +"इंस्‍क्रि‍प्‍शंस प्रकट लेन-देन के इनपुट में समाहित होते हैं। विशिष्ट रूप से इनकी पहचानके लिए उन्हें फॉर्म की एक " +"आईडी दी गई है:" + +#: src/inscriptions.md:102 +msgid "`521f8eccffa4c41a3a7728dd012ea5a4a02feed81f41159231251ecf1e5c79dai0`" +msgstr "" + +#: src/inscriptions.md:104 +msgid "" +"The part in front of the `i` is the transaction ID (`txid`) of the reveal " +"transaction. The number after the `i` defines the index (starting at 0) of " +"new inscriptions being inscribed in the reveal transaction." +msgstr "" +"वर्ण `i` के सामने वाला भाग प्रकट लेन-देन की आईडी (txid) अर्थात पहचान है। " +"वर्ण `i` के बाद की संख्या प्रकट लेनदेन में अंकित किए जा रहे नई इंस्‍क्रि‍प्‍शंस के सूचकांक (0 से शुरू) " +"को परिभाषित करती है।" + +#: src/inscriptions.md:108 +msgid "" +"Inscriptions can either be located in different inputs, within the same " +"input or a combination of both. In any case the ordering is clear, since a " +"parser would go through the inputs consecutively and look for all " +"inscription `envelopes`." +msgstr "" +"इंस्‍क्रि‍प्‍शंस या तो अलग-अलग इनपुट में, या किसी एक इनपुट में या दोनों के संयोजन में स्थित हो सकती हैं। " +"किसी भी मामले में आर्डरिंग यानि क्रम स्‍थापन स्पष्ट होता है, क्योंकि पार्सर (कोड को कार्यात्मक घटकों में " +"विभाजित करने वाला कंप्यूटर प्रोग्राम) क्रमानुसार इनपुट के माध्यम से जांच-परख या प्रयोग और सभी " +"इंस्‍क्रि‍प्‍शंस `लिफाफों` की खोज करता है।" + +#: src/inscriptions.md:112 +msgid "Input" +msgstr "इनपुट" + +#: src/inscriptions.md:112 +msgid "Inscription Count" +msgstr "इंस्‍क्रि‍प्‍शंस गणना" + +#: src/inscriptions.md:112 +msgid "Indices" +msgstr "सूचियां" + +#: src/inscriptions.md:114 src/inscriptions.md:117 +msgid "0" +msgstr "" + +#: src/inscriptions.md:114 src/inscriptions.md:116 +msgid "2" +msgstr "" + +#: src/inscriptions.md:114 +msgid "i0, i1" +msgstr "" + +#: src/inscriptions.md:115 src/inscriptions.md:118 +msgid "1" +msgstr "" + +#: src/inscriptions.md:115 +msgid "i2" +msgstr "" + +#: src/inscriptions.md:116 src/inscriptions.md:117 +msgid "3" +msgstr "" + +#: src/inscriptions.md:116 +msgid "i3, i4, i5" +msgstr "" + +#: src/inscriptions.md:118 +msgid "4" +msgstr "" + +#: src/inscriptions.md:118 +msgid "i6" +msgstr "" + +#: src/inscriptions.md:120 +msgid "Sandboxing" +msgstr "सैंडबॉक्सिंग" + +#: src/inscriptions.md:123 +msgid "" +"HTML and SVG inscriptions are sandboxed in order to prevent references to " +"off-chain content, thus keeping inscriptions immutable and self-contained." +msgstr "" +"ऑफ-चेन संदेशों के संदर्भ निर्देशों को रोकने के लिए HTML और SVG इंस्‍क्रि‍प्‍शंस को " +"सैंडबॉक्स कर देता है, इस प्रकार इंस्‍क्रि‍प्‍शंस को स्थिर और पृथक रखा जाता है।" + +#: src/inscriptions.md:126 +msgid "" +"This is accomplished by loading HTML and SVG inscriptions inside `iframes` " +"with the `sandbox` attribute, as well as serving inscription content with " +"`Content-Security-Policy` headers." +msgstr "" +"इसे `सैंडबॉक्स` गुणों के साथ `आईफ्रेम` के भीतर HTML और SVG इंस्‍क्रि‍प्‍शंस लोड करने के साथ-साथ " +"इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु को `Content-Security-Policy` है की सेवा प्रदान करके पूरा किया जाता है।" + +#: src/inscriptions/provenance.md:4 +msgid "" +"The owner of an inscription can create child inscriptions, trustlessly " +"establishing the provenance of those children on-chain as having been " +"created by the owner of the parent inscription. This can be used for " +"collections, with the children of a parent inscription being members of the " +"same collection." +msgstr "" +"एक इंस्‍क्रि‍प्‍शंस का मालिक चाइल्‍ड इंस्‍क्रि‍प्‍शंस का सृजन कर सकता है, अविश्वसनीय रूप से, उन बच्चों की " +"ऑन-चेन उत्पत्ति को इस प्रकार से स्‍थापित किया जाएगा जिस प्रकार से उन्हें मूल इंस्‍क्रि‍प्‍शंस के मालिक द्वारा " +"निर्मित किया गया है। इसका उपयोग संग्रहों के लिए किया जा सकता है, जिसमें मूल इंस्‍क्रि‍प्‍शंस के बच्चे उसी " +"संग्रह के सदस्य होंगे।" + +#: src/inscriptions/provenance.md:9 +msgid "" +"Children can themselves have children, allowing for complex hierarchies. For " +"example, an artist might create an inscription representing themselves, with " +"sub inscriptions representing collections that they create, with the " +"children of those sub inscriptions being items in those collections." +msgstr "" +"बच्चे स्वयं बच्चों की उत्‍पति कर सकते हैं, जटिल पदानुक्रमों सक्षम करते हुए। उदाहरण के लिए, एक कलाकार " +"अपने स्‍वयं का प्रतिनिधित्व करने वाले इंस्‍क्रि‍प्‍शंस का सृजन कर सकता है, जिसमें वह उसके द्वारा सृजन किए " +"गये उप इंस्‍क्रि‍प्‍शंस संग्रहों का प्रतिनिधित्व करते हैं, जिसमें उन उप इंस्‍क्रि‍प्‍शंस के बच्चे उन संग्रहों के नाते उसकी " +"मदें होंगी।" + +#: src/inscriptions/provenance.md:14 +msgid "Specification" +msgstr "विनिर्देश" + +#: src/inscriptions/provenance.md:16 +msgid "To create a child inscription C with parent inscription P:" +msgstr "" +"मूल इंस्‍क्रि‍प्‍शंस P के साथ एक चाइल्ड इंस्‍क्रि‍प्‍शंस C का सृजन करने के लिए:" + +#: src/inscriptions/provenance.md:18 +msgid "Create an inscribe transaction T as usual for C." +msgstr "हमेशा की तरह C के लिए एक इंस्क्राइब लेनदेन T का सृजन करें।" + +#: src/inscriptions/provenance.md:19 +msgid "Spend the parent P in one of the inputs of T." +msgstr "T की किसी एक इनपुट में से मूल P खर्च करें।" + +#: src/inscriptions/provenance.md:20 +msgid "" +"Include tag `3`, i.e. `OP_PUSH 3`, in C, with the value of the serialized " +"binary inscription ID of P, serialized as the 32-byte `TXID`, followed by " +"the four-byte little-endian `INDEX`, with trailing zeroes omitted." +msgstr "" +"टैग `3` दर्ज करें, अर्थात C में, P के क्रमबद्ध बाइनरी इंस्‍क्रि‍प्‍शंस आईडी के मान के साथ `OP_PUSH 3` " +"दर्ज करें, जिसे 32-बाइट `TXID` के रूप में क्रमबद्ध किया गया है, इसके बाद चार-बाइट वाला " +"लिटल-एंडियन (छोटा अंतिय) `सूचकांक` आता है, जिसमें पीछे के शून्य मिटा दिए जाते हैं।" + +#: src/inscriptions/provenance.md:24 +msgid "" +"_NB_ The bytes of a bitcoin transaction ID are reversed in their text " +"representation, so the serialized transaction ID will be in the opposite " +"order." +msgstr "" +"चिन्हित बिटकॉइन लेनदेन आईडी के बाइट्स उनके विषय-वस्‍तु प्रतिनिधित्व में पलट दिए जाते हैं, इसलिए " +"क्रमबद्ध लेनदेन आईडी विपरीत क्रम में होंगे।" + +#: src/inscriptions/provenance.md:27 src/guides/testing.md:18 +#: src/guides/reindexing.md:15 +msgid "Example" +msgstr "उदाहरण" + +#: src/inscriptions/provenance.md:29 +msgid "" +"An example of a child inscription of " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi0`:" +msgstr "" +"चाइल्ड इंस्‍क्रि‍प्‍शंस का एक उदाहरण: " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi0`:" + +#: src/inscriptions/provenance.md:32 +msgid "" +"```\n" +"OP_FALSE\n" +"OP_IF\n" +" OP_PUSH \"ord\"\n" +" OP_PUSH 1\n" +" OP_PUSH \"text/plain;charset=utf-8\"\n" +" OP_PUSH 3\n" +" OP_PUSH " +"0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100\n" +" OP_PUSH 0\n" +" OP_PUSH \"Hello, world!\"\n" +"OP_ENDIF\n" +"```" +msgstr "" + +#: src/inscriptions/provenance.md:45 +msgid "" +"Note that the value of tag `3` is binary, not hex, and that for the child " +"inscription to be recognized as a child, " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi0` must be " +"spent as one of the inputs of the inscribe transaction." +msgstr "" +"ध्यान दें कि टैग `3` का मान बाइनरी है, हेक्स नहीं, और चाइल्ड इंस्क्रिप्शन को चाइल्ड के रूप में मान्यता दी " +"जाएगी, " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi0` को " +"इंस्क्राइब लेनदेन के इनपुट में से एक के रूप में खर्च किया जाना चाहिए।" + +#: src/inscriptions/provenance.md:50 +msgid "" +"Example encoding of inscription ID " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi255`:" +msgstr "" +"इंस्‍क्रि‍प्‍शंस आईडी एन्कोडिंग का उदाहरण: " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi255`:" + +#: src/inscriptions/provenance.md:53 +msgid "" +"```\n" +"OP_FALSE\n" +"OP_IF\n" +" …\n" +" OP_PUSH 3\n" +" OP_PUSH " +"0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100ff\n" +" …\n" +"OP_ENDIF\n" +"```" +msgstr "" + +#: src/inscriptions/provenance.md:63 +msgid "" +"And of inscription ID " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi256`:" +msgstr "" +"और इंस्‍क्रि‍प्‍शंस ID " +"`000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fi256`:" + +#: src/inscriptions/provenance.md:65 +msgid "" +"```\n" +"OP_FALSE\n" +"OP_IF\n" +" …\n" +" OP_PUSH 3\n" +" OP_PUSH " +"0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201000001\n" +" …\n" +"OP_ENDIF\n" +"```" +msgstr "" + +#: src/inscriptions/provenance.md:75 +msgid "Notes" +msgstr "टिप्पणियाँ" + +#: src/inscriptions/provenance.md:77 +msgid "" +"The tag `3` is used because it is the first available odd tag. Unrecognized " +"odd tags do not make an inscription unbound, so child inscriptions would be " +"recognized and tracked by old versions of `ord`." +msgstr "" +"टैग `3` का उपयोग इसलिए किया जाता है क्योंकि यह पहला उपलब्ध विषम टैग है। अपरिचित अजीब टैग " +"डिजिटल अभिलेख को अनबाउंड यानि अबाध नहीं बनाते हैं, इसलिए चाइल्‍ड डिजिटल अभिलेखों को ऑर्ड के " +"पुराने संस्करणों द्वारा पहचाना और ट्रैक किया जाएगा।" + +#: src/inscriptions/provenance.md:81 +msgid "" +"A collection can be closed by burning the collection's parent inscription, " +"which guarantees that no more items in the collection can be issued." +msgstr "" +"संग्रह के मूल डिजिटल अभिलेखों को बर्न (कुल सप्लाई कम करने के लिए किसी टोकन की निश्चित संख्या को " +"हटाकर डैड वॉलेट में रखा जाता है) करने के बाद संग्रह को बंद किया जा सकता है, जो गारंटी देता है कि संग्रह में " +"कोई और आइटम जारी नहीं की जा सकती।" + +#: src/inscriptions/recursion.md:4 +msgid "" +"An important exception to [sandboxing](../inscriptions.md#sandboxing) is " +"recursion: access to `ord`'s `/content` endpoint is permitted, allowing " +"inscriptions to access the content of other inscriptions by requesting `/" +"content/`." +msgstr "" +"[सैंडबॉक्सिंग](../inscriptions.md#sandboxing) का एक महत्वपूर्ण अपवाद " +"रिकर्सन (प्रतिवर्तन) है: `ord`'s `/ content` के अंतिम बिंदु तक पहुंच की " +"अनुमति देता है, जिससे `/content/` पर अनुरोध भेजकर अन्य इंस्‍क्रि‍प्‍शंस +"(डिजिटल अभिलेखों) की विषय-वस्‍तु तक संपर्क करने की अनुमति मिलती है।" + + +#: src/inscriptions/recursion.md:9 +msgid "This has a number of interesting use-cases:" +msgstr "इसके कई दिलचस्प उपयोज्‍य-मामले हैं:" + +#: src/inscriptions/recursion.md:11 +msgid "Remixing the content of existing inscriptions." +msgstr "प्रचलित इंस्‍क्रि‍प्‍शंस संदेशों को रीमिक्स करना।" + +#: src/inscriptions/recursion.md:13 +msgid "" +"Publishing snippets of code, images, audio, or stylesheets as shared public " +"resources." +msgstr "" +"साझा सार्वजनिक संसाधनों के रूप में कोड, चित्रों, ऑडियो या स्टाइलशीट के अंशों को " +"प्रकाशित करना।" + +#: src/inscriptions/recursion.md:16 +msgid "" +"Generative art collections where an algorithm is inscribed as JavaScript, " +"and instantiated from multiple inscriptions with unique seeds." +msgstr "" +"प्रजनक कला संग्रह जिनमें एक एल्गोरिथ्म को जावास्क्रिप्ट के रूप में अंकित किया गया है, और " +"अद्वितीय सीड्स के साथ कई इंस्‍क्रि‍प्‍शंस से प्रस्‍तुत किया गया है।" + +#: src/inscriptions/recursion.md:19 +msgid "" +"Generative profile picture collections where accessories and attributes are " +"inscribed as individual images, or in a shared texture atlas, and then " +"combined, collage-style, in unique combinations in multiple inscriptions." +msgstr "" +"प्रजनक प्रोफ़ाइल चित्र संग्रह जहां सहायक विषय-वस्‍तु और गुणों को अलग-अलग चित्रों के रूप में, या " +"एक साझा बनावट एटलस में उत्‍कीर्ण किया जाता है, और उसके बाद कई इंस्‍क्रि‍प्‍शंस में अद्वितीय " +"संयोजनों में, समुच्चित चित्र-शैली में संयोजित किया जाता है।" + +#: src/inscriptions/recursion.md:23 +msgid "A few other endpoints that inscriptions may access are the following:" +msgstr "इंस्‍क्रि‍प्‍शंस द्वारा संपर्क किए जा सकने वाले कुछ अन्य अंतिम बिंदु निम्नलिखित हैं:" + +#: src/inscriptions/recursion.md:25 +msgid "`/blockheight`: latest block height." +msgstr "`/blockheight`: नवीनतम ब्लॉक ऊंचाई" + +#: src/inscriptions/recursion.md:26 +msgid "`/blockhash`: latest block hash." +msgstr "`/blockhash`: नवीनतम ब्लॉक हैश" + +#: src/inscriptions/recursion.md:27 +msgid "`/blockhash/`: block hash at given block height." +msgstr "`/blockhash/`: दी गई ब्लॉक ऊंचाई पर ब्लॉक हैश" + +#: src/inscriptions/recursion.md:28 +msgid "`/blocktime`: UNIX time stamp of latest block." +msgstr "`/blocktime`: नवीनतम ब्लॉक का यूनिक्स टाइम स्टैम्प" + +#: src/faq.md:1 +msgid "Ordinal Theory FAQ" +msgstr "ऑर्डिनल थ्‍यौरी एफएक्‍यू" + +#: src/faq.md:4 +msgid "What is ordinal theory?" +msgstr "ऑर्डिनल थ्‍यौरी क्या है?" + +#: src/faq.md:7 +msgid "" +"Ordinal theory is a protocol for assigning serial numbers to satoshis, the " +"smallest subdivision of a bitcoin, and tracking those satoshis as they are " +"spent by transactions." +msgstr "" +"ऑर्डिनल थ्‍यौरी एक प्रोटोकॉल है जिसके अधीन बिटकॉइन के अंश के सबसे छोटे भाग को सातोशी में क्रम " +"संख्‍या निर्दिष्ट करने और लेनदेन के रूप में खर्च सातोशी को ट्रैक करने के लिए एक प्रोटोकॉल है।" + +#: src/faq.md:11 +msgid "" +"These serial numbers are large numbers, like this 804766073970493. Every " +"satoshi, which is ¹⁄₁₀₀₀₀₀₀₀₀ of a bitcoin, has an ordinal number." +msgstr "" +"ये क्रम संख्‍या बड़ी संख्याएँ होती हैं, जैसे 804766073970493। प्रत्येक सातोशी, जो एक बिटकॉइन " +"का ¹⁄₁₀₀₀₀₀₀₀₀ भाग है, उसमें क्रमसूचक संख्या निहित होती हैं।" + +#: src/faq.md:14 +msgid "" +"Does ordinal theory require a side chain, a separate token, or changes to " +"Bitcoin?" +msgstr "" +"क्या ऑर्डिनल थ्‍यौरी के लिए साइड चेन, अलग टोकन या बिटकॉइन में बदलाव करने की आवश्यकता " +"होती है?" + +#: src/faq.md:17 +msgid "" +"Nope! Ordinal theory works right now, without a side chain, and the only " +"token needed is bitcoin itself." +msgstr "" +"बिलकुल नहीं! वर्तमान समय में, आर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) साइड चेन के बगैर काम करती है, और " +"इसके लिए सिर्फ बिटकॉइन टोकन ही जरूरी होता है।" + +#: src/faq.md:20 +msgid "What is ordinal theory good for?" +msgstr "ऑर्डिनल थ्‍यौरी किस प्रकार से अच्छी है?" + +#: src/faq.md:23 +msgid "" +"Collecting, trading, and scheming. Ordinal theory assigns identities to " +"individual satoshis, allowing them to be individually tracked and traded, as " +"curios and for numismatic value." +msgstr "" +"संग्रह, लेनदेन करना और योजना बनाना। आर्डिनल थ्‍यौरी व्यक्तिगत सातोशियों को पहचान देती है, ताकि वे " +"व्यक्तिगत रूप से ट्रैक और क्‍यूरियस के रूप में मौद्रिक मूल्‍य पर लेनदेन कर सकें।" + +#: src/faq.md:27 +msgid "" +"Ordinal theory also enables inscriptions, a protocol for attaching arbitrary " +"content to individual satoshis, turning them into bitcoin-native digital " +"artifacts." +msgstr "" +"ऑर्डिनल थ्‍यौरी इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) को भी सक्षम बनाता है, जो स्‍वेच्छित संदेशों को " +"व्यक्तिगत सातोशियों के साथ जोड़ने के लिए एक प्रोटोकॉल है, उन्हें बिटकॉइन-मूल डिजिटल कलाकृतियों में " +"परिवर्तित करता है।" + +#: src/faq.md:31 +msgid "How does ordinal theory work?" +msgstr "ऑर्डिनल थ्‍यौरी कैसे काम करती है?" + +#: src/faq.md:34 +msgid "" +"Ordinal numbers are assigned to satoshis in the order in which they are " +"mined. The first satoshi in the first block has ordinal number 0, the second " +"has ordinal number 1, and the last satoshi of the first block has ordinal " +"number 4,999,999,999." +msgstr "" +"क्रमसूचक संख्‍याएं सातोशि‍यों को उस क्रम में निर्दिष्‍ट की जाती हैं, जिस क्रम में उनका खनन किया जाता है। " +"पहले ब्लॉक के पहले सातोशी की क्रमसूचक संख्‍या 0 है, दूसरे की क्रमसूचक संख्‍या 1 है, और पहले ब्लॉक के " +"अंतिम सातोशी की क्रमसूचक संख्‍या 4,999,999,999 है।" + +#: src/faq.md:39 +msgid "" +"Satoshis live in outputs, but transactions destroy outputs and create new " +"ones, so ordinal theory uses an algorithm to determine how satoshis hop from " +"the inputs of a transaction to its outputs." +msgstr "" +"सातोशी आउटपुट में निर्वाह करते हैं, लेकिन लेनदेन आउटपुट को नष्ट करके नई आउटपुट का सृजन कर लिया " +"है, इसलिए आर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) एक एल्गोरिदम (कलन विध‍ि) का उपयोग करके यह निर्धारित " +"करती है कि कैसे सातोषी लेनदेन के इनपुट से उसके आउटपुट तक उछाल लगाते हैं।" + +#: src/faq.md:43 +msgid "Fortunately, that algorithm is very simple." +msgstr "सौभाग्य से, यह एल्गोरिदम बहुत सरल है।" + +#: src/faq.md:45 +msgid "" +"Satoshis transfer in first-in-first-out order. Think of the inputs to a " +"transaction as being a list of satoshis, and the outputs as a list of slots, " +"waiting to receive a satoshi. To assign input satoshis to slots, go through " +"each satoshi in the inputs in order, and assign each to the first available " +"slot in the outputs." +msgstr "" +"सातोशी फर्स्ट-इन-फर्स्ट-आउट (फीफो) क्रम में स्थानांतरण करते हैं। लेन-देन इनपुट को सातोशी की सूची और " +"आउटपुट को सातोशी प्राप्त करने की प्रतीक्षारत स्लॉट की सूची के रूप में विचार करते हैं। इनपुट सातोशी को " +"स्लॉट में निर्दिष्‍ट करने के लिए, इनपुट में प्रत्येक सातोशी की क्रम से जांच-परख करें, और प्रत्येक को आउटपुट " +"में पहले उपलब्ध स्लॉट में निर्दिष्‍ट कर दें।" + +#: src/faq.md:51 +msgid "" +"Let's imagine a transaction with three inputs and two outputs. The inputs " +"are on the left of the arrow and the outputs are on the right, all labeled " +"with their values:" +msgstr "" +"आइए तीन इनपुट और दो आउटपुट वाले लेनदेन की कल्पना करते हैं। इनपुट तीर के बाईं ओर हैं और आउटपुट " +"तीर के दाईं ओर रखी गई हैं, उन सभी पर उनके मान के साथ लेबल लगाए गए हैं:" + +#: src/faq.md:55 +msgid "" +"```\n" +"[2] [1] [3] → [4] [2]\n" +"```" +msgstr "" + +#: src/faq.md:57 +msgid "" +"Now let's label the same transaction with the ordinal numbers of the " +"satoshis that each input contains, and question marks for each output slot. " +"Ordinal numbers are large, so let's use letters to represent them:" +msgstr "" +"अब चलिए उसी लेन-देन को उस प्रवेश इनपुट में होने वाले सतोशियों के क्रमिक अंकों से चिह्नित करते हैं, " +"और प्रत्येक आउटपुट स्लॉट के लिए प्रश्न चिह्न। क्रमिक अंक बड़े होते हैं, इसलिए चलिए उन्हें प्रतिस्थापित " +"करने के लिए अक्षरों का उपयोग करते हैं:" + +#: src/faq.md:61 +msgid "" +"```\n" +"[a b] [c] [d e f] → [? ? ? ?] [? ?]\n" +"```" +msgstr "" + +#: src/faq.md:63 +msgid "" +"To figure out which satoshi goes to which output, go through the input " +"satoshis in order and assign each to a question mark:" +msgstr "" +"यह समझने के लिए कि कौन सा सातोशी किस आउटपुट में जाता है, प्रवेश सतोशियों को क्रम में " +"देखें और प्रत्येक को एक प्रश्न चिह्न के साथ सौंपें:" + +#: src/faq.md:66 +msgid "" +"```\n" +"[a b] [c] [d e f] → [a b c d] [e f]\n" +"```" +msgstr "" + +#: src/faq.md:68 +msgid "" +"What about fees, you might ask? Good question! Let's imagine the same " +"transaction, this time with a two satoshi fee. Transactions with fees send " +"more satoshis in the inputs than are received by the outputs, so to make our " +"transaction into one that pays fees, we'll remove the second output:" +msgstr "" +"आप शुल्क के बारे में पूछ सकते हैं, हैं ना? अच्छा सवाल! चलिए वही लेन-देन कल्पना करते हैं, इस बार दो " +"सातोशी शुल्क के साथ। शुल्क वाले लेन-देन में प्रवेश में अधिक सातोशियाँ भेजी जाती हैं जितनी आउटपुट द्वारा " +"प्राप्त होती है, इसलिए हमारे लेन-देन को एक शुल्क चुकाने वाले लेन-देन में बदलने के लिए, हम दूसरे आउटपुट " +"को हटा देंगे:" + +#: src/faq.md:73 +msgid "" +"```\n" +"[2] [1] [3] → [4]\n" +"```" +msgstr "" + +#: src/faq.md:75 +msgid "The satoshis " +msgstr "सातोशी" + +#: src/faq.md:75 +msgid "e" +msgstr "" + +#: src/faq.md:75 +msgid " and " +msgstr " और " + +#: src/faq.md:75 +msgid "f" +msgstr "" + +#: src/faq.md:75 +msgid " now have nowhere to go in the outputs:" +msgstr "आउटपुट में निष्क्रिय हो गया है:" + +#: src/faq.md:78 +msgid "" +"```\n" +"[a b] [c] [d e f] → [a b c d]\n" +"```" +msgstr "" +"```\n" +"[a b] [c] [d e f] → [a b c d]\n" +"```" + +#: src/faq.md:80 +msgid "" +"So they go to the miner who mined the block as fees. [The BIP](https://" +"github.com/ordinals/ord/blob/master/bip.mediawiki) has the details, but in " +"short, fees paid by transactions are treated as extra inputs to the coinbase " +"transaction, and are ordered how their corresponding transactions are " +"ordered in the block. The coinbase transaction of the block might look like " +"this:" +msgstr "" +"इसलिए वे शुल्‍क के रूप में ब्‍लॉक का खनन करने वाले माइनर (खनिक) के पास जाते हैं। " +"बीआईपी [The BIP](https://github.com/ordinals/ord/blob/master/bip.mediawiki) " +"में विवरण दिए गये हैं, लेकिन संक्षेप में, लेनदेन द्वारा किए गये भुगतान शुल्‍क सिक्‍का आधारित लेनदेन के अतिरिक्त " +"इनपुट के रूप में उपचारित किये जाएंगे, और इस तरह क्रमबद्ध किये जाएंगे जिस क्रम में ब्लॉक में उनके संबंधित " +"लेनदेन के क्रम दिये गये हैं। ब्लॉक का कॉइनबेस लेनदेन इस तरह दिख सकता है:" + +#: src/faq.md:87 +msgid "" +"```\n" +"[SUBSIDY] [e f] → [SUBSIDY e f]\n" +"```" +msgstr "" + +#: src/faq.md:89 +msgid "Where can I find the nitty-gritty details?" +msgstr "मैं कहां से विस्तृत विवरण प्राप्‍त कर सकता हूं?" + +#: src/faq.md:92 +msgid "[The BIP!](https://github.com/ordinals/ord/blob/master/bip.mediawiki)" +msgstr "[बीआईपी!](https://github.com/ordinals/ord/blob/master/bip.mediawiki)" + +#: src/faq.md:94 +msgid "" +"Why are sat inscriptions called \"digital artifacts\" instead of \"NFTs\"?" +msgstr "सैट इंस्‍क्रि‍प्‍शंस को क्‍यों "एनएफटी" के बदले "डिजिटल अभिलेख" कहा जाता है?" + +#: src/faq.md:97 +msgid "" +"An inscription is an NFT, but the term \"digital artifact\" is used instead, " +"because it's simple, suggestive, and familiar." +msgstr "" +"एक इंस्‍क्रि‍प्‍शंस एनएफटी है, लेकिन इसके बजाय इसके लिए \"डिजिटल अभिलेख\" शब्द का उपयोग किया जाता है, " +"क्योंकि यह सरल, सांकेतिक और परिचित है।" + +#: src/faq.md:100 +msgid "" +"The phrase \"digital artifact\" is highly suggestive, even to someone who " +"has never heard the term before. In comparison, NFT is an acronym, and " +"doesn't provide any indication of what it means if you haven't heard the " +"term before." +msgstr "" +"वाक्यांश \"डिजिटल अभिलेख\" अत्यधिक सांकेतिक है, यहां तक कि उस व्यक्ति के लिए भी जिसने यह शब्द " +"पहले कभी नहीं सुना है। इसकी तुलना में, एनएफटी एक संक्षिप्त शब्द है, और यदि आपने इस शब्द को पहले " +"नहीं सुना है तो यह इसका कोई संकेत व्‍यक्‍त नहीं करता है कि इसका क्या अर्थ हो सकता है।" + +#: src/faq.md:104 +msgid "" +"Additionally, \"NFT\" feels like financial terminology, and the both word " +"\"fungible\" and sense of the word \"token\" as used in \"NFT\" is uncommon " +"outside of financial contexts." +msgstr "" +"इसके अतिरिक्त, \"एनएफटी\" एक प्रकार से वित्तीय शब्दावली सदृश लगता है, और \"एनएफटी\" में प्रयुक्त शब्द " +"\"प्रतिमोच्‍य\" और \"टोकन\" शब्द का अर्थ वित्तीय संदर्भों के बाहर बहुत ही असामान्य है।" + +#: src/faq.md:108 +msgid "How do sat inscriptions compare to…" +msgstr "सैट्स अभिलेखों की तुलना निम्‍न के साथ किस प्रकार की जाती है…" + +#: src/faq.md:111 +msgid "Ethereum NFTs?" +msgstr "एथेरियम एनएफटी?" + +#: src/faq.md:113 +msgid "_Inscriptions are always immutable._" +msgstr "_डिजिटल अभिलेख सदैव अपरिवर्तनीय रहते हैं।_" + +#: src/faq.md:115 +msgid "" +"There is simply no way to for the creator of an inscription, or the owner of " +"an inscription, to modify it after it has been created." +msgstr "" +"एक बार किसी डिजिटल अभिलेख का सृजन करने के बाद किसी भी तरीके से उसके निर्माता, या किसी " +"डिजिटल अभिलेख का सृजनकर्ता उसे संशोधित नहीं कर सकते।" + +#: src/faq.md:118 +msgid "" +"Ethereum NFTs _can_ be immutable, but many are not, and can be changed or " +"deleted by the NFT contract owner." +msgstr "" +"एथेरियम एनएफटी अपरिवर्तनीय _हो सकते हैं_, लेकिन बहुत सारे नहीं, और इन्‍हें एनएफटी अनुबंध मालिकों के " +"द्वारा बदला या हटाया जा सकता है।" + +#: src/faq.md:121 +msgid "" +"In order to make sure that a particular Ethereum NFT is immutable, the " +"contract code must be audited, which requires detailed knowledge of the EVM " +"and Solidity semantics." +msgstr "" +"यह सुनिश्चित करने के लिए एथेरियम एनएफटी अपरिवर्तनीय हैं, उनके अनुबंध कोड का लेखा-परीक्षण किया " +"जाना चाहिए, जिसके लिए ईवीएम और मजबूती के शब्‍दार्थ का विस्‍तृत ज्ञान होना अत्‍यन्‍त आवश्‍यक है।" + +#: src/faq.md:125 +msgid "" +"It is very hard for a non-technical user to determine whether or not a given " +"Ethereum NFT is mutable or immutable, and Ethereum NFT platforms make no " +"effort to distinguish whether an NFT is mutable or immutable, and whether " +"the contract source code is available and has been audited." +msgstr "" +"एक गैर-तकनीकी उपयोगकर्ता के लिए यह तय करना बहुत मुश्किल है कि क्‍या एथेरियम एनएफटी परिवर्तनीय " +"या अपरिवर्तनीय है या नहीं, और एथेरियम एनएफटी मंच यह अंतर करने का बिलकुल प्रयास नहीं करते कि कोई " +"एनएफटी परिवर्तनीय है या अपरिवर्तनीय है, और क्या अनुबंध स्रोत कोड उपलब्ध है और उसका लेखा-परीक्षण " +"किया गया है।" + +#: src/faq.md:130 +msgid "_Inscription content is always on-chain._" +msgstr "_इंस्‍क्र‍िपशन (डिजिटल अभिलेख) विषय-वस्‍तु हमेशा ऑन-चेन होती हैं।_" + +#: src/faq.md:132 +msgid "" +"There is no way for an inscription to refer to off-chain content. This makes " +"inscriptions more durable, because content cannot be lost, and scarcer, " +"because inscription creators must pay fees proportional to the size of the " +"content." +msgstr "" +"किसी भी सूरत में इंस्‍क्र‍िपशन (डिजिटल अभिलेख) ऑफ-चेन विषय-वस्‍तु को संदर्भित नहीं करते। यह " +"इंस्‍क्र‍िपशन को अधिक स्थिर बनाता है, क्योंकि विषय-वस्‍तु नष्ट नहीं हो सकते हैं, और " +"दुर्लभ हैं, क्योंकि इंस्‍क्र‍िपशन (डिजिटल अभिलेख) के सृजनकर्ता को विषय-वस्‍तु के आकार के अनुपात में शुल्क " +"का भुगतान करना होगा।" + +#: src/faq.md:136 +msgid "" +"Some Ethereum NFT content is on-chain, but much is off-chain, and is stored " +"on platforms like IPFS or Arweave, or on traditional, fully centralized web " +"servers. Content on IPFS is not guaranteed to continue to be available, and " +"some NFT content stored on IPFS has already been lost. Platforms like " +"Arweave rely on weak economic assumptions, and will likely fail " +"catastrophically when these economic assumptions are no longer met. " +"Centralized web servers may disappear at any time." +msgstr "" +"कुछ एथेरियम एनएफटी विषय-वस्‍तु ऑन-चेन (क्लाउड सदृश सभी के लिए दृश्यमान) हैं, लेकिन अधिकांश " +"ऑफ-चेन (निजी हैं सार्वजनिक रूप से दृश्य नहीं हैं) हैं, और इन्‍हें IPFS या Arweave जैसे मंचों पर, या " +"पारंपरिक रूप से, पूरी तरह से केंद्रीकृत वेब सर्वर पर संग्रहि‍त किया जाता है। आईपीएफएस पर विषय-वस्‍तु " +"उपलब्ध रहने की गारंटी नहीं है, और आईपीएफएस पर संग्रहीत कुछ एनएफटी विषय-वस्‍तु पहले ही खो चुकी " +"है। Arweave जैसे प्लेटफ़ॉर्म कमज़ोर आर्थिक धारणाओं पर भरोसा करते हैं, और जब ये आर्थिक धारणाएँ पूरी " +"नहीं होंगी तो संभवतः विनाशकारी रूप से विफल हो जाएंगे। केंद्रीकृत वेब सर्वर किसी भी समय गायब हो सकते हैं।" + +#: src/faq.md:144 +msgid "" +"It is very hard for a non-technical user to determine where the content of a " +"given Ethereum NFT is stored." +msgstr "" +"एक गैर-तकनीकी उपयोगकर्ता के लिए यह तय करना बहुत मुश्किल है कि दी गई एथेरियम एनएफटी की विषय-वस्‍तु " +"कहाँ संग्रहीत की गई है।" + +#: src/faq.md:147 +msgid "_Inscriptions are much simpler._" +msgstr "_इंस्‍क्र‍िपशन (डिजिटल अभिलेख) बहुत सरल हैं।_" + +#: src/faq.md:149 +msgid "" +"Ethereum NFTs depend on the Ethereum network and virtual machine, which are " +"highly complex, constantly changing, and which introduce changes via " +"backwards-incompatible hard forks." +msgstr "" +"एथेरियम एनएफटी, एथेरियम नेटवर्क और वर्चुअल मशीन पर निर्भर करते हैं, जो बेहद जटिल होते हैं, निरंतर " +"बदलते रहते हैं, और जो बैकवर्ड-कम्‍पेटिबल हार्ड फोर्क्स (बैकवर्ड कम्पैटिबिलिटी को किसी भी हार्डवेयर या " +"सॉफ़्टवेयर के पुराने सॉफ़्टवेयर संस्करणों से इंटरफ़ेस का उपयोग करने या अन्य हार्डवेयर सिस्टम के साथ पुराने " +"मॉडलों के साथ संगत करना) के माध्यम से अपडेट होते रहते हैं।" + +#: src/faq.md:153 +msgid "" +"Inscriptions, on the other hand, depend on the Bitcoin blockchain, which is " +"relatively simple and conservative, and which introduces changes via " +"backwards-compatible soft forks." +msgstr "" +"दूसरी ओर, इंस्‍क्रि‍प्‍शंस बिटकॉइन ब्लॉकचेन पर निर्भर करते हैं, जो अपेक्षाकृत सरल हैं लेकिन परिवर्तनशील " +"नहीं हैं, और जो बैकवर्ड-संगत सॉफ्ट फोर्क्स के माध्यम से परिवर्तन अपडेट करते हैं।" + +#: src/faq.md:157 +msgid "_Inscriptions are more secure._" +msgstr "_इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) अधिक सुरक्षित हैं।_" + +#: src/faq.md:159 +msgid "" +"Inscriptions inherit Bitcoin's transaction model, which allow a user to see " +"exactly which inscriptions are being transferred by a transaction before " +"they sign it. Inscriptions can be offered for sale using partially signed " +"transactions, which don't require allowing a third party, such as an " +"exchange or marketplace, to transfer them on the user's behalf." +msgstr "" +"इंस्‍क्रि‍प्‍शंस बिटकॉइन के लेनदेन मॉडल को विरासत में अपनाते हैं। यह उपयोगकर्ता को हस्ताक्षर करने से पहले " +"यह देखने की अनुमति देते हैं कि वास्‍तव में लेनदेन द्वारा कौन से इंस्‍क्रि‍प्‍शंस स्थानांतरित किए जा रहे हैं। " +"इंस्‍क्रि‍प्‍शंस की आंशिक रूप से लेनदेन पर हस्‍ताक्षर करके बिक्री की जा सकती है, जिसके लिए उपयोगकर्ता की ओर " +"से उन्हें स्थानांतरित करने के लिए एक्सचेंज या बाजार जैसे किसी तीसरे पक्ष से अनुमति लेने की आवश्यकता नहीं होती।" + +#: src/faq.md:165 +msgid "" +"By comparison, Ethereum NFTs are plagued with end-user security " +"vulnerabilities. It is commonplace to blind-sign transactions, grant third-" +"party apps unlimited permissions over a user's NFTs, and interact with " +"complex and unpredictable smart contracts. This creates a minefield of " +"hazards for Ethereum NFT users which are simply not a concern for ordinal " +"theorists." +msgstr "" +"तुलनात्मक रूप से, एथेरियम एनएफटी अंतिम-उपयोगकर्ता सुरक्षा अरक्षितता से ग्रस्त हैं। लेनदेन पर अंधाधुंध " +"हस्ताक्षर करना, उपयोगकर्ता के एनएफटी पर तीसरे पक्ष के ऐप्स तक पहुंच को असीमित अनुमति देना और " +"जटिल और अप्रत्याशित स्मार्ट अनुबंधों के साथ समन्‍वय करना इनमें आम कमजोरियां हैं। यह एथेरियम " +"एनएफटी उपयोगकर्ताओं के लिए खतरों से भरी विस्‍फोटक स्थिति उत्‍पन्‍न कर देता है जो आर्डिनल थ्‍योरिस्‍ट " +"(क्रमसूचक सिद्धांतवादियों) के लिए चिंता का विषय नहीं है।" + +#: src/faq.md:171 +msgid "_Inscriptions are scarcer._" +msgstr "_इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) दुर्लभ हैं।_" + +#: src/faq.md:173 +msgid "" +"Inscriptions require bitcoin to mint, transfer, and store. This seems like a " +"downside on the surface, but the raison d'etre of digital artifacts is to be " +"scarce and thus valuable." +msgstr "" +"इंस्‍क्रि‍प्‍शंस की ढलाई, स्थानांतरित करने और संग्रहीत करने के लिए बिटकॉइन की आवश्यकता पड़ती है। " +"वास्‍तविक धरातल पर यह एक नकारात्मक पहलू प्रतीत होता है, लेकिन डिजिटल अभिलेख का उद्देश्‍य दुर्लभ है " +"और इसलिए यह मूल्यवान है। " + +#: src/faq.md:177 +msgid "" +"Ethereum NFTs, on the other hand, can be minted in virtually unlimited " +"qualities with a single transaction, making them inherently less scarce, and " +"thus, potentially less valuable." +msgstr "" +"एथेरियम एनएफटी, दूसरी ओर, एक ही लेन-देन के साथ लगभग असीमित गुणों में ढाले जा सकते हैं, जिससे वे " +"स्वाभाविक रूप से कम दुर्लभ बन जाते हैं, और इसीलिए, संभावित रूप से कम मूल्यवान होते हैं।" + +#: src/faq.md:181 +msgid "_Inscriptions do not pretend to support on-chain royalties._" +msgstr "_इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख), ऑन-चेन रॉयल्टी का समर्थन करने का दिखावा नहीं करते हैं।_" + +#: src/faq.md:183 +msgid "" +"On-chain royalties are a good idea in theory but not in practice. Royalty " +"payment cannot be enforced on-chain without complex and invasive " +"restrictions. The Ethereum NFT ecosystem is currently grappling with " +"confusion around royalties, and is collectively coming to grips with the " +"reality that on-chain royalties, which were messaged to artists as an " +"advantage of NFTs, are not possible, while platforms race to the bottom and " +"remove royalty support." +msgstr "" +"ऑन-चेन रॉयल्टी सैद्धांति‍क रूप में एक अच्छा विचार है लेकिन व्यवहारि‍क नहीं है। जटिल और आक्रामक " +"प्रतिबंधों के बिना रॉयल्टी के भुगतान ऑन-चेन पर लागू नहीं किये जा सकते। वर्तमान समय में, एथेरियम " +"एनएफटी पारिस्थितिकी तंत्र रॉयल्टी के इर्दगिर्द आशंका से जूझ रहा है, और सामूहिक रूप से इस असलियत " +"की चपेट में आ गया है कि ऑन-चेन रॉयल्टी, जिसके संदेश कलाकारों को एनएफटी के लाभ के रूप में भेजे गये " +"थे, संभव ही नहीं हैं, जबकि मंच सभी नियमों का ताक पर रखकर रॉयल्टी समर्थन को समाप्‍त कर देते हैं।" + +#: src/faq.md:190 +msgid "" +"Inscriptions avoid this situation entirely by making no false promises of " +"supporting royalties on-chain, thus avoiding the confusion, chaos, and " +"negativity of the Ethereum NFT situation." +msgstr "" +"इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख), ऑन-चेन की तरह रॉयल्टी के समर्थन का ऐसा कोई झूठा वायदा नहीं करता " +"और इस स्थिति से सर्वथा पूरी तरह बचता है, इस प्रकार, एथेरियम एनएफटी जैसी स्थिति के भ्रम, अराजकता " +"और नकारात्मकता से बचते हैं।" + +#: src/faq.md:194 +msgid "_Inscriptions unlock new markets._" +msgstr "_इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) नए बाज़ारों में प्रवेश_" + +#: src/faq.md:196 +msgid "" +"Bitcoin's market capitalization and liquidity are greater than Ethereum's by " +"a large margin. Much of this liquidity is not available to Ethereum NFTs, " +"since many Bitcoiners prefer not to interact with the Ethereum ecosystem due " +"to concerns related to simplicity, security, and decentralization." +msgstr "" +"बिटकॉइन का बाजारी पूंजीकरण और तरलता एथेरियम से काफी अधिक है। इस तरलता का अधिकांश भाग " +"एथेरियम एनएफटी के लिए उपलब्ध नहीं होता है, क्योंकि कई बिटकॉन उपयोगकर्ता इसकी सरलता, सुरक्षा " +"और विकेंद्रीकरण से संबंधित सरोकारों के कारण एथेरियम पारिस्थितिकी तंत्र के साथ समन्‍वय करना पसंद नहीं करते हैं।" + +#: src/faq.md:201 +msgid "" +"Such Bitcoiners may be more interested in inscriptions than Ethereum NFTs, " +"unlocking new classes of collector." +msgstr "" +"ऐसे बिटकॉन उपयोगकर्ता, एथेरियम एनएफटी की तुलना में इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) में अधिक " +"दिलचस्‍पी दिखा सकते हैं, जो संग्रहकों के नए वर्गों के द्वार खोल देते हैं।" + +#: src/faq.md:204 +msgid "_Inscriptions have a richer data model._" +msgstr "_इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) का समृद्ध डेटा मॉडल है।_" + +#: src/faq.md:206 +msgid "" +"Inscriptions consist of a content type, also known as a MIME type, and " +"content, which is an arbitrary byte string. This is the same data model used " +"by the web, and allows inscription content to evolve with the web, and come " +"to support any kind of content supported by web browsers, without requiring " +"changes to the underlying protocol." +msgstr "" +"इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) में विषय-वस्‍तु का प्रकार सम्मिलित होता है, जिसे MIME प्रकार के रूप में भी " +"जाना जाता है, और इसकी विषय-वस्‍तु एक स्‍वेच्छित बाइट स्ट्रिंग होती है। यह वेब द्वारा उपयोग किया जाने " +"वाला वैसा ही डेटा मॉडल है, और इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु को वेब के साथ विकसित करने में सक्षम करता है, " +"और अंतर्निहित प्रोटोकॉल में बदलाव की जरूरत के बिना, वेब ब्राउज़र द्वारा समर्थित किसी भी प्रकार की " +"विषय-वस्‍तु का समर्थन करता है।" + +#: src/faq.md:212 +msgid "RGB and Taro assets?" +msgstr "RGB (आरजीबी) और Taro (टैरो) संपत्तियां?" + +#: src/faq.md:214 +msgid "" +"RGB and Taro are both second-layer asset protocols built on Bitcoin. " +"Compared to inscriptions, they are much more complicated, but much more " +"featureful." +msgstr "" +"RGB और Taro दोनों बिटकॉइन पर निर्मित दूसरी परत के परिसंपत्ति प्रोटोकॉल हैं। इंस्‍क्रि‍प्‍शंस की तुलना में, " +"वे बहुत अधिक जटिल हैं, लेकिन बहुत अधिक विशिष्ट भी हैं।" + +#: src/faq.md:217 +msgid "" +"Ordinal theory has been designed from the ground up for digital artifacts, " +"whereas the primary use-case of RGB and Taro are fungible tokens, so the " +"user experience for inscriptions is likely to be simpler and more polished " +"than the user experience for RGB and Taro NFTs." +msgstr "" +"डिजिटल अभिलेखों के लिए ऑर्डिनल सिद्धांत को जमीनी स्तर पर डिजाइन किया गया है, जबकि RGB " +"और Taro के प्राथमिक उपयोग-मामले परिवर्तनीय टोकन हैं, इसलिए इंस्‍क्रि‍प्‍शंस के लिए उपयोगकर्ता अनुभव " +"आरजीबी और टैरो एनएफटी के लिए उपयोगकर्ता अनुभव की तुलना में सरल और अधिक परिष्कृत होने की " +"संभावना है।" + +#: src/faq.md:222 +msgid "" +"RGB and Taro both store content off-chain, which requires additional " +"infrastructure, and which may be lost. By contrast, inscription content is " +"stored on-chain, and cannot be lost." +msgstr "" +"RGB और Taro दोनों ऑफ-चेन विषय-वस्‍तु संग्रहीत करते हैं, जिसके लिए अतिरिक्त बुनियादी ढांचे की " +"आवश्यकता होती है, और जो खो सकता है। इसके विपरीत, इंस्‍क्रि‍प्‍शंस विषय-वस्‍तु को श्रृंखला पर संग्रहीत " +"किया जाता है, और उसे खोया नहीं जा सकता।" + +#: src/faq.md:226 +msgid "" +"Ordinal theory, RGB, and Taro are all very early, so this is speculation, " +"but ordinal theory's focus may give it the edge in terms of features for " +"digital artifacts, including a better content model, and features like " +"globally unique symbols." +msgstr "" +"ऑर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत), RGB और Taro पुराने हो गये हैं, इसलिए यह अनुमान/सट्टा हैं, लेकिन " +"ऑर्डिनल थ्‍यौरी इसे डिजिटल अभिलेखों के लिए सुविधाओं के मामले में अनुकूल या श्रेष्ठ स्थिति में बेहतर लाभ " +"प्रदान कर सकती है, जिसमें एक बेहतर विषय-वस्‍तु मॉडल और विश्व स्तर पर अद्वितीय प्रतीकों जैसी विशेषताएं। " +"शामिल हैं।" + +#: src/faq.md:231 +msgid "Counterparty assets?" +msgstr "प्रतिपक्ष संपत्तियां?" + +#: src/faq.md:233 +msgid "" +"Counterparty has its own token, XCP, which is required for some " +"functionality, which makes most bitcoiners regard it as an altcoin, and not " +"an extension or second layer for bitcoin." +msgstr "" +"प्रतिपक्ष के अपने स्‍वयं के टोकन, XCP (एक्ससीपी) हैं, जो कुछ कार्यक्षमता के लिए अत्‍यंत आवश्यक हैं, जिससे " +"अधिकांश बिटकॉइनर्स इसे एक आल्टकॉइन के रूप में मानते हैं, न कि बिटकॉइन का विस्‍तार/प्रसार या दूसरी " +"परत का रूप।" + +#: src/faq.md:237 +msgid "" +"Ordinal theory has been designed from the ground up for digital artifacts, " +"whereas Counterparty was primarily designed for financial token issuance." +msgstr "" +"ऑर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत), का सृजन पूरी तरह से डिजिटल अभिलेखों के लिए किया गया है, " +"जबकि प्रतिपक्ष संपत्तियों को मुख्य रूप से वित्तीय टोकन जारी करने के लिए डिज़ाइन किया गया था।" + +#: src/faq.md:240 +msgid "Inscriptions for…" +msgstr "इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख)…" + +#: src/faq.md:243 +msgid "Artists" +msgstr "कलाकारों के लिए" + +#: src/faq.md:245 +msgid "" +"_Inscriptions are on Bitcoin._ Bitcoin is the digital currency with the " +"highest status and greatest chance of long-term survival. If you want to " +"guarantee that your art survives into the future, there is no better way to " +"publish it than as inscriptions." +msgstr "" +"_इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) बिटकॉइन पर उपलब्‍ध होते हैं।_ बिटकॉइन उच्चतम स्थिति और दीर्घकालिक " +"अस्तित्व की सबसे व्‍यापक संभावना वाली डिजिटल मुद्रा है। यदि आप यह गारंटी देना चाहते हैं कि " +"आपकी कला भविष्य में भी अस्तित्‍व में बरकरार रहे, तो इसे इंस्‍क्रि‍प्‍शंस के रूप में प्रकाशित करने का इससे बेहतर " +"कोई भी दूसरा तरीका नहीं है।" + + +#: src/faq.md:250 +msgid "" +"_Cheaper on-chain storage._ At $20,000 per BTC and the minimum relay fee of " +"1 satoshi per vbyte, publishing inscription content costs $50 per 1 million " +"bytes." +msgstr "" +"_किफायती ऑन-चेन भंडारण।_ $20,000 प्रति बीटीसी और 1 सातोशी प्रति वीबाइट की न्यूनतम रिले शुल्क पर, " +"इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) विषय-वस्‍तु प्रकाशित करने की लागत $50 प्रति 1 मिलियन बाइट्स आती है।" + +#: src/faq.md:254 +msgid "" +"_Inscriptions are early!_ Inscriptions are still in development, and have " +"not yet launched on mainnet. This gives you an opportunity to be an early " +"adopter, and explore the medium as it evolves." +msgstr "" +"_इंस्‍क्रि‍प्‍शंस आउटडेटेड हो गई हैं!_ इंस्‍क्रि‍प्‍शंस अभी भी विकसित हो रही है, और अभी तक मुख्‍य नेट पर लॉन्च नहीं " +"हुई है। आपके लिए यह सुनहरी मौका है कि आप जल्‍द से जल्‍द इसे अपना लें, और जैसे-जैसे यह माध्यम " +"विकसित होता है, उसका फायदा उठाएं।" + +#: src/faq.md:258 +msgid "" +"_Inscriptions are simple._ Inscriptions do not require writing or " +"understanding smart contracts." +msgstr "_इंस्‍क्रि‍प्‍शंस सरल हैं।_ इंस्‍क्रि‍प्‍शंस के लिए स्मार्ट अनुबंध लिखने या समझने की बिलकुल जरूरत नहीं है।" + +#: src/faq.md:261 +msgid "" +"_Inscriptions unlock new liquidity._ Inscriptions are more accessible and " +"appealing to bitcoin holders, unlocking an entirely new class of collector." +msgstr "" +"_इंस्‍क्रि‍प्‍शंस नई लिक्विडिटी/तरलता के मार्ग प्रशस्‍त करती हैं।_ बिटकॉइन धारकों के लिए इंस्‍क्रि‍प्‍शंस अधिक " +"सुलभ और आकर्षक हैं, जो पूरी तरह नई श्रेणी के संग्रहकों के लिए लेनदेन करने के नये रास्‍ते खोल देती हैं।" + +#: src/faq.md:264 +msgid "" +"_Inscriptions are designed for digital artifacts._ Inscriptions are designed " +"from the ground up to support NFTs, and feature a better data model, and " +"features like globally unique symbols and enhanced provenance." +msgstr "" +"_इंस्‍क्रि‍प्‍शंस डिजिटल अभिलेखों के लिए डिज़ाइन किए गए हैं।_ एनएफटी का समर्थन करने के लिए इंस्‍क्रि‍प्‍शंस " +"को बुनियादी स्‍तर से ही डिज़ाइन किया जाता है, जिसमें एक बेहतर डेटा मॉडल और विश्व स्तरीय असाधारण " +"प्रतीकों और उन्नत उत्‍पति जैसी अनूठी विशेषताएं हैं।" + +#: src/faq.md:268 +msgid "" +"_Inscriptions do not support on-chain royalties._ This is negative, but only " +"depending on how you look at it. On-chain royalties have been a boon for " +"creators, but have also created a huge amount of confusion in the Ethereum " +"NFT ecosystem. The ecosystem now grapples with this issue, and is engaged in " +"a race to the bottom, towards a royalties-optional future. Inscriptions have " +"no support for on-chain royalties, because they are technically infeasible. " +"If you choose to create inscriptions, there are many ways you can work " +"around this limitation: withhold a portion of your inscriptions for future " +"sale, to benefit from future appreciation, or perhaps offer perks for users " +"who respect optional royalties." +msgstr "" +"_इंस्‍क्रि‍प्‍शंस ऑन-चेन रॉयल्टी का समर्थन नहीं करते।_ यह नकारात्मक है, जो केवल इस पर निर्भर करता है कि " +"आप इसे कैसे देखते हैं। ऑन-चेन रॉयल्टी उत्‍पतिकर्ताओं के लिए एक वरदान साबित हुआ है, लेकिन इसने " +"एथेरियम एनएफटी पारिस्थितिकी तंत्र में बहुत अधिक भ्रम भी पैदा कर दिये हैं। पारिस्थितिकी तंत्र अब इस मुद्दे " +"के साथ संघर्षरत है, और रॉयल्टी-वैकल्पिक भविष्य की ओर, प्रतिस्पर्धा की दौड़ में समझौता करने में संलग्‍न हो " +"जाता है। इंस्‍क्रि‍प्‍शंस में ऑन-चेन रॉयल्टी के लिए कोई समर्थन नहीं मिलता, क्योंकि तकनीकी रूप से वे " +"व्यवहारिक नहीं हैं। यदि आप इंस्‍क्रि‍प्‍शंस सृजन करने का चयन करते हैं, ऐसे कई तरीके हैं जिनसे आप इस " +"सीमा के दायरे में काम कर सकते हैं: अपने इंस्‍क्रि‍प्‍शंस के एक हिस्से को भविष्य में बिक्री के लिए सहेज लें, " +"ताकि भविष्य में होने वाली उछाल से लाभ उठा पाएं, या क‍दाचित वैकल्पिक रॉयल्टी देने वाले वाले " +"उपयोगकर्ताओं को प्रोत्‍साहन की पेशकश करें।" + +#: src/faq.md:279 +msgid "Collectors" +msgstr "संग्रहक" + +#: src/faq.md:281 +msgid "" +"_Inscriptions are simple, clear, and have no surprises._ They are always " +"immutable and on-chain, with no special due diligence required." +msgstr "" +"_इंस्‍क्रि‍प्‍शंस सरल, स्पष्ट हैं और इनमें कोई अप्रत्‍याशित घटना नहीं होती।_ वे हमेशा अपरिवर्तनीय और ऑन-चेन " +"रहती हैं, इसके लिए कोई विशेष सम्‍यक तत्‍परता (ड्यू डिलिजेंस) की आवश्यकता नहीं होती है।" + +#: src/faq.md:284 +msgid "" +"_Inscriptions are on Bitcoin._ You can verify the location and properties of " +"inscriptions easily with Bitcoin full node that you control." +msgstr "" +"_इंस्‍क्रि‍प्‍शंस बिटकॉइन पर सुलभ हैं।_ आप अपने नियंत्रण वाले बिटकॉइन पूर्ण नोड के साथ इंस्‍क्रि‍प्‍शंस के स्थान " +"और गुणों को आसानी से सत्यापित कर सकते हैं।" + +#: src/faq.md:287 +msgid "Bitcoiners" +msgstr "बिटकॉइनर्स" + +#: src/faq.md:289 +msgid "" +"Let me begin this section by saying: the most important thing that the " +"Bitcoin network does is decentralize money. All other use-cases are " +"secondary, including ordinal theory. The developers of ordinal theory " +"understand and acknowledge this, and believe that ordinal theory helps, at " +"least in a small way, Bitcoin's primary mission." +msgstr "" +"आईये अब मैं इस अनुभाग को यह संबोधित कर शुरू करता हूं: बिटकॉइन नेटवर्क सबसे महत्वपूर्ण काम " +"पैसे का विकेंद्रीकरण करना है। आर्डिनल थ्‍यौ‍री (क्रमसूचक सिद्धांत) सहित अन्य सभी उपयोग के मामलों " +"का महत्‍व कम है। आर्डिनल थ्‍यौ‍री (क्रमसूचक सिद्धांत) के डेवलपर्स इसे अच्‍छे से समझते हैं और स्वीकार " +"भी करते हैं, और मानते हैं कि आर्डिनल थ्‍यौ‍री (क्रमसूचक सिद्धांत), कम से कम बहुत ही मामूली तरीके " +"के साथ बिटकॉइन के प्राथमिक मिशन में मदद करती है।" + +#: src/faq.md:295 +msgid "" +"Unlike many other things in the altcoin space, digital artifacts have merit. " +"There are, of course, a great deal of NFTs that are ugly, stupid, and " +"fraudulent. However, there are many that are fantastically creative, and " +"creating and collecting art has been a part of the human story since its " +"inception, and predates even trade and money, which are also ancient " +"technologies." +msgstr "" +"ऑल्टकॉइन स्‍पेस में कई अन्य तथ्‍यों के विपरीत, डिजिटल अभिलेख सक्षम हैं। " +"बेशक, बड़ी संख्या में एनएफटी बेढंगे, मूर्खतापूर्ण और धोखाधड़ी वाले हैं। " +"हालाँकि, कुछेक ऐसे भी हैं जो शानदार ढंग से रचनात्मक हैं, और कला का निर्माण और संग्रह शुरू से ही " +"मानव इतिहास का एक अभिन्‍न हिस्सा रहा है, यहां तक कि व्यापार और मुद्रा के प्रचलन से भी " +"पहले का है, जो प्राचीन प्रौद्योगिकियां भी हैं।" + +#: src/faq.md:302 +msgid "" +"Bitcoin provides an amazing platform for creating and collecting digital " +"artifacts in a secure, decentralized way, that protects users and artists in " +"the same way that it provides an amazing platform for sending and receiving " +"value, and for all the same reasons." +msgstr "" +"बिटकॉइन डिजिटल अभिलेखों के सुरक्षित, विकेन्द्रीकृत तरीके से सृजन और संग्रह करने हेतु एक अद्भुत मंच प्रदान " +"करता है, जो उपयोगकर्ताओं और कलाकारों को उसी तरह सुरक्षा प्रदान करता है जिस प्रकार यह अद्भुत मंच धन " +"भेजने और प्राप्त करने या इस प्रकार के समान कारणों के लिए करता है।" + +#: src/faq.md:307 +msgid "" +"Ordinals and inscriptions increase demand for Bitcoin block space, which " +"increase Bitcoin's security budget, which is vital for safeguarding " +"Bitcoin's transition to a fee-dependent security model, as the block subsidy " +"is halved into insignificance." +msgstr "" +"ऑर्डिनल्स और इंस्‍क्रि‍प्‍शंस बिटकॉइन ब्लॉक स्पेस की मांग में इजाफा करते हैं, जिससे बिटकॉइन " +"का सुरक्षा बजट बढ़ जाता है, जो बिटकॉइन के शुल्क-निर्भर सुरक्षा मॉडल में ट्रांजिशन को सुरक्षित रखने " +"के लिए महत्वपूर्ण है, क्योंकि ब्लॉक की आर्थिक सहायता को निरर्थक आधा कर दिया गया है।" + +#: src/faq.md:312 +msgid "" +"Inscription content is stored on-chain, and thus the demand for block space " +"for use in inscriptions is unlimited. This creates a buyer of last resort " +"for _all_ Bitcoin block space. This will help support a robust fee market, " +"which ensures that Bitcoin remains secure." +msgstr "" +"इंस्‍क्रि‍प्‍शंस की विषय-वस्‍तु को ऑन-चेन संग्रहीत किया जाता है, और इस प्रकार इंस्‍क्रि‍प्‍शंस में उपयोग के लिए ब्लॉक स्‍पेस " +"की मांग असीमित है। यह _सभी_ बिटकॉइन ब्लॉक स्पेस के लिए खरीदार के पास अंतिम उपाय बन जाता है। +"इससे एक मजबूत शुल्क बाजार का समर्थन करने में मदद मिलेगी, " +"जो सुनिश्चित करता है कि बिटकॉइन सुरक्षित बने रहें।" + +#: src/faq.md:317 +msgid "" +"Inscriptions also counter the narrative that Bitcoin cannot be extended or " +"used for new use-cases. If you follow projects like DLCs, Fedimint, " +"Lightning, Taro, and RGB, you know that this narrative is false, but " +"inscriptions provide a counter argument which is easy to understand, and " +"which targets a popular and proven use case, NFTs, which makes it highly " +"legible." +msgstr "" +"इंस्‍क्रि‍प्‍शंस इस वृतांत का भी प्रतिकार करते हैं कि बिटकॉइन को नए उपयोग के मामलों में विस्तारित या उपयोग नहीं " +"किया जा सकता है। यदि आप डीएलसी, फेडिमिंट, लाइटनिंग, टैरो और आरजीबी जैसी परियोजनाओं का अनुसरण करते हैं, " +"तब आप जानते हैं कि यह वृतांत झूठा है, लेकिन इंस्‍क्रि‍प्‍शंस एक जवाबी तर्क प्रदान करता है जिसे समझना आसान है, " +"और जो एक लोकप्रिय और सिद्ध उपयोग के मामले, एनएफटी को लक्षित करता है, जो इसे अत्यधिक सुपाठ्य बनाता है।" + +#: src/faq.md:323 +msgid "" +"If inscriptions prove, as the authors hope, to be highly sought after " +"digital artifacts with a rich history, they will serve as a powerful hook " +"for Bitcoin adoption: come for the fun, rich art, stay for the decentralized " +"digital money." +msgstr "" +"यदि लेखकों की आशा के अनुरूप इंस्‍क्रि‍प्‍शंस समृद्ध इतिहास के साथ डिजिटल अभिलेखों की अत्यधिक मांग " +"का सृजन करने में सफल हो जाता है, तो वे बिटकॉइन अपनाने के लि‍ए एक शक्तिशाली दावे के समर्थन में कारगर " +"होंगे: चाहे वह मनोरंजन का क्षेत्र हो, समृद्ध कला, विकेंद्रीकृत डिजिटल पैसों के लेनदेनों का दृढ़ता के साथ " +"बरकरार बने रहना।" + +#: src/faq.md:327 +msgid "" +"Inscriptions are an extremely benign source of demand for block space. " +"Unlike, for example, stablecoins, which potentially give large stablecoin " +"issuers influence over the future of Bitcoin development, or DeFi, which " +"might centralize mining by introducing opportunities for MEV, digital art " +"and collectables on Bitcoin, are unlikely to produce individual entities " +"with enough power to corrupt Bitcoin. Art is decentralized." +msgstr "" +"इंस्‍क्रि‍प्‍शंस ब्लॉक स्‍पेस मांग का एक अत्‍यधिक अनुकूल स्रोत हैं। इसके विपरीत, उदाहरण के लिए, " +"स्‍टेबलकॉईन (स्थिर सिक्के), बिटकॉइन भविष्य के विकास या डीएफआई पर संभावित रूप से बिटकॉइन दिग्‍गज स्‍टेबलकॉईन " +"जारीकर्ताओं पर अपना असर डालते है, जो बिटकॉइन पर एमईवी, डिजिटल कला और संग्रहणीय वस्तुओं के लिए " +"अवसरों को प्रस्‍तुत करते हुए खनन को केंद्रीकृत कर सकते हैं, बिटकॉइन को भ्रष्ट करने के लिए पर्याप्त शक्ति वाली " +"व्यक्तिगत संस्थाओं के उत्पादन करने की संभावना नगण्‍य है। कला विकेन्द्रीकृत है।" + +#: src/faq.md:334 +msgid "" +"Inscription users and service providers are incentivized to run Bitcoin full " +"nodes, to publish and track inscriptions, and thus throw their economic " +"weight behind the honest chain." +msgstr "" +"इंस्‍क्रि‍प्‍शंस उपयोगकर्ताओं और सेवा प्रदाताओं को बिटकॉइन पूर्ण नोड्स संचालित करने, इंस्‍क्रि‍प्‍शंस प्रकाशित " +"करने और ट्रैक करने के लिए प्रोत्साहित किया जाता है, और इस प्रकार ईमानदार श्रृंखला के पीछे आक्रामक तरीके " +"से आर्थिक रूप से अपना प्रभाव डालकर समर्थन किया जाता है।" + +#: src/faq.md:338 +msgid "" +"Ordinal theory and inscriptions do not meaningfully affect Bitcoin's " +"fungibility. Bitcoin users can ignore both and be unaffected." +msgstr "" +"ऑर्डिनल्स थ्‍यौरी (क्रमसूचक सिद्धांत) और इंस्‍क्रि‍प्‍शंस (डिजिटल अभिलेख) बिटकॉइन की परिवर्तनशीलता " +"को सार्थक रूप से प्रभावित नहीं करते। बिटकॉइन उपयोगकर्ता दोनों को अनदेखा कर सकते हैं और इससे अप्रभावित " +"रह सकते हैं।" + +#: src/faq.md:341 +msgid "" +"We hope that ordinal theory strengthens and enriches bitcoin, and gives it " +"another dimension of appeal and functionality, enabling it more effectively " +"serve its primary use case as humanity's decentralized store of value." +msgstr "" +"हम आशा करते हैं कि ऑर्डिनल्स थ्‍यौरी (क्रमसूचक सिद्धांत) बिटकॉइन को मजबूत और समृद्ध करेंगे, और इसे आकर्षक " +"और कार्यात्‍मक बनाकर इसके प्राथमिक उपयोग के मामले की सेवा करके इसे और अधिक प्रभावी ढंग से मानवता के " +"मूल्य के विकेन्द्रीकृत भंडार के रूप में सक्षम करेंगे।" + +#: src/contributing.md:1 +msgid "Contributing to `ord`" +msgstr "`ऑर्ड` में योगदान" + +#: src/contributing.md:4 +msgid "Suggested Steps" +msgstr "अनुशंसित कदम" + +#: src/contributing.md:7 +msgid "Find an issue you want to work on." +msgstr "जिस मुद्दे पर आप काम करना चाहते हैं उसका पता लगाएं" + +#: src/contributing.md:8 +msgid "" +"Figure out what would be a good first step towards resolving the issue. This " +"could be in the form of code, research, a proposal, or suggesting that it be " +"closed, if it's out of date or not a good idea in the first place." +msgstr "" +"यह जानने का पता लगाएँ कि समस्या सुलझाने की दिशा में आपका पहला बेहतर कदम क्या होगा। " +"यह कोड, शोध, एक प्रस्ताव या इसे बंद करने के सुझाव के रूप में हो सकता है, यदि यह बहुत पुराना " +"हो गया है या पहली बार अच्छे से विचार नहीं किया है।" + +#: src/contributing.md:11 +msgid "" +"Comment on the issue with an outline of your suggested first step, and " +"asking for feedback. Of course, you can dive in and start writing code or " +"tests immediately, but this avoids potentially wasted effort, if the issue " +"is out of date, not clearly specified, blocked on something else, or " +"otherwise not ready to implement." +msgstr "" +"अपने सुझाए गए पहले कदम की रूपरेखा के साथ मुद्दे पर टिप्पणी करें, और प्रतिक्रिया की मांग करें। निस्‍संदेह, " +"आप इसकी गहराई में उतरें और तुरंत कोड या परीक्षण लिखना शुरू कर सकते हैं, लेकिन यह संभावित रूप से बेकार " +"की मेहनत करने से बचना है, यदि मुद्दा बहुत पुराना है, स्पष्ट उल्‍लेख नहीं किया गया, किसी अन्‍य को अवरुद्ध किया है, " +"या अन्यथा लागू करने के लिए तैयार नहीं है।" + +#: src/contributing.md:16 +msgid "" +"If the issue requires a code change or bugfix, open a draft PR with tests, " +"and ask for feedback. This makes sure that everyone is on the same page " +"about what needs to be done, or what the first step in solving the issue " +"should be. Also, since tests are required, writing the tests first makes it " +"easy to confirm that the change can be tested easily." +msgstr "" +"यदि मुद्दे के लिए कोड में बदलाव या बगफिक्स (किसी कंप्यूटर प्रोग्राम या सिस्टम में किसी बग में सुधार) करने की " +"आवश्यकता है, तब परीक्षणों के साथ एक ड्राफ्ट पीआर खोलें और प्रतिक्रिया की मांग करें। यह सुनिश्चित करता है कि " +"मुद्दे को सुलझाने के लिए जो कुछ भी करने की आवश्यकता है उस पर सबने सहमति दे दी है। इसके अतिरिक्‍त, साथ ही, " +"चूंकि परीक्षण करने की आवश्यकता होती है, इसलिए पहले परीक्षण लिखने से यह पुष्टि करना आसान हो जाता है कि " +"परिवर्तन का आसानी से परीक्षण किया जा सकता है।" + +#: src/contributing.md:21 +msgid "" +"Mash the keyboard randomly until the tests pass, and refactor until the code " +"is ready to submit." +msgstr "" +"परीक्षण पास होने तक कीबोर्ड को बेतरतीब ढंग से मैश करें, और जब तक कोड सबमिट करने के लिए तैयार न हो जाए, " +"तब तक पुनर्संशोधित करें।" + +#: src/contributing.md:23 +msgid "Mark the PR as ready to review." +msgstr "PR (पीआर) को समीक्षा के लिए तैयार के रूप में चिह्नित करें।" + +#: src/contributing.md:24 +msgid "Revise the PR as needed." +msgstr "PR (पीआर) जरूरत के अनुसार संशोधित करें।" + +#: src/contributing.md:25 +msgid "And finally, mergies!" +msgstr "और अंत में, विलयन!" + +#: src/contributing.md:27 +msgid "Start small" +msgstr "छोटे-छोटे बदलावों से शुरूआत करें" + +#: src/contributing.md:30 +msgid "" +"Small changes will allow you to make an impact quickly, and if you take the " +"wrong tack, you won't have wasted much time." +msgstr "" +"छोटे-छोटे बदलाव करने से आपको उनका तुरन्‍त असर डालने में मदद करेगा और यदि आप गलत तरीका अपनाते हैं, " +"तो भी आपका बहुत ज्यादा समय बर्बाद नहीं होगा।" + +#: src/contributing.md:33 +msgid "Ideas for small issues:" +msgstr "छोटे मुद्दों के लिए विचार:" + +#: src/contributing.md:34 +msgid "Add a new test or test case that increases test coverage" +msgstr "एक नये परीक्षण या परीक्षण मामले को जोड़ें जो परीक्षण के कवरेज को बढ़ाता है" + +#: src/contributing.md:35 +msgid "Add or improve documentation" +msgstr "दस्तावेज़ीकरण संलग्‍न करें या सुधार करें" + +#: src/contributing.md:36 +msgid "" +"Find an issue that needs more research, and do that research and summarize " +"it in a comment" +msgstr "" +"ऐसे मुद्दे की खोज करें जिस पर अधिक शोध करने की आवश्यकता है, और वह शोध करें तथा एक टिप्पणी में " +"उसके संक्षिप्‍त विवरण प्रस्तुत करें" + +#: src/contributing.md:38 +msgid "Find an out-of-date issue and comment that it can be closed" +msgstr "किसी पुराने मुद्दे को खोजें और टिप्पणी में उल्‍लेख करें कि उसे बंद किया जा सकता है" + +#: src/contributing.md:39 +msgid "" +"Find an issue that shouldn't be done, and provide constructive feedback " +"detailing why you think that is the case" +msgstr "" +"एक ऐसे मुद्दे का पता लगाएं जिसे नहीं किया जाना चाहिए, और रचनात्मक प्रतिक्रिया प्रदान करें जिसमें उल्‍लेख " +"किया गया हो कि आप ऐसा क्यों सोचते हैं" + +#: src/contributing.md:42 +msgid "Merge early and often" +msgstr "जल्द-से-जल्‍द और बार-बार विलय करें" + +#: src/contributing.md:45 +msgid "" +"Break up large tasks into multiple smaller steps that individually make " +"progress. If there's a bug, you can open a PR that adds a failing ignored " +"test. This can be merged, and the next step can be to fix the bug and " +"unignore the test. Do research or testing, and report on your results. Break " +"a feature into small sub-features, and implement them one at a time." +msgstr "" +"बड़े कामों को छोटे-छोटे कई चरणों में बांट दें ताकि व्यक्तिगत रूप से प्रगति हो सके। यदि कोई बग से हमला हुआ है, " +"तब आप एक पीआर खोल सकते हैं जो एक असफल उपेक्षित परीक्षण को जोड़ देता है। इसे विलय किया जा सकता है, " +"और अगला कदम बग को फिक्‍स यानि सुधार करना और परीक्षण को अनदेखा नहीं करना हो सकता है। शोध या परीक्षण " +"करें, और अपने परिणामों पर सूचित करें। किसी विशेषता को छोटी-छोटी उप-विशेषताओं में तोड़ दें और उन्हें एक-एक " +"करके कार्यान्वित करें।" + +#: src/contributing.md:51 +msgid "" +"Figuring out how to break down a larger PR into smaller PRs where each can " +"be merged is an art form well-worth practicing. The hard part is that each " +"PR must itself be an improvement." +msgstr "" +"यह पता लगाएं कि एक बड़े पीआर को छोटे पीआर में कैसे तोड़ा जाए, जहां प्रत्येक का अभ्‍यास करने योग्‍य कला " +"के रूप में विलय किया जा सके। मुश्किल यह है कि प्रत्येक पीआर अपने आप में एक सुधार होना चाहिए।" + +#: src/contributing.md:55 +msgid "" +"I strive to follow this advice myself, and am always better off when I do." +msgstr "" +"मैं स्वयं इस सलाह का पालन करने का प्रयास करता हूं और जब भी मैं कुछ ऐसा करता हूं अपने आपको हमेशा " +"बेहतर स्थिति में पाता हूं।" + +#: src/contributing.md:57 +msgid "" +"Small changes are fast to write, review, and merge, which is much more fun " +"than laboring over a single giant PR that takes forever to write, review, " +"and merge. Small changes don't take much time, so if you need to stop " +"working on a small change, you won't have wasted much time as compared to a " +"larger change that represents many hours of work. Getting a PR in quickly " +"improves the project a little bit immediately, instead of having to wait a " +"long time for larger improvement. Small changes are less likely to " +"accumulate merge conflict. As the Athenians said: _The fast commit what they " +"will, the slow merge what they must._" +msgstr "" +"छोटे-छोटे बदलाव शीघ्रता के साथ लिखे, समीक्षा और विलय किए जा सकते हैं है, बहुत अधिक बड़े पीआर पर मेहनत " +"करने से ये कहीं अधिक आसान होते हैं, बड़े पीआर लिखने, समीक्षा करने और विलय करने में बहुत समय खर्च हो " +"जाता है। छोटे-छोटे बदलावों में ज्यादा समय नहीं लगता, इसलिए यदि आपको बीच में काम रोकना भी पड़ता है तो छोटे " +"बदलावों में बड़े बदलावों के मुकाबले आपका ज्यादा समय बर्बाद नहीं होगा। पीआर को तुरन्‍त प्राप्त करने के लिए परियोजना " +"में हलके सुधार, बहुत व्‍यापक सुधार के मुकाबले तुरंत पूरे हो जाते हैं। छोटे बदलावों से विलय मतभेदों के बढ़ने की संभावना " +"कम हो जाती है। जैसा कि एथेनियाईयों ने कहा है:_तेज़ लोग वही करते हैं जो वे करना चाहते हैं, धीमे लोग जो " +"करना चाहते हैं उसे पूरा कर लेते हैं।_" + +#: src/contributing.md:67 +msgid "Get help" +msgstr "सहायता की मांग करें" + +#: src/contributing.md:70 +msgid "" +"If you're stuck for more than 15 minutes, ask for help, like a Rust Discord, " +"Stack Exchange, or in a project issue or discussion." +msgstr "" +"यदि आप 15 मिनट से अधिक समय तक रस्ट डिस्कॉर्ड, स्टैक एक्सचेंज, या किसी परियोजना के मुद्दे या चर्चा " +"संबंधी किसी मामले में फंस जाते हैं, तो किसी से मदद की मांग करें।" + +#: src/contributing.md:73 +msgid "Practice hypothesis-driven debugging" +msgstr "परिकल्पना-चालित डिबगिंग का अभ्यास करें" + +#: src/contributing.md:76 +msgid "" +"Formulate a hypothesis as to what is causing the problem. Figure out how to " +"test that hypothesis. Perform that tests. If it works, great, you fixed the " +"issue or now you know how to fix the issue. If not, repeat with a new " +"hypothesis." +msgstr "" +"समस्या के पीछे के कारण के बारे में परिकल्पना करें। यह पता लगाने का प्रयास करें कि उस परिकल्पना का " +"परीक्षण कैसे किया जाए। परीक्षण को अंजाम दें। यदि यह ठीक से काम करता है, तो बहुत बढ़िया है, आपने " +"समस्या दुरूस्‍त कर दी है या अब आप जान गये हैं कि समस्या को कैसे दुरूस्‍त किया जाए। यदि ऐसा कुछ भी " +"नहीं हुआ है, तो एक नई परिकल्पना करके फिर से यही प्रक्रिया दोहराएँ।" + +#: src/contributing.md:81 +msgid "Pay attention to error messages" +msgstr "त्रुटि संदेशों पर ध्यान दें" + +#: src/contributing.md:84 +msgid "Read all error messages and don't tolerate warnings." +msgstr "सभी त्रुटि संदेशों को ध्‍यान से पढ़ें और चेतावनियाँ को नजरअंदाज मत करें।" + +#: src/donate.md:4 +msgid "" +"Ordinals is open-source and community funded. The current lead maintainer of " +"`ord` is [raphjaph](https://github.com/raphjaph/). Raph's work on `ord` is " +"entirely funded by donations. If you can, please consider donating!" +msgstr "" +"ऑर्डिनल्स (क्रमसूचक) ओपन-सोर्स (मुक्‍त-स्रोत) है और समुदाय द्वारा वित्त पोषित किया जाता है। `ऑर्ड` " +"(क्रमसूचक) का वर्तमान प्रमुख अनुरक्षक [raphjaph](https://github.com/raphjaph/) है। आर्डिनल्‍स " +"पर raph का काम पूरी तरह से दान द्वारा वित्त पोषित होता है। यदि आप भी दान देना चाहते हैं, " +"तब विलंब मत करें, कृपया तुरन्‍त दान देने पर विचार करें!" + +#: src/donate.md:8 +msgid "" +"The donation address for Bitcoin is " +"[bc1q8kt9pyd6r27k2840l8g5d7zshz3cg9v6rfda0m248lva3ve5072q3sxelt](https://" +"mempool.space/address/" +"bc1q8kt9pyd6r27k2840l8g5d7zshz3cg9v6rfda0m248lva3ve5072q3sxelt). The " +"donation address for inscriptions is " +"[bc1qn3map8m9hmk5jyqdkkwlwvt335g94zvxwd9aql7q3vdkdw9r5eyqvlvec0](https://" +"mempool.space/address/" +"bc1qn3map8m9hmk5jyqdkkwlwvt335g94zvxwd9aql7q3vdkdw9r5eyqvlvec0)." +msgstr "" +"बिटकॉइन के लिए दान का पता है " +"[bc1q8kt9pyd6r27k2840l8g5d7zshz3cg9v6rfda0m248lva3ve5072q3sxelt](https://" +"mempool.space/address/" +"bc1q8kt9pyd6r27k2840l8g5d7zshz3cg9v6rfda0m248lva3ve5072q3sxelt). " +"डिजिटल अभिलेखों के लिए दान का पता है " +"[bc1qn3map8m9hmk5jyqdkkwlwvt335g94zvxwd9aql7q3vdkdw9r5eyqvlvec0]" +"(https://mempool.space/address/" +"bc1qn3map8m9hmk5jyqdkkwlwvt335g94zvxwd9aql7q3vdkdw9r5eyqvlvec0)." + +#: src/donate.md:11 +msgid "" +"Both addresses are in a 2 of 4 multisig wallet with keys held by [raphjaph]" +"(https://twitter.com/raphjaph), [erin](https://twitter.com/realizingerin), " +"[rodarmor](https://twitter.com/rodarmor), and [ordinally](https://twitter." +"com/veryordinally)." +msgstr "" +"दोनों पते 4 में से 2 मल्टीसिग वॉलेट में हैं जिनकी कुंजियां [raphjaph](https://twitter.com/raphjaph), " +"[erin](https://twitter.com/realizingerin), [rodarmor](https://twitter.com/rodarmor), " +"और [ordinally](https://twitter.com/veryordinally) से रखी गई हैं।" + +#: src/donate.md:17 +msgid "" +"Donations received will go towards funding maintenance and development of " +"`ord`, as well as hosting costs for [ordinals.com](https://ordinals.com)." +msgstr "" +"प्राप्त किए गये दान का उपयोग `ऑर्डिनल्स` (क्रमसूचक) के रखरखाव और विकास के वित्त-पोषण के साथ-साथ " +"[ordinals.com](https://ordinals.com) की होस्टिंग लागत में किया जाएगा।" + +#: src/donate.md:20 +msgid "Thank you for donating!" +msgstr "दान देने के लिए आपका आभार!" + +#: src/guides.md:1 +msgid "Ordinal Theory Guides" +msgstr "ऑर्डिनल्स थ्‍यौरी के मार्गदर्शक निर्देश" + +#: src/guides.md:4 +msgid "" +"See the table of contents for a list of guides, including a guide to the " +"explorer, a guide for sat hunters, and a guide to inscriptions." +msgstr "" +"मार्गदर्शक निर्देशों की सूची के लिए विषय-वस्‍तु में दी गई तालिका देखें, जिसमें अन्वेषक और अभिलेखों के " +"लिए मार्गदर्शक निर्देश शामिल हैं।" + +#: src/guides/explorer.md:1 +msgid "Ordinal Explorer" +msgstr "ऑर्डिनल्स एक्सप्लोरर" + +#: src/guides/explorer.md:4 +msgid "" +"The `ord` binary includes a block explorer. We host a instance of the block " +"explorer on mainnet at [ordinals.com](https://ordinals.com), and on signet " +"at [signet.ordinals.com](https://signet.ordinals.com)." +msgstr "" +"`ऑर्ड` बाइनरी में एक ब्‍लॉक एक्‍सप्‍लोरर शामिल हैं। हम ब्लॉक एक्सप्लोरर के उदाहरण मेननेट के " +"[ordinals.com](https://ordinals.com), और [signet.ordinals.com]" +"(https://signet.ordinals.com) पर होस्ट करते हैं।" + +#: src/guides/explorer.md:8 +msgid "Running The Explorer" +msgstr "एक्सप्लोरर संचालन" + +#: src/guides/explorer.md:9 +msgid "The server can be run locally with:" +msgstr "सर्वर स्थानीय रूप से निम्‍न के साथ चलाया जा सकता है:" + +#: src/guides/explorer.md:11 +msgid "`ord server`" +msgstr "`ऑर्ड सर्वर`" + +#: src/guides/explorer.md:13 +msgid "To specify a port add the `--http-port` flag:" +msgstr "पोर्ट निर्दिष्ट करने के लिए `--http-port` फ़्लैग टाइप करें:" + +#: src/guides/explorer.md:15 +msgid "`ord server --http-port 8080`" +msgstr "ऑर्ड सर्वर --http-port 8080`" + +#: src/guides/explorer.md:17 +msgid "To test how your inscriptions will look you can run:" +msgstr "आपके डिजिटल अभिलेख कैसे दिखेंगे, यह जांचने के लिए कि आप निम्‍न संचालित कर सकते हैं:" + +#: src/guides/explorer.md:19 +msgid "`ord preview ...`" +msgstr "ऑर्ड प्रिव्‍यु ..." + +#: src/guides/explorer.md:21 +msgid "Search" +msgstr "सर्च (तलाश करें)" + +#: src/guides/explorer.md:24 +msgid "The search box accepts a variety of object representations." +msgstr "सर्च बॉक्स विभिन्न प्रकार के ऑब्जेक्ट अभ्यावेदन स्वीकार करता है।" + +#: src/guides/explorer.md:26 +msgid "Blocks" +msgstr "ब्लॉक्‍स" + +#: src/guides/explorer.md:28 +msgid "Blocks can be searched by hash, for example, the genesis block:" +msgstr "ब्लॉक्‍स हैश के माध्‍यम से सर्च किए जा सकता हैं, इसका उदाहरण, जेनेसिस ब्लॉक है:" + +#: src/guides/explorer.md:30 +msgid "" +"[000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f](https://" +"ordinals.com/" +"search/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f)" +msgstr "" + +#: src/guides/explorer.md:32 +msgid "Transactions" +msgstr "लेनदेन" + +#: src/guides/explorer.md:34 +msgid "" +"Transactions can be searched by hash, for example, the genesis block " +"coinbase transaction:" +msgstr "" +"लेनदेन हैश द्वारा सर्च किए जा सकते हैं, उदाहरण के लिए, जेनेसिस ब्लॉक कॉइनबेस लेनदेन:" + +#: src/guides/explorer.md:37 +msgid "" +"[4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b](https://" +"ordinals.com/" +"search/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b)" +msgstr "" + +#: src/guides/explorer.md:39 +msgid "Outputs" +msgstr "आउटपुट" + +#: src/guides/explorer.md:41 +msgid "" +"Transaction outputs can searched by outpoint, for example, the only output " +"of the genesis block coinbase transaction:" +msgstr "" +"लेनदेन आउटपुट आउटपॉइंट द्वारा तलाशी जा सकती है, उदाहरण के लिए, जेनेसिस ब्लॉक कॉइनबेस लेनदेन " +"की एकमात्र आउटपुट:" + +#: src/guides/explorer.md:44 +msgid "" +"[4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0](https://" +"ordinals.com/" +"search/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0)" +msgstr "" + +#: src/guides/explorer.md:46 +msgid "Sats" +msgstr "सैट्स" + +#: src/guides/explorer.md:48 +msgid "" +"Sats can be searched by integer, their position within the entire bitcoin " +"supply:" +msgstr "" +"सैट्स इंटेगर (पूर्णांक) द्वारा खोजे जा सकते हैं, संपूर्ण बिटकॉइन आपूर्ति के भीतर उनकी स्थिति में:" + +#: src/guides/explorer.md:51 +msgid "[2099994106992659](https://ordinals.com/search/2099994106992659)" +msgstr "" + +#: src/guides/explorer.md:53 +msgid "By decimal, their block and offset within that block:" +msgstr "दशमलव द्वारा द्वारा खोजे जा सकते हैं, उनके ब्लॉक और उस ब्लॉक के भीतर ऑफसेट (प्रतिसंतुलित) कर:" + +#: src/guides/explorer.md:55 +msgid "[481824.0](https://ordinals.com/search/481824.0)" +msgstr "" + +#: src/guides/explorer.md:57 +msgid "" +"By degree, their cycle, blocks since the last halving, blocks since the last " +"difficulty adjustment, and offset within their block:" +msgstr "" +"डिग्री, उसके चक्र, अंतिम कठिन समायोजन के बाद से अंतिम पड़ाव के बाद ब्लॉक द्वारा, और उनके ब्लॉक के " +"भीतर ऑफसेट (प्रतिसंतुलित) कर:" + +#: src/guides/explorer.md:60 +msgid "[1°0′0″0‴](https://ordinals.com/search/1°0′0″0‴)" +msgstr "" + +#: src/guides/explorer.md:62 +msgid "" +"By name, their base 26 representation using the letters \"a\" through \"z\":" +msgstr "नाम द्वारा, \"a\" से \"z\" उनके मूल 26 अक्षरों के प्रतिनिधित्व का उपयोग करके:" + +#: src/guides/explorer.md:64 +msgid "[ahistorical](https://ordinals.com/search/ahistorical)" +msgstr "[अनैतिहासिक](https://ordinals.com/search/ahistorical)" + +#: src/guides/explorer.md:66 +msgid "" +"Or by percentile, the percentage of bitcoin's supply that has been or will " +"have been issued when they are mined:" +msgstr "" +"या प्रतिशतक द्वारा, बिटकॉइन खनन के समय जारी किये गये या जारी की जाने वाली बिटकॉइन की आपूर्ति के " +"अनुरूप की जाएगी:" + +#: src/guides/explorer.md:69 +msgid "[100%](https://ordinals.com/search/100%)" +msgstr "" + +#: src/guides/inscriptions.md:1 +msgid "Ordinal Inscription Guide" +msgstr "ऑर्डिनल्स्‍स इंस्‍क्रि‍प्‍शन मार्गदर्शक निर्देश" + +#: src/guides/inscriptions.md:4 +msgid "" +"Individual sats can be inscribed with arbitrary content, creating Bitcoin-" +"native digital artifacts that can be held in a Bitcoin wallet and " +"transferred using Bitcoin transactions. Inscriptions are as durable, " +"immutable, secure, and decentralized as Bitcoin itself." +msgstr "" +"व्‍यक्तिगत सैट्स को स्‍वेच्छित विषय-वस्‍तु के साथ उत्‍कीर्ण किया जा सकता है, जो बिटकॉइन-मूल डिजिटल " +"अभिलेखों का सृजन किया जा सकता है जिन्हें बिटकॉइन वॉलेट में सहेजा जा सकता है और बिटकॉइन लेनदेन " +"करके स्थानांतरित किया जा सकता है। ये डिजिटल अभिलेख भी बिटकॉइन की तरह ही टिकाऊ, अपरिवर्तनीय, " +"सुरक्षित और विकेंद्रीकृत हैं।" + +#: src/guides/inscriptions.md:9 +msgid "" +"Working with inscriptions requires a Bitcoin full node, to give you a view " +"of the current state of the Bitcoin blockchain, and a wallet that can create " +"inscriptions and perform sat control when constructing transactions to send " +"inscriptions to another wallet." +msgstr "" +"डिजिटल अभिलेखों का प्रयोग करने के लिए आपको बिटकॉइन ब्लॉकचेन की वर्तमान स्थिति दर्शाने के लिए " +"एक बिटकॉइन पूर्ण नोड की आवश्यकता होती है। इसके अतिरिक्‍त, वॉलेट जो डिजिटल अभिलेखों का सृजन " +"कर सकता है और दूसरे वॉलेट में डिजिटल अभिलेखों को प्रेषित करने के लिए लेनदेन के दौरान सैट नियंत्रि‍त कर " +"सकता है।" + +#: src/guides/inscriptions.md:14 +msgid "" +"Bitcoin Core provides both a Bitcoin full node and wallet. However, the " +"Bitcoin Core wallet cannot create inscriptions and does not perform sat " +"control." +msgstr "" +"बिटकॉइन कोर में बिटकॉइन पूर्ण नोड और वॉलेट दोनों प्रदान किए जाते हैं। हालाँकि, बिटकॉइन कोर " +"वॉलेट डिजिटल अभिलेखों के सृजन नहीं कर सकते और न ही सैट नियंत्रण निष्‍पादित करते हैं।" + +#: src/guides/inscriptions.md:17 +msgid "" +"This requires [`ord`](https://github.com/ordinals/ord), the ordinal utility. " +"`ord` doesn't implement its own wallet, so `ord wallet` subcommands interact " +"with Bitcoin Core wallets." +msgstr "" +"इसके लिए [`ऑर्ड`](https://github.com/ordinals/ord), यूटिलिटी की आवश्यकता होती है। " +"`ऑर्ड` अपने स्वयं के वॉलेट अमल में नहीं लाते हैं, इसीलिए `ऑर्ड वॉलेट` के उप-अनुदेश बिटकॉइन कोर वॉलेट के " +"साथ समन्‍वय करते हैं।" + +#: src/guides/inscriptions.md:21 +msgid "This guide covers:" +msgstr "इस मार्गदर्शक निर्देशों में निम्‍नलिखित शामिल हैं:" + +#: src/guides/inscriptions.md:23 src/guides/inscriptions.md:39 +msgid "Installing Bitcoin Core" +msgstr "बिटकॉइन कोर इंस्‍टाल करना" + +#: src/guides/inscriptions.md:24 +msgid "Syncing the Bitcoin blockchain" +msgstr "बिटकॉइन ब्लॉकचेन सिंक करना" + +#: src/guides/inscriptions.md:25 +msgid "Creating a Bitcoin Core wallet" +msgstr "बिटकॉइन कोर वॉलेट का सृजन करना" + +#: src/guides/inscriptions.md:26 +msgid "Using `ord wallet receive` to receive sats" +msgstr " सैट प्राप्त करने के लिए `ord wallet receive` का उपयोग करना" + +#: src/guides/inscriptions.md:27 +msgid "Creating inscriptions with `ord wallet inscribe`" +msgstr "`ord wallet inscribe` के साथ डिजिटल अभिलेख बनाना" + +#: src/guides/inscriptions.md:28 +msgid "Sending inscriptions with `ord wallet send`" +msgstr "`ord wallet send` के साथ डिजिटल अभिलेख भेजना" + +#: src/guides/inscriptions.md:29 +msgid "Receiving inscriptions with `ord wallet receive`" +msgstr "`ord wallet receive` के साथ डिजिटल अभिलेख प्राप्त करना" + +#: src/guides/inscriptions.md:31 +msgid "Getting Help" +msgstr "मदद प्राप्त करें" + +#: src/guides/inscriptions.md:34 +msgid "" +"If you get stuck, try asking for help on the [Ordinals Discord Server]" +"(https://discord.com/invite/87cjuz4FYg), or checking GitHub for relevant " +"[issues](https://github.com/ordinals/ord/issues) and [discussions](https://" +"github.com/ordinals/ord/discussions)." +msgstr "" +"यदि आप कहीं फंस जाते हैं, तब आप [Ordinals Discord Server]" +"(https://discord.com/invite/87cjuz4FYg), पर मदद के लिए संपर्क करने का प्रयास करें, " +"या प्रासंगिक [मुद्दों](https://github.com/ordinals/ord/issues) और [चर्चाओं](https://" +"github.com/ordinals/ord/discussions) के लिए GitHub पर संबंधित अवरोध के बारे में पता लगाएं।" + +#: src/guides/inscriptions.md:42 +msgid "" +"Bitcoin Core is available from [bitcoincore.org](https://bitcoincore.org/) " +"on the [download page](https://bitcoincore.org/en/download/)." +msgstr "" +"बिटकॉइन कोर [bitcoincore.org](https://bitcoincore.org/) के डाउनलोड पृष्‍ठ (https://" +"bitcoincore.org/en/download/) पर उपलब्ध हैं।" + +#: src/guides/inscriptions.md:45 +msgid "Making inscriptions requires Bitcoin Core 24 or newer." +msgstr "डिजिटल अभिलेख बनाने के लिए बिटकॉइन कोर 24 या उसका नया संस्‍करण आवश्यक है।" + +#: src/guides/inscriptions.md:47 +msgid "" +"This guide does not cover installing Bitcoin Core in detail. Once Bitcoin " +"Core is installed, you should be able to run `bitcoind -version` " +"successfully from the command line." +msgstr "" +"यह मार्गदर्शक निर्देश बिटकॉइन कोर इंस्‍टाल करने के विस्तृत विवरण समावेश नहीं करते। एक बार जब " +"बिटकॉइन कोर इंस्‍टाल हो जाता है, आप कमांड लाइन से bitcoind-संस्‍करण को सफलतापूर्वक संचालित " +"करने में सक्षम हो जाएंगे।" + +#: src/guides/inscriptions.md:51 +msgid "Configuring Bitcoin Core" +msgstr "बिटकॉइन कोर कॉन्फ़िगर (समरूप) करना" + +#: src/guides/inscriptions.md:54 +msgid "`ord` requires Bitcoin Core's transaction index." +msgstr "`ऑर्ड` को बिटकॉइन कोर लेनदेन सूचकांक की आवश्यकता होती है।" + +#: src/guides/inscriptions.md:56 +msgid "" +"To configure your Bitcoin Core node to maintain a transaction index, add the " +"following to your `bitcoin.conf`:" +msgstr "" +"लेन-देन सूचकांक के अनुरक्षण के लिए अपने बिटकॉइन कोर नोड को कॉन्फ़िगर करने के लिए, निम्नलिखित को " +"अपने `bitcoin.conf` में जोड़ें:" + +#: src/guides/inscriptions.md:59 src/guides/sat-hunting.md:30 +msgid "" +"```\n" +"txindex=1\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:63 +msgid "Or, run `bitcoind` with `-txindex`:" +msgstr "या, `bitcoind` के साथ `-txindex` बिटकॉइन संचालित करें:" + +#: src/guides/inscriptions.md:65 src/guides/inscriptions.md:74 +msgid "" +"```\n" +"bitcoind -txindex\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:69 +msgid "Syncing the Bitcoin Blockchain" +msgstr "बिटकॉइन ब्लॉकचेन सिंक करना" + +#: src/guides/inscriptions.md:72 +msgid "To sync the chain, run:" +msgstr "चेन सिंक करने के लिए, निम्‍नलिखित संचालित करें:" + +#: src/guides/inscriptions.md:78 +msgid "…and leave it running until `getblockcount`:" +msgstr "…और `getblockcount` तक इसे चालू रहने दें:" + +#: src/guides/inscriptions.md:80 +msgid "" +"```\n" +"bitcoin-cli getblockcount\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:84 +msgid "" +"agrees with the block count on a block explorer like [the mempool.space " +"block explorer](https://mempool.space/). `ord` interacts with `bitcoind`, so " +"you should leave `bitcoind` running in the background when you're using " +"`ord`." +msgstr "" +"[the mempool.space block explorer](https://mempool.space/) " +"ब्लॉक एक्सप्लोरर जैसे ब्लॉक एक्सप्लोरर पर ब्लॉक गणना से सहमत है। `ऑर्ड` `bitcoind` " +"के साथ समन्‍वय करता है, इसलिए जब आप ऑर्ड का उपयोग कर रहे हों तो आपको `bitcoind` " +"को पृष्ठभूमि में चालू रहने देना चाहिए।" + +#: src/guides/inscriptions.md:88 +msgid "Installing `ord`" +msgstr "`ऑर्ड` इंस्‍टाल करना" + +#: src/guides/inscriptions.md:91 +msgid "" +"The `ord` utility is written in Rust and can be built from [source](https://" +"github.com/ordinals/ord). Pre-built binaries are available on the [releases " +"page](https://github.com/ordinals/ord/releases)." +msgstr "" +"`ऑर्ड` यूटिलिटी रस्ट में लिखी जाती है और इसे [सोर्स](https://github.com/ordinals/ord) " +"से बनाया जा सकता है। पूर्व-निर्मित बाइनेरी रिलीज़ पृष्ठ [releases " +"page](https://github.com/ordinals/ord/releases) पर उपलब्ध हैं।" + + +#: src/guides/inscriptions.md:95 +msgid "You can install the latest pre-built binary from the command line with:" +msgstr "" +"आप निम्‍न के साथ कमांड लाइन से नवीनतम पूर्व-निर्मित बाइनरी इंस्‍टाल कर सकते हैं:" + +#: src/guides/inscriptions.md:97 +msgid "" +"```sh\n" +"curl --proto '=https' --tlsv1.2 -fsLS https://ordinals.com/install.sh | bash " +"-s\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:101 +msgid "Once `ord` is installed, you should be able to run:" +msgstr "एक बार `ऑर्ड` इंस्‍टाल होने पर, आप उसे संचालित करने में सक्षम हो जाएंगे:" + +#: src/guides/inscriptions.md:103 +msgid "" +"```\n" +"ord --version\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:107 +msgid "Which prints out `ord`'s version number." +msgstr "जिसमें `ऑर्ड`—संस्करण नंबर प्रिंट होता है।" + +#: src/guides/inscriptions.md:109 +msgid "Creating a Bitcoin Core Wallet" +msgstr "बिटकॉइन कोर वॉलेट का सृजन करें" + +#: src/guides/inscriptions.md:112 +msgid "" +"`ord` uses Bitcoin Core to manage private keys, sign transactions, and " +"broadcast transactions to the Bitcoin network." +msgstr "" +"`ऑर्ड` निजी कुंजी संचालित करने, लेनदेन पर हस्ताक्षर करने और बिटकॉइन नेटवर्क पर लेनदेन प्रसारित करने के " +"लिए बिटकॉइन कोर का उपयोग करता है।" + +#: src/guides/inscriptions.md:115 +msgid "To create a Bitcoin Core wallet named `ord` for use with `ord`, run:" +msgstr "`ऑर्ड` के साथ उपयोग के लिए ऑर्ड नामक बिटकॉइन कोर वॉलेट का सृजन करने के लिए, निम्‍न संचालित करें:" + +#: src/guides/inscriptions.md:117 +msgid "" +"```\n" +"ord wallet create\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:121 +msgid "Receiving Sats" +msgstr "सैट्स प्राप्त करें" + +#: src/guides/inscriptions.md:124 +msgid "" +"Inscriptions are made on individual sats, using normal Bitcoin transactions " +"that pay fees in sats, so your wallet will need some sats." +msgstr "" +"इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) सामान्य बिटकॉइन लेनदेन का उपयोग करके अलग-अलग सैट्स पर बनाए " +"जाते हैं, जो सैट्स में शुल्कों का भुगतान करते हैं, इसलिए आपके वॉलेट में कुछ सैट्स का होना जरूरी है।" + +#: src/guides/inscriptions.md:127 +msgid "Get a new address from your `ord` wallet by running:" +msgstr "अपने `ऑर्ड` वॉलेट से निम्‍नलिखत चलाकर नया पता प्राप्त करें:" + +#: src/guides/inscriptions.md:129 src/guides/inscriptions.md:201 +#: src/guides/inscriptions.md:229 +msgid "" +"```\n" +"ord wallet receive\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:133 +msgid "And send it some funds." +msgstr "और इसमें कुछ धनराशि भेजें" + +#: src/guides/inscriptions.md:135 +msgid "You can see pending transactions with:" +msgstr "आप निम्‍न के साथ लंबित लेनदेन देख सकते हैं:" + +#: src/guides/inscriptions.md:137 src/guides/inscriptions.md:213 +#: src/guides/inscriptions.md:240 +msgid "" +"```\n" +"ord wallet transactions\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:141 +msgid "" +"Once the transaction confirms, you should be able to see the transactions " +"outputs with `ord wallet outputs`." +msgstr "" +"एक बार जब लेन-देन की पुष्टि हो जाती है, आप `ord wallet outputs` के साथ लेन-देन आउटपुट देखने " +"में सक्षम होंगे।" + +#: src/guides/inscriptions.md:144 +msgid "Creating Inscription Content" +msgstr "इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) विषय-वस्‍तु का सृजन" + +#: src/guides/inscriptions.md:147 +msgid "" +"Sats can be inscribed with any kind of content, but the `ord` wallet only " +"supports content types that can be displayed by the `ord` block explorer." +msgstr "" +"सैट्स को किसी भी प्रकार की विषय-वस्‍तु के साथ उत्‍कीर्ण किया जा सकता है, लेकिन ऑर्ड वॉलेट केवल उन " +"विषय-वस्‍तु के प्रकारों का समर्थन करता है जिन्हें ऑर्ड ब्लॉक एक्सप्लोरर द्वारा प्रदर्शित किया जा सकता है।" + +#: src/guides/inscriptions.md:150 +msgid "" +"Additionally, inscriptions are included in transactions, so the larger the " +"content, the higher the fee that the inscription transaction must pay." +msgstr "" +"इसके अतिरिक्त, डिजिटल अभिलेख लेनदेनों में शामिल होते हैं, इसलिए विषय-वस्‍तु जितनी विशाल होगी," +"डिजिटल अभिलेख लेनदेन के लिए उतने अधिक शुल्क का भुगतान करना होगा।" + +#: src/guides/inscriptions.md:153 +msgid "" +"Inscription content is included in transaction witnesses, which receive the " +"witness discount. To calculate the approximate fee that an inscribe " +"transaction will pay, divide the content size by four and multiply by the " +"fee rate." +msgstr "" +"डिजिटल अभिलेख विषय-वस्‍तु लेनदेन के साक्ष्‍यों में शामिल होते हैं, जिसमें साक्ष्‍य छूट प्राप्त होती हैं। डिजिटल " +"अभिलेख द्वारा लेनदेन के भुगतान की अनुमानित शुल्क की गणना करने के लिए, विषय-वस्‍तु के आकार को चार " +"से विभाजित करने के बाद उसे शुल्क दर से गुणा कर दें।" + +#: src/guides/inscriptions.md:157 +msgid "" +"Inscription transactions must be less than 400,000 weight units, or they " +"will not be relayed by Bitcoin Core. One byte of inscription content costs " +"one weight unit. Since an inscription transaction includes not just the " +"inscription content, limit inscription content to less than 400,000 weight " +"units. 390,000 weight units should be safe." +msgstr "" +"डिजिटल अभिलेख लेनदेन 400,000 भार इकाइयों से कम होने चाहिए, अन्यथा उन्हें बिटकॉइन कोर द्वारा आगे " +"प्रसारित नहीं किया जाएगा। डिजिटल अभिलेख विषय-वस्‍तु के एक बाइट की लागत एक भार इकाई होती है। " +"चूंकि एक डिजिटल अभिलेख लेनदेन में केवल डिजिटल अभिलेख विषय-वस्‍तु ही शामिल नहीं होती है, डिजिटल " +"अभिलेख विषय-वस्‍तु को 400,000 वजन इकाइयों से कम तक सीमित करें। 390,000 भार इकाइयाँ सुरक्षित " +"होंगी।" + +#: src/guides/inscriptions.md:163 +msgid "Creating Inscriptions" +msgstr "इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) का सृजन" + +#: src/guides/inscriptions.md:166 +msgid "To create an inscription with the contents of `FILE`, run:" +msgstr "`FILE` (फ़ाइल) की विषय-वस्‍तु के साथ एक डिजिटल अभिलेख का सृजन करने के लिए, " +"निम्‍नलिखित संचालित करें:" + +#: src/guides/inscriptions.md:168 +msgid "" +"```\n" +"ord wallet inscribe --fee-rate FEE_RATE FILE\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:172 +msgid "" +"Ord will output two transactions IDs, one for the commit transaction, and " +"one for the reveal transaction, and the inscription ID. Inscription IDs are " +"of the form `TXIDiN`, where `TXID` is the transaction ID of the reveal " +"transaction, and `N` is the index of the inscription in the reveal " +"transaction." +msgstr "" +"ऑर्ड दो लेनदेन आईडी आउटपुट प्रदान करेगा, एक प्रतिबद्ध लेनदेन के लिए, और दूसरी प्रकट लेनदेन, और " +"डिजिटल अभिलेख आईडी के लिए। डिजिटल अभिलेख आईडी `TXIDiN` के रूप में है, जिसमें `TXID` प्रकट " +"लेनदेन की लेनदेन आईडी है, और `N` प्रकट लेनदेन में डिजिटल अभिलेख का सूचकांक है।" + +#: src/guides/inscriptions.md:177 +msgid "" +"The commit transaction commits to a tapscript containing the content of the " +"inscription, and the reveal transaction spends from that tapscript, " +"revealing the content on chain and inscribing it on the first sat of the " +"input that contains the corresponding tapscript." +msgstr "" +"प्रतिबद्ध लेनदेन एक टेपस्क्रिप्ट के लिए प्रतिबद्ध होता है जिसमें डिजिटल अभिलेख की विषय-वस्‍तु निहित होती " +"है, और प्रकट लेनदेन उस टेपस्क्रिप्ट से खर्च होता है, चेन पर विषय-वस्‍तु को प्रकट करता है और इसे इनपुट के " +"पहले सेट पर अंकित करता है जिसमें संबंधित टेपस्क्रिप्ट शामिल होती है।" + +#: src/guides/inscriptions.md:182 +msgid "" +"Wait for the reveal transaction to be mined. You can check the status of the " +"commit and reveal transactions using [the mempool.space block explorer]" +"(https://mempool.space/)." +msgstr "" +"प्रकट लेन-देन के खनन होने की प्रतीक्षा करें। आप [the mempool.space block explorer]" +"(https://mempool.space/) का उपयोग करके प्रतिबद्धता स्थिति की जांच और लेनदेन का खुलासा कर " +"सकते हैं।" + +#: src/guides/inscriptions.md:186 +msgid "" +"Once the reveal transaction has been mined, the inscription ID should be " +"printed when you run:" +msgstr "" +"एक बार प्रकट लेनदेन खनन हो जाने के बाद, जब आप अग्रसर होते हैं तो डिजिटल अभिलेख आईडी मुद्रित " +"होनी चाहिए:" + +#: src/guides/inscriptions.md:189 src/guides/inscriptions.md:220 +#: src/guides/inscriptions.md:246 +msgid "" +"```\n" +"ord wallet inscriptions\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:193 +msgid "" +"And when you visit [the ordinals explorer](https://ordinals.com/) at " +"`ordinals.com/inscription/INSCRIPTION_ID`." +msgstr "" +"और जब आप [the ordinals explorer](https://ordinals.com/) पर " +"`ordinals.com/inscription/INSCRIPTION_ID` देखते हैं।" + +#: src/guides/inscriptions.md:196 +msgid "Sending Inscriptions" +msgstr "इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्रेषण" + +#: src/guides/inscriptions.md:199 +msgid "Ask the recipient to generate a new address by running:" +msgstr "प्राप्तकर्ता को निम्न संचालित कर एक नये पते का सृजन करने के लिए कहें:" + +#: src/guides/inscriptions.md:205 +msgid "Send the inscription by running:" +msgstr "संचालित कर इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्रेषित करें:" + +#: src/guides/inscriptions.md:207 +msgid "" +"```\n" +"ord wallet send --fee-rate
\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:211 src/guides/inscriptions.md:239 +msgid "See the pending transaction with:" +msgstr "निम्‍न के साथ लंबित लेनदेन देखें:" + +#: src/guides/inscriptions.md:217 +msgid "" +"Once the send transaction confirms, the recipient can confirm receipt by " +"running:" +msgstr "" +"एक बार प्रेषित लेनदेन की पुष्टि हो जाने पर, प्राप्तकर्ता निम्नलिखित चलाकर रसीद की पुष्टि कर सकता है:" + +#: src/guides/inscriptions.md:224 +msgid "Receiving Inscriptions" +msgstr "इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्राप्त करना" + +#: src/guides/inscriptions.md:227 +msgid "Generate a new receive address using:" +msgstr "इसका उपयोग करके एक नया प्राप्त पता उत्पन्न करें:" + +#: src/guides/inscriptions.md:233 +msgid "The sender can transfer the inscription to your address using:" +msgstr "प्रेषक निम्नलिखित का उपयोग करके इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) आपके पते पर स्थानांतरित कर सकता है:" + +#: src/guides/inscriptions.md:235 +msgid "" +"```\n" +"ord wallet send ADDRESS INSCRIPTION_ID\n" +"```" +msgstr "" + +#: src/guides/inscriptions.md:244 +msgid "" +"Once the send transaction confirms, you can can confirm receipt by running:" +msgstr "" +"एक बार प्रेषण लेनदेन की पुष्टि हो जाने पर, आप निम्न चलाकर रसीद की पुष्टि कर सकते हैं:" + +#: src/guides/sat-hunting.md:4 +msgid "" +"_This guide is out of date. Since it was written, the `ord` binary was " +"changed to only build the full satoshi index when the `--index-sats` flag is " +"supplied. Additionally, `ord` now has a built-in wallet that wraps a Bitcoin " +"Core wallet. See `ord wallet --help`._" +msgstr "" +"_यह मार्गदर्शिका पुरानी हो गई है। जब से इसे लिखा गया है, `ऑर्ड` बाइनरी को `--index-sats` फ्लैग आपूर्ति " +"करने के बाद पूर्ण सातोशी सूचकांक बनाने के लिए बदल दिया गया था। इसके अतिरिक्त, ऑर्ड में अब एक अंतरंग " +"वॉलेट है जो बिटकॉइन कोर वॉलेट को सम्मिलित करता है। `ord wallet –help` पर देखें।" + +#: src/guides/sat-hunting.md:9 +msgid "" +"Ordinal hunting is difficult but rewarding. The feeling of owning a wallet " +"full of UTXOs, redolent with the scent of rare and exotic sats, is beyond " +"compare." +msgstr "" +"ऑर्डिनल हंटिंग कठिन जरूर है लेकिन बहुत लाभदायक है। यूटीएक्सओ से युक्‍त वॉलेट के मालिक बनने का एहसास, " +"सैट की आकर्षकता और दुर्लभता का सूचक है, जो अतुलनीय है।" + +#: src/guides/sat-hunting.md:12 +msgid "" +"Ordinals are numbers for satoshis. Every satoshi has an ordinal number and " +"every ordinal number has a satoshi." +msgstr "" +"ऑर्डिनल्स सातोशी के लिए संख्याएँ हैं। प्रत्येक सातोशी में क्रमसूचक संख्या होती है और प्रत्येक क्रमसूचक " +"संख्या की एक सातोशी होती है।" + +#: src/guides/sat-hunting.md:15 +msgid "Preparation" +msgstr "तैयारी करना" + +#: src/guides/sat-hunting.md:18 +msgid "There are a few things you'll need before you start." +msgstr "आरंभ करने से पहले आपको कुछ कार्य करने की आवश्यकता होगी।" + +#: src/guides/sat-hunting.md:20 +msgid "" +"First, you'll need a synced Bitcoin Core node with a transaction index. To " +"turn on transaction indexing, pass `-txindex` on the command-line:" +msgstr "" +"सबसे पहले, आपको लेनदेन सूचकांक के साथ सिंक किए बिटकॉइन कोर नोड की आवश्यकता होगी। " +"लेन-देन सूचकांक सक्रिय करने के लिए, कमांड-लाइन पर `-txindex` पास करें:" + +#: src/guides/sat-hunting.md:23 +msgid "" +"```sh\n" +"bitcoind -txindex\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:27 +msgid "" +"Or put the following in your [Bitcoin configuration file](https://github.com/" +"bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md#configuration-file-path):" +msgstr "" +"या अपनी [बिटकॉइन कॉन्फ़िगरेशन फ़ाइल](https://github.com/" +"bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md#configuration-file-path) " +"में निम्नलिखित दर्ज करें:" + +#: src/guides/sat-hunting.md:34 +msgid "" +"Launch it and wait for it to catch up to the chain tip, at which point the " +"following command should print out the current block height:" +msgstr "" +"इसे लॉन्च करें और इसके चेन टिप तक पहुंचने की प्रतीक्षा करें, जिस बिंदु पर निम्नलिखित कमांड को " +"वर्तमान ब्लॉक की ऊंचाई को प्रिंट करना चाहिए:" + +#: src/guides/sat-hunting.md:37 +msgid "" +"```sh\n" +"bitcoin-cli getblockcount\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:41 +msgid "Second, you'll need a synced `ord` index." +msgstr "" +"दूसरा, आपको एक सिंक किए गए ऑर्ड इंडेक्स की आवश्यकता होगी।" + +#: src/guides/sat-hunting.md:43 +msgid "Get a copy of `ord` from [the repo](https://github.com/ordinals/ord/)." +msgstr "" +"[रेपो](https://github.com/ordinals/ord/) से `ऑर्ड` की एक प्रति प्राप्त करें।" + +#: src/guides/sat-hunting.md:45 +msgid "" +"Run `RUST_LOG=info ord index`. It should connect to your bitcoin core node " +"and start indexing." +msgstr "" +"`RUST_LOG=जानकारी ऑर्ड इंडेक्स` क्रियाशील करें। यह आपके बिटकॉइन कोर नोड से जुड़ना चाहिए और " +"सूचकांक शुरू हो जाना चाहिए।" + +#: src/guides/sat-hunting.md:48 +msgid "Wait for it to finish indexing." +msgstr "" +"इसके सूचकांक के समाप्त होने तक प्रतीक्षा करें।" + +#: src/guides/sat-hunting.md:50 +msgid "Third, you'll need a wallet with UTXOs that you want to search." +msgstr "" +"तीसरा, जिसे UTXOs वॉलेट को आप खोजना चाहते हैं आपको उसकी आवश्यकता होगी।" + +#: src/guides/sat-hunting.md:52 +msgid "Searching for Rare Ordinals" +msgstr "" +"दुर्लभ ऑर्डिनल्स्‍स (क्रमसूचक) के लिए खोज" + +#: src/guides/sat-hunting.md:55 +msgid "Searching for Rare Ordinals in a Bitcoin Core Wallet" +msgstr "" +"बिटकॉइन कोर वॉलेट में दुर्लभ ऑर्डिनल्स्‍स (क्रमसूचक) के लिए खोज" + +#: src/guides/sat-hunting.md:57 +msgid "" +"The `ord wallet` command is just a wrapper around Bitcoin Core's RPC API, so " +"searching for rare ordinals in a Bitcoin Core wallet is Easy. Assuming your " +"wallet is named `foo`:" +msgstr "" +"`ऑर्ड वॉलेट` कमांड बिटकॉइन कोर के आरपीसी एपीआई के चारों ओर सिर्फ एक आवरण है, इसलिए बिटकॉइन " +"कोर वॉलेट में दुर्लभ ऑर्डिनल्स की खोज करना आसान है। मान लें कि आपके वॉलेट का नाम `foo` है:" + +#: src/guides/sat-hunting.md:61 +msgid "Load your wallet:" +msgstr "" +"अपना वॉलेट लोड करें:" + +#: src/guides/sat-hunting.md:63 +msgid "" +"```sh\n" +"bitcoin-cli loadwallet foo\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:67 +msgid "Display any rare ordinals wallet `foo`'s UTXOs:" +msgstr "" +"किसी भी दुर्लभ ऑर्डिनल्स वॉलेट `foo` का UTXO प्रदर्शित करें:" + +#: src/guides/sat-hunting.md:69 src/guides/sat-hunting.md:132 +#: src/guides/sat-hunting.md:233 +msgid "" +"```sh\n" +"ord wallet sats\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:73 +msgid "Searching for Rare Ordinals in a Non-Bitcoin Core Wallet" +msgstr "" +"गैर-बिटकॉइन कोर वॉलेट में दुर्लभ ऑर्डिनल्स की खोज करें" + +#: src/guides/sat-hunting.md:75 +msgid "" +"The `ord wallet` command is just a wrapper around Bitcoin Core's RPC API, so " +"to search for rare ordinals in a non-Bitcoin Core wallet, you'll need to " +"import your wallet's descriptors into Bitcoin Core." +msgstr "" +"`ऑर्ड वॉलेट` कमांड बिटकॉइन कोर के आरपीसी एपीआई के इर्द-गिर्द रैप्‍ड हैं, इसलिए गैर-बिटकॉइन कोर वॉलेट " +"में दुर्लभ ऑर्डिनल्स की खोज करने के लिए, आपको अपने वॉलेट के डिस्क्रिप्टर को बिटकॉइन कोर में इंपोर्ट " +"करना होगा।" + +#: src/guides/sat-hunting.md:79 +msgid "" +"[Descriptors](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors." +"md) describe the ways that wallets generate private keys and public keys." +msgstr "" +"[डिस्क्रिप्टर्स](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md) " +"उन तरीकों का वर्णन करते हैं जिनसे वॉलेट निजी कुंजी और सार्वजनिक कुंजी का सृजन करते हैं।" + +#: src/guides/sat-hunting.md:82 +msgid "" +"You should only import descriptors into Bitcoin Core for your wallet's " +"public keys, not its private keys." +msgstr "" +"केवल वॉलेट की सार्वजनिक कुंजी के लिए आपको अपने बिटकॉइन कोर में डिस्क्रिप्टर इंपोर्ट करना चाहिए, " +"न कि इसकी निजी कुंजी के लिए।" + +#: src/guides/sat-hunting.md:85 +msgid "" +"If your wallet's public key descriptor is compromised, an attacker will be " +"able to see your wallet's addresses, but your funds will be safe." +msgstr "" +"यदि आपके वॉलेट की सार्वजनिक कुंजी डिस्क्रिप्टर के साथ छेड़छाड़ की गई है, ऐसी सूरत में छेड़छाड़ करने " +"वाला आपके वॉलेट के पते देख सकेगा, लेकिन आपका फंड फिर भी सुरक्षित रहेगा।" + +#: src/guides/sat-hunting.md:88 +msgid "" +"If your wallet's private key descriptor is compromised, an attacker can " +"drain your wallet of funds." +msgstr "" +"यदि आपके वॉलेट की निजी कुंजी डिस्क्रिप्टर के साथ किसी प्रकार की छेड़छाड़ की गई है, तो ऐसी स्थिति में " +"छेड़छाड़ करने वाला आपके वॉलेट से धनराशि निकाल सकता है।" + +#: src/guides/sat-hunting.md:91 +msgid "" +"Get the wallet descriptor from the wallet whose UTXOs you want to search for " +"rare ordinals. It will look something like this:" +msgstr "" +"वॉलेट डिस्क्रिप्टर उस वॉलेट से प्राप्त करें जिसके यूटीएक्सओ में आप दुर्लभ ऑर्डिनल्स की खोज करना चाहते हैं। " +"यह कुछ इस तरह से दिखेगा:" + +#: src/guides/sat-hunting.md:94 +msgid "" +"```\n" +"wpkh([bf1dd55e/84'/0'/0']xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/0/" +"*)#csvefu29\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:98 +msgid "Create a watch-only wallet named `foo-watch-only`:" +msgstr "" +"सिर्फ देखने योग्‍य `foo-watch-only` नामक वॉलेट बनाएं:" + +#: src/guides/sat-hunting.md:100 +msgid "" +"```sh\n" +"bitcoin-cli createwallet foo-watch-only true true\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:104 +msgid "Feel free to give it a better name than `foo-watch-only`!" +msgstr "" +"इसे `foo-watch-only` के मुकाबले बेझिझक बेहतर नाम दें!" + +#: src/guides/sat-hunting.md:106 +msgid "Load the `foo-watch-only` wallet:" +msgstr "" +"`foo-watch-only` वॉलेट लोड करें:" + +#: src/guides/sat-hunting.md:108 src/guides/sat-hunting.md:199 +msgid "" +"```sh\n" +"bitcoin-cli loadwallet foo-watch-only\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:112 +msgid "Import your wallet descriptors into `foo-watch-only`:" +msgstr "" +"अपने वॉलेट डिस्क्रिप्टर को `foo-watch-only` पर इंपोर्ट करें:" + +#: src/guides/sat-hunting.md:114 +msgid "" +"```sh\n" +"bitcoin-cli importdescriptors \\\n" +" '[{ \"desc\": " +"\"wpkh([bf1dd55e/84h/0h/0h]xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/0/" +"*)#tpnxnxax\", \"timestamp\":0 }]'\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:119 +msgid "" +"If you know the Unix timestamp when your wallet first started receive " +"transactions, you may use it for the value of `\"timestamp\"` instead of " +"`0`. This will reduce the time it takes for Bitcoin Core to search for your " +"wallet's UTXOs." +msgstr "" +"यदि आप यूनिक्स टाइमस्टैम्प से अवगत हैं जब आपके वॉलेट ने पहली बार लेनदेन प्राप्त करना शुरू " +"किया था, तब आप इसका उपयोग 0 के बजाय "टाइमस्टैम्प" के मूल्य के लिए कर सकते हैं। इससे " +"बिटकॉइन कोर को आपके वॉलेट के यूटीएक्सओ की खोज करने में लगने वाला समय कम हो जाएगा।" + +#: src/guides/sat-hunting.md:124 src/guides/sat-hunting.md:225 +msgid "Check that everything worked:" +msgstr "" +"जांच लें कि सब कुछ सही से काम कर रहा है:" + +#: src/guides/sat-hunting.md:126 src/guides/sat-hunting.md:227 +msgid "" +"```sh\n" +"bitcoin-cli getwalletinfo\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:130 src/guides/sat-hunting.md:231 +msgid "Display your wallet's rare ordinals:" +msgstr "" +"अपने वॉलेट के दुर्लभ ऑर्डिनलस प्रदर्शित करें:" + +#: src/guides/sat-hunting.md:136 +msgid "" +"Searching for Rare Ordinals in a Wallet that Exports Multi-path Descriptors" +msgstr "" +"मल्टी-पथ डिस्क्रिप्टर निर्यात करने वाले वॉलेट में दुर्लभ ऑर्डिनल्स की खोज करना" + +#: src/guides/sat-hunting.md:138 +msgid "" +"Some descriptors describe multiple paths in one descriptor using angle " +"brackets, e.g., `<0;1>`. Multi-path descriptors are not yet supported by " +"Bitcoin Core, so you'll first need to convert them into multiple " +"descriptors, and then import those multiple descriptors into Bitcoin Core." +msgstr "" +"कुछ डिस्क्रिप्टर कोण कोष्ठक का उपयोग करके एक डिस्क्रिप्टर में एक से अधिक पथों का उल्‍लेख करते हैं, " +"उदाहरण के लिए, `<0;1>` मल्टी-पथ डिस्क्रिप्टर को वर्तमान में बिटकॉइन कोर द्वारा समर्थन नहीं दिया गया है, " +"इसलिए आपको पहले उन्हें बहुत सारे डिस्क्रिप्टर्स में बदलना होगा, और फिर उन मल्टीपल डिस्क्रिप्टर को " +"बिटकॉइन कोर में इंपोर्ट करना होगा।" + +#: src/guides/sat-hunting.md:143 +msgid "" +"First get the multi-path descriptor from your wallet. It will look something " +"like this:" +msgstr "" +"सबसे पहले अपने वॉलेट से मल्टी-पथ डिस्क्रिप्टर प्राप्त करें। यह कुछ इस तरह दिखेगा:" + +#: src/guides/sat-hunting.md:146 +msgid "" +"```\n" +"wpkh([bf1dd55e/84h/0h/0h]xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/" +"<0;1>/*)#fw76ulgt\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:150 +msgid "Create a descriptor for the receive address path:" +msgstr "प्राप्त पता पथ के लिए एक डिस्क्रिप्टर का सृजन करें:" + +#: src/guides/sat-hunting.md:152 +msgid "" +"```\n" +"wpkh([bf1dd55e/84'/0'/0']xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/0/" +"*)\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:156 +msgid "And the change address path:" +msgstr "और पता परिवर्तन पथ:" + +#: src/guides/sat-hunting.md:158 +msgid "" +"```\n" +"wpkh([bf1dd55e/84'/0'/0']xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/1/" +"*)\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:162 +msgid "" +"Get and note the checksum for the receive address descriptor, in this case " +"`tpnxnxax`:" +msgstr "" +"प्राप्त पता डिस्क्रिप्टर के लिए चेकसम प्राप्त करें और नोट करें, इस मामले में tpnxnxax:" + +#: src/guides/sat-hunting.md:165 +msgid "" +"```sh\n" +"bitcoin-cli getdescriptorinfo \\\n" +" 'wpkh([bf1dd55e/84h/0h/0h]xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/0/" +"*)'\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:170 +msgid "" +"```json\n" +"{\n" +" \"descriptor\": " +"\"wpkh([bf1dd55e/84'/0'/0']xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/0/" +"*)#csvefu29\",\n" +" \"checksum\": \"tpnxnxax\",\n" +" \"isrange\": true,\n" +" \"issolvable\": true,\n" +" \"hasprivatekeys\": false\n" +"}\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:180 +msgid "And for the change address descriptor, in this case `64k8wnd7`:" +msgstr "और परिवर्तन पता डिस्क्रिप्टर के लिए, इस मामले में 64k8wnd7:" + +#: src/guides/sat-hunting.md:182 +msgid "" +"```sh\n" +"bitcoin-cli getdescriptorinfo \\\n" +" 'wpkh([bf1dd55e/84h/0h/0h]xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/1/" +"*)'\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:187 +msgid "" +"```json\n" +"{\n" +" \"descriptor\": " +"\"wpkh([bf1dd55e/84'/0'/0']xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/1/" +"*)#fyfc5f6a\",\n" +" \"checksum\": \"64k8wnd7\",\n" +" \"isrange\": true,\n" +" \"issolvable\": true,\n" +" \"hasprivatekeys\": false\n" +"}\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:197 +msgid "Load the wallet you want to import the descriptors into:" +msgstr "वह वॉलेट लोड करें जिसमें आप डिस्क्रिप्टर इंपोर्ट करना चाहते हैं:" + +#: src/guides/sat-hunting.md:203 +msgid "" +"Now import the descriptors, with the correct checksums, into Bitcoin Core." +msgstr "" +"अब बिटकॉइन कोर में सही चेकसम के साथ डिस्क्रिप्टर को इंपोर्ट करें।" + +#: src/guides/sat-hunting.md:205 +msgid "" +"```sh\n" +"bitcoin-cli \\\n" +" importdescriptors \\\n" +" '[\n" +" {\n" +" \"desc\": " +"\"wpkh([bf1dd55e/84h/0h/0h]xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/0/" +"*)#tpnxnxax\"\n" +" \"timestamp\":0\n" +" },\n" +" {\n" +" \"desc\": " +"\"wpkh([bf1dd55e/84h/0h/0h]xpub6CcJtWcvFQaMo39ANFi1MyXkEXM8T8ZhnxMtSjQAdPmVSTHYnc8Hwoc11VpuP8cb8JUTboZB5A7YYGDonYySij4XTawL6iNZvmZwdnSEEep/1/" +"*)#64k8wnd7\",\n" +" \"timestamp\":0\n" +" }\n" +" ]'\n" +"```" +msgstr "" + +#: src/guides/sat-hunting.md:220 +msgid "" +"If you know the Unix timestamp when your wallet first started receive " +"transactions, you may use it for the value of the `\"timestamp\"` fields " +"instead of `0`. This will reduce the time it takes for Bitcoin Core to " +"search for your wallet's UTXOs." +msgstr "" +"यदि आप यूनिक्स टाइमस्टैम्प से अवगत हैं जब आपके वॉलेट ने पहली बार लेनदेन प्राप्त करना शुरू किया था, " +"तब आप इसका उपयोग `0` के बजाय `\"टाइमस्टैम्प\"` के मूल्य के लिए कर सकते हैं। इससे बिटकॉइन कोर को " +"आपके वॉलेट के यूटीएक्सओ की खोज करने में लगने वाला समय कम हो जाएगा।" + +#: src/guides/sat-hunting.md:237 +msgid "Exporting Descriptors" +msgstr "डिस्क्रिप्टर एक्‍सपोर्ट करना" + +#: src/guides/sat-hunting.md:241 +msgid "" +"Navigate to the `Settings` tab, then to `Script Policy`, and press the edit " +"button to display the descriptor." +msgstr "" +"पहले सेटिंग्स टैब पर जाएँ, फिर स्क्रिप्ट पॉलिसी पर जाएँ, और डिस्क्रिप्टर प्रदर्शित करने के लिए एडिट बटन दबाएँ।" + +#: src/guides/sat-hunting.md:244 +msgid "Transferring Ordinals" +msgstr "ऑर्डिनल्‍स (क्रमसूचक संख्‍याएं) स्थानांतरित करना" + +#: src/guides/sat-hunting.md:246 +msgid "" +"The `ord` wallet supports transferring specific satoshis. You can also use " +"`bitcoin-cli` commands `createrawtransaction`, " +"`signrawtransactionwithwallet`, and `sendrawtransaction`, how to do so is " +"complex and outside the scope of this guide." +msgstr "" +"`ऑर्ड` वॉलेट विशिष्ट सातोशी स्थानांतरित करने का समर्थन करता है। आप `createrawtransaction`, " +"`signrawtransactionwithwallet`, और `sendrawtransaction` बिटकॉइन-सीएलआई कमांड भी प्रयोग " +"कर सकते हैं, इसे कैसे करना है यह थोड़ा मुश्किल है और इस मार्गदर्शिका के दायरे से बाहर के विषय हैं।" + +#: src/guides/collecting.md:4 +msgid "" +"Currently, [ord](https://github.com/ordinals/ord/) is the only wallet " +"supporting sat-control and sat-selection, which are required to safely store " +"and send rare sats and inscriptions, hereafter ordinals." +msgstr "" +"वर्तमान में, [ऑर्ड](https://github.com/ordinals/ord/) सैट-कंट्रोल और सैट-सलेक्‍शन का समर्थन " +"करने वाला एकमात्र वॉलेट है, जो दुर्लभ सैट्स और इंस्‍क्रीप्‍शंसm(एतदद्वारा ऑर्डिनल्‍स कहा गया है) को सुरक्षित रूप " +"से संग्रहीत करने और प्रेषित करने के लिए आवश्यक हैं।" + +#: src/guides/collecting.md:8 +msgid "" +"The recommended way to send, receive, and store ordinals is with `ord`, but " +"if you are careful, it is possible to safely store, and in some cases send, " +"ordinals with other wallets." +msgstr "" +ऑर्डिनल्स को प्रेषित, प्राप्त और संग्रहीत करने के लिए ऑर्ड अनुशंसित तरीका है, लेकिन यदि आप चौकस रहते हैं, " +तो ऑर्डिनल्स को अन्य वॉलेट के साथ सुरक्षित रूप से संग्रहीत करना और कुछ मामलों में प्रेषित करना संभव है।" + +#: src/guides/collecting.md:12 +msgid "" +"As a general note, receiving ordinals in an unsupported wallet is not " +"dangerous. Ordinals can be sent to any bitcoin address, and are safe as long " +"as the UTXO that contains them is not spent. However, if that wallet is then " +"used to send bitcoin, it may select the UTXO containing the ordinal as an " +"input, and send the inscription or spend it to fees." +msgstr "" +"एक सामान्य टिप्‍पणी के रूप में, ऐसा वॉलेट जिसका समर्थन नहीं किया जाता उसमें ऑर्डिनल्स प्राप्त करना " +"खतरनाक नहीं है। ऑर्डिनल्स किसी भी बिटकॉइन पते पर भेजे जा सकते हैं, और वे तब तक सुरक्षित हैं जब तक " +"उनमें शामिल यूटीएक्सओ खर्च नहीं किए जाते। हालाँकि, यदि उस वॉलेट का उपयोग बिटकॉइन भेजने के लिए किया " +"जाता है, तो यह इनपुट के रूप में ऑर्डिनल वाले UTXO का चयन कर सकता है, और डिजिटल अभिलेख " +"प्रेषित कर सकता है या इसे शुल्‍क के रूप में खर्च कर सकता है।" + +#: src/guides/collecting.md:18 +msgid "" +"A [guide](./collecting/sparrow-wallet.md) to creating an `ord`\\-compatible " +"wallet with [Sparrow Wallet](https://sparrowwallet.com/), is available in " +"this handbook." +msgstr "" +"[स्पैरो वॉलेट](https://sparrowwallet.com/) के साथ एक `ऑर्ड`\\-संगत वॉलेट बनाने की मार्गदर्शिका " +"इस[हस्‍तपुस्तिका](./collecting/sparrow-wallet.md) में उपलब्ध है।" + +#: src/guides/collecting.md:21 +msgid "" +"Please note that if you follow this guide, you should not use the wallet you " +"create to send BTC, unless you perform manual coin-selection to avoid " +"sending ordinals." +msgstr "" +"कृपया ध्यान दें कि यदि आप इस मार्गदर्शिका का अनुसरण करते हैं, तब आपको बीटीसी भेजने के लिए अपने " +"द्वारा बनाए गए वॉलेट का उपयोग नहीं करना चाहिए, जब तक कि आप ऑर्डर भेजने से बचने के लिए मैन्युअल " +"सिक्कों का चयन नहीं करते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:1 +msgid "Collecting Inscriptions and Ordinals with Sparrow Wallet" +msgstr "स्पैरो वॉलेट के साथ इंस्‍क्रीप्‍शंस और ऑर्डिनल्‍स संग्रहीत करना" + +#: src/guides/collecting/sparrow-wallet.md:4 +msgid "" +"Users who cannot or have not yet set up the [ord](https://github.com/" +"ordinals/ord) wallet can receive inscriptions and ordinals with alternative " +"bitcoin wallets, as long as they are _very_ careful about how they spend " +"from that wallet." +msgstr "" +"ऐसे उपयोगकर्ता जो अभी तक [ऑर्ड](https://github.com/ordinals/ord) वॉलेट सेट नहीं कर " +"सके या अभी तक सेट नहीं किया है, वे वैकल्पिक बिटकॉइन वॉलेट से इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) और " +"ऑर्डिनल्‍स (क्रमसूचक संख्‍याएं) प्राप्त कर सकते हैं, बशर्ते वे उस वॉलेट से _सावधानी_ के साथ खर्च करते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:6 +msgid "" +"This guide gives some basic steps on how to create a wallet with [Sparrow " +"Wallet](https://sparrowwallet.com/) which is compatible with `ord` and can " +"be later imported into `ord`" +msgstr "" +"[स्पैरो वॉलेट](https://sparrowwallet.com/) के साथ वॉलेट कैसे बनाने हैं इसके बारे में यह " +"मार्गदर्शिका कुछ बुनियादी कदमों का उल्‍लेख करती है जो ऑर्ड के साथ संगत है और बाद में इसे `ऑर्ड` में इंपोर्ट " +"किया जा सकता है।" + +#: src/guides/collecting/sparrow-wallet.md:8 +msgid "⚠️⚠️ Warning!! ⚠️⚠️" +msgstr "⚠️⚠️ चेतावनी!! ⚠️⚠️" + +#: src/guides/collecting/sparrow-wallet.md:9 +msgid "" +"As a general rule if you take this approach, you should use this wallet with " +"the Sparrow software as a receive-only wallet." +msgstr "" +"एक सामान्य नियम के रूप में यदि आप इस दृष्टिकोण को अपनाते हैं, तब आपको स्पैरो सॉफ़्टवेयर के साथ इस " +"वॉलेट का उपयोग रिसीव-ओनली वॉलेट के रूप में करना चाहिए।" + +#: src/guides/collecting/sparrow-wallet.md:11 +msgid "" +"Do not spend any satoshis from this wallet unless you are sure you know what " +"you are doing. You could very easily inadvertently lose access to your " +"ordinals and inscriptions if you don't heed this warning." +msgstr "" +"इस वॉलेट से तब तक कोई सातोशी खर्च मत करें जब तक आप आश्वस्त न हो जाएं कि आप अच्‍छे से जानते हैं " +"कि आप क्या कर रहे हैं। यदि आप इस चेतावनी पर ध्यान नहीं देते हैं तो आप बहुत आसानी से अनजाने में अपने " +"ऑर्डिनल्‍स और इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) पर संपर्क करने में सक्षम नहीं होंगे।" + +#: src/guides/collecting/sparrow-wallet.md:13 +msgid "Wallet Setup & Receiving" +msgstr "वॉलेट सेटअप और प्राप्त करना" + +#: src/guides/collecting/sparrow-wallet.md:15 +msgid "" +"Download the Sparrow Wallet from the [releases page](https://sparrowwallet." +"com/download/) for your particular operating system." +msgstr "" +"[रिलीज़ पेज](https://sparrowwallet.com/download/) से अपने विशेष ऑपरेटिंग सिस्टम " +"के लिए स्पैरो वॉलेट डाउनलोड करें।" + +#: src/guides/collecting/sparrow-wallet.md:17 +msgid "Select `File -> New Wallet` and create a new wallet called `ord`." +msgstr "" +"`फ़ाइल -> New Wallet` चयन करें और `ऑर्ड` नामक एक नया वॉलेट बनाएं।" + +#: src/guides/collecting/sparrow-wallet.md:19 +msgid "![](images/wallet_setup_01.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:21 +msgid "" +"Change the `Script Type` to `Taproot (P2TR)` and select the `New or Imported " +"Software Wallet` option." +msgstr "" +"`Script Type` को `Taproot (P2TR)` में बदलें और `नया या इंर्पोटेड " +"सॉफ़्टवेयर वॉलेट` विकल्प का चयन करें।" + +#: src/guides/collecting/sparrow-wallet.md:23 +msgid "![](images/wallet_setup_02.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:25 +msgid "" +"Select `Use 12 Words` and then click `Generate New`. Leave the passphrase " +"blank." +msgstr "" +"`Use 12 Words` का चयन करें और फिर `Generate New` पर क्लिक करें। पासफ़्रेज़ को खाली छोड़ दें।" + +#: src/guides/collecting/sparrow-wallet.md:27 +msgid "![](images/wallet_setup_03.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:29 +msgid "" +"A new 12 word BIP39 seed phrase will be generated for you. Write this down " +"somewhere safe as this is your backup to get access to your wallet. NEVER " +"share or show this seed phrase to anyone else." +msgstr "" +"आपके लिए एक नया 12 शब्दों का BIP39 सीड फ्रेज उत्पन्न किया जाएगा। इसे कहीं सुरक्षित स्थान पर लिख " +"लें क्‍योंकि यह आपकी वॉलेट तक पहुँचने के लिए आपकी बैकअप है। किसी के साथ इस सीड फ्रेज को कभी " +"साझा नहीं करें और न दिखाएं।" + +#: src/guides/collecting/sparrow-wallet.md:31 +msgid "Once you have written down the seed phrase click `Confirm Backup`." +msgstr "" +"जब आपने सीड फ्रेज लिख लिया हो, तो `Confirm Backup` पर क्लिक करें।" + + +#: src/guides/collecting/sparrow-wallet.md:33 +msgid "![](images/wallet_setup_04.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:35 +msgid "" +"Re-enter the seed phrase which you wrote down, and then click `Create " +"Keystore`." +msgstr "" +"जिस सीड फ़्रेज़ को आपने अभी लिखा है उसे दुबारा दर्ज करें, और फिर `Create Keystore` पर क्लिक करें।" + +#: src/guides/collecting/sparrow-wallet.md:37 +msgid "![](images/wallet_setup_05.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:39 +msgid "Click `Import Keystore`." +msgstr "`Import Keystore` पर क्लिक करें।" + +#: src/guides/collecting/sparrow-wallet.md:41 +msgid "![](images/wallet_setup_06.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:43 +msgid "Click `Apply`. Add a password for the wallet if you want to." +msgstr "" +"`Apply` पर क्लिक करें। यदि आप चाहते हैं तो वॉलेट के लिए एक पासवर्ड डालें।" + +#: src/guides/collecting/sparrow-wallet.md:45 +msgid "![](images/wallet_setup_07.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:47 +msgid "" +"You now have a wallet which is compatible with `ord`, and can be imported " +"into `ord` using the BIP39 Seed Phrase. To receive ordinals or inscriptions, " +"click on the `Receive` tab and copy a new address." +msgstr "" +"अब आपके पास एक वॉलेट उपलब्‍ध है जो `ऑर्ड` के साथ संगत है, और इसे BIP39 सीड फ़्रेज़ का उपयोग करके " +"`ऑर्ड` में इंपोर्ट किया जा सकता है। ऑर्डिनल्‍स (क्रमसूचक संख्‍याएं) या इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्राप्त " +"करने के लिए, `Receive` टैब पर क्लिक करें और नये पते को कॉपी करें।" + +#: src/guides/collecting/sparrow-wallet.md:49 +msgid "" +"Each time you want to receive you should use a brand-new address, and not re-" +"use existing addresses." +msgstr "" +"हर बार जब आप प्राप्त करना चाहते हैं तो आपको बिल्कुल नए पते का उपयोग करना होगा, और वर्तमान पते का " +"दोबारा उपयोग नहीं करना है।" + +#: src/guides/collecting/sparrow-wallet.md:51 +msgid "" +"Note that bitcoin is different to some other blockchain wallets, in that " +"this wallet can generate an unlimited number of new addresses. You can " +"generate a new address by clicking on the `Get Next Address` button. You can " +"see all of your addresses in the `Addresses` tab of the app." +msgstr "" +"ध्यान दें कि बिटकॉइन कुछ अन्य ब्लॉकचेन वॉलेट से भिन्‍न होते हैं, क्योंकि यह वॉलेट असीमित संख्या में नए पते " +"उत्पन्न कर सकते हैं। आप `Get Next Address` बटन पर क्लिक करके नये पते का सृजन कर सकते हैं। आप " +"अपने सभी पते ऐप के `एड्रेस` टैब पर देख सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:53 +msgid "" +"You can add a label to each address, so you can keep track of what it was " +"used for." +msgstr "" +"आप प्रत्येक पते पर एक लेबल जोड़ सकते हैं, ताकि आप इसका ट्रैक रख सकें कि इसका उपयोग किस लिए " +"किया गया था।" + +#: src/guides/collecting/sparrow-wallet.md:55 +msgid "![](images/wallet_setup_08.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:57 +msgid "Validating / Viewing Received Inscriptions" +msgstr "प्राप्त की गई इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) का प्रमाणीकरण/देखना" + +#: src/guides/collecting/sparrow-wallet.md:59 +msgid "" +"Once you have received an inscription you will see a new transaction in the " +"`Transactions` tab of Sparrow, as well as a new UTXO in the `UTXOs` tab." +msgstr "" +"एक बार जब आप एक इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्राप्त कर लेते हैं तब आपको स्पैरो के `Transactions` " +"टैब में एक नया लेनदेन, साथ ही यूटीएक्सओ टैब में एक नया `UTXOs` दिखाई देगा।" + +#: src/guides/collecting/sparrow-wallet.md:61 +msgid "" +"Initially this transaction may have an \"Unconfirmed\" status, and you will " +"need to wait for it to be mined into a bitcoin block before it is fully " +"received." +msgstr "" +"शुरूआत में इस लेन-देन की स्थिति \"अपुष्टीकृत\" हो सकती है, और आपको इसे पूरी तरह से प्राप्त होने से पहले +"बिटकॉइन ब्लॉक में इसके खनन होने की प्रतीक्षा करनी होगी।" + +#: src/guides/collecting/sparrow-wallet.md:63 +msgid "![](images/validating_viewing_01.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:65 +msgid "" +"To track the status of your transaction you can right-click on it, select " +"`Copy Transaction ID` and then paste that transaction id into [mempool.space]" +"(https://mempool.space)." +msgstr "" +"अपने लेनदेन की स्थिति को ट्रैक करने के लिए आप उस पर राइट-क्लिक कर सकते हैं, `Copy Transaction ID` " +"का चयन करें और फिर उस लेनदेन आईडी को [mempool.space](https://mempool.space) में पेस्ट कर दें।" + +#: src/guides/collecting/sparrow-wallet.md:67 +msgid "![](images/validating_viewing_02.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:69 +msgid "" +"Once the transaction has confirmed, you can validate and view your " +"inscription by heading over to the `UTXOs` tab, finding the UTXO you want to " +"check, right-clicking on the `Output` and selecting `Copy Transaction " +"Output`. This transaction output id can then be pasted into the [ordinals." +"com](https://ordinals.com) search." +msgstr "" +"एक बार जब लेन-देन की पुष्टि हो जाती है, आप इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) को प्रमाणीकरण और देखने " +"के लिए `UTXOs` टैब पर जाकर, जिस यूटीएक्सओ की जांच करना चाहते हैं, आप Output और `Copy " +"Transaction Output` पर राइट क्लिक करें। इस लेनदेन आउटपुट आईडी को फिर [ordinals.com]" +"(https://ordinals.com) खोज में पेस्‍ट किया जा सकता है।" + +#: src/guides/collecting/sparrow-wallet.md:72 +msgid "Freezing UTXO's" +msgstr " UTXO फ्रीज करना" + +#: src/guides/collecting/sparrow-wallet.md:73 +msgid "" +"As explained above, each of your inscriptions is stored in an Unspent " +"Transaction Output (UTXO). You want to be very careful not to accidentally " +"spend your inscriptions, and one way to make it harder for this to happen is " +"to freeze the UTXO." +msgstr "" +"जैसा कि ऊपर स्‍पष्‍ट किया गया है, आपका प्रत्येक इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) अनस्पेंट ट्रांजेक्शन " +"आउटपुट (UTXO) में संग्रहीत किया गया है। आपके इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) गलती से भी खर्च न हों, " +"इसके लिए आपको बेहद सावधान रहना चाहि‍ए, और इसे कठिन बनाने का तरीका यूटीएक्सओ को फ्रीज " +"करना है।" + + +#: src/guides/collecting/sparrow-wallet.md:75 +msgid "" +"To do this, go to the `UTXOs` tab, find the UTXO you want to freeze, right-" +"click on the `Output` and select `Freeze UTXO`." +msgstr "" +"इसे करने के लिए, `UTXOs` टैब पर जाएं, जिस UTXO को आप फ़्रीज़ करना चाहते हैं, " +"`Output` पर राइट-क्लिक करें और `Freeze UTXO` टैब का चयन करें।" + +#: src/guides/collecting/sparrow-wallet.md:77 +msgid "" +"This UTXO (Inscription) is now un-spendable within the Sparrow Wallet until " +"you unfreeze it." +msgstr "" +"यह UTXO (इंस्‍क्रीप्‍शंस) अब स्पैरो वॉलेट में तब तक खर्च नहीं किए जा सकेंगे जब तक आप " +"इसे फ्रीज को निष्क्रिय नहीं कर देते।" + +#: src/guides/collecting/sparrow-wallet.md:79 +msgid "Importing into `ord` wallet" +msgstr "`ऑर्ड` वॉलेट में इंपोर्ट किया जा रहा है" + +#: src/guides/collecting/sparrow-wallet.md:81 +msgid "" +"For details on setting up Bitcoin Core and the `ord` wallet check out the " +"[Inscriptions Guide](../inscriptions.md)" +msgstr "" +"बिटकॉइन कोर और `ऑर्ड` वॉलेट सेट करने के विवरण के लिए इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) मार्गदर्शक " +"[Inscriptions Guide](../inscriptions.md) निर्देश देखें।" + +#: src/guides/collecting/sparrow-wallet.md:83 +msgid "" +"When setting up `ord`, instead of running `ord wallet create` to create a " +"brand-new wallet, you can import your existing wallet using `ord wallet " +"restore \"BIP39 SEED PHRASE\"` using the seed phrase you generated with " +"Sparrow Wallet." +msgstr "" +"`ऑर्ड` सेट करते समय, `ord wallet create` को चलाने के बजाय, एकदम नया वॉलेट बनाएं, आप स्पैरो " +"वॉलेट के साथ सृजन किए गए सीड फ़्रेज़ का उपयोग करके `ord wallet restore \"BIP39 सीड फ़्रेज़\"` " +"का उपयोग करके अपना मौजूदा वॉलेट इंपोर्ट कर सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:85 +msgid "" +"There is currently a [bug](https://github.com/ordinals/ord/issues/1589) " +"which causes an imported wallet to not be automatically rescanned against " +"the blockchain. To work around this you will need to manually trigger a " +"rescan using the bitcoin core cli: `bitcoin-cli -rpcwallet=ord " +"rescanblockchain 767430`" +msgstr "" +"वर्तमान में एक [बग](https://github.com/ordinals/ord/issues/1589) का हमला हुआ है, " +"जिसके कारण इंपोर्ट किए गये वॉलेट को ब्लॉकचेन के विरुद्ध स्वचालित रूप से दुबारा स्कैन नहीं किया जा सकता। " +"इसे दुरूस्‍त करने के लिए, आपको bitcoin core cli:`bitcoin-cli -rpcwallet=ord " +"rescanblockchain 767430` का उपयोग करके मैन्युअल रूप से रीस्कैन करना होगा।" + + +#: src/guides/collecting/sparrow-wallet.md:88 +msgid "" +"You can then check your wallet's inscriptions using `ord wallet inscriptions`" +msgstr "" +"इसके बाद आप `ord wallet inscriptions` का उपयोग कर अपने वॉलेट इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) " +"की जांच कर सकते हैं" + +#: src/guides/collecting/sparrow-wallet.md:90 +msgid "" +"Note that if you have previously created a wallet with `ord`, then you will " +"already have a wallet with the default name, and will need to give your " +"imported wallet a different name. You can use the `--wallet` parameter in " +"all `ord` commands to reference a different wallet, eg:" +msgstr "" +"ध्यान रहे, यदि आपने पहले `ऑर्ड` के साथ एक वॉलेट बना चुके हैं, तब आपके पास पहले से ही डिफ़ॉल्ट नाम " +"वाला एक वॉलेट पहले से ही उपलब्‍ध है, और इसलिए आपको अपने इंर्पोटेड वॉलेट को कोई दूसरा नाम देना होगा। " +"आप सभी `ऑर्ड` में `–-wallet` पैरामीटर में सभी कमांड का उपयोग करके किसी भिन्न वॉलेट को संदर्भित कर " +"सकते हैं, उदाहरण के लिए:" + +#: src/guides/collecting/sparrow-wallet.md:92 +msgid "`ord --wallet ord_from_sparrow wallet restore \"BIP39 SEED PHRASE\"`" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:94 +msgid "`ord --wallet ord_from_sparrow wallet inscriptions`" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:96 +msgid "`bitcoin-cli -rpcwallet=ord_from_sparrow rescanblockchain 767430`" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:98 +msgid "Sending inscriptions with Sparrow Wallet" +msgstr "स्पैरो वॉलेट के साथ इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्रेषित करना" + +#: src/guides/collecting/sparrow-wallet.md:100 +msgid "⚠️⚠️ Warning ⚠️⚠️" +msgstr "⚠️⚠️ चेतावनी ⚠️⚠️" + +#: src/guides/collecting/sparrow-wallet.md:101 +msgid "" +"While it is highly recommended that you set up a bitcoin core node and run " +"the `ord` software, there are certain limited ways you can send inscriptions " +"out of Sparrow Wallet in a safe way. Please note that this is not " +"recommended, and you should only do this if you fully understand what you " +"are doing." +msgstr "" +"हालांकि यह अत्यधिक अनुशंसित किया जाता है कि आप एक बिटकॉइन कोर नोड सेट करें और `ऑर्ड` " +"सॉफ़्टवेयर संचालित करें, सुरक्षित तरीके से स्पैरो वॉलेट से इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्रेषित करने के कुछ " +"सीमित तरीके हैं। कृपया ध्यान रखें कि यह अनुशंसित नहीं किया जाता, और आपको यह केवल तभी करना " +"चाहिए जब आप पूरी तरह से समझें कि आप क्या कर रहे हैं।" + +#: src/guides/collecting/sparrow-wallet.md:103 +msgid "" +"Using the `ord` software will remove much of the complexity we are " +"describing here, as it is able to automatically and safely handle sending " +"inscriptions in an easy way." +msgstr "" +"`ऑर्ड` सॉफ़्टवेयर का उपयोग करने से हम यहां जो जटिलता वर्णन कर रहे हैं, उसका बहुत सारा हिस्‍सा निकाल देगा, " +"क्‍योंकि यह स्वच्‍छंद तरीके से इंस्‍क्रीप्‍शंस भेजने का काम स्‍वत: और सुरक्षित तरीके से कर सकता है।" + +#: src/guides/collecting/sparrow-wallet.md:105 +msgid "⚠️⚠️ Additional Warning ⚠️⚠️" +msgstr "⚠️⚠️ अतिरिक्‍त चेतावनी ⚠️⚠️" + +#: src/guides/collecting/sparrow-wallet.md:106 +msgid "" +"Don't use your sparrow inscriptions wallet to do general sends of non-" +"inscription bitcoin. You can setup a separate wallet in sparrow if you need " +"to do normal bitcoin transactions, and keep your inscriptions wallet " +"separate." +msgstr "" +"गैर-इंस्‍क्रीप्‍शंस बिटकॉईन के सामान्‍य प्रे‍षण के लिए स्पैरो इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) वॉलेट का प्रयोग " +"मत करो। आप स्‍पैरो में अलग वॉलेट सेट कर सकते हैं यदि आपको सामान्‍य बिटकॉईन लेनदेन करने की " +"आवश्‍यकता है, और अपना इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) वॉलेट अलग रख सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:108 +msgid "Bitcoin's UTXO model" +msgstr "बिटकॉइन का UTXO मॉडल" + +#: src/guides/collecting/sparrow-wallet.md:109 +msgid "" +"Before sending any transaction it's important that you have a good mental " +"model for bitcoin's Unspent Transaction Output (UTXO) system. The way " +"Bitcoin works is fundamentally different to many other blockchains such as " +"Ethereum. In Ethereum generally you have a single address in which you store " +"ETH, and you cannot differentiate between any of the ETH - it is just all a " +"single value of the total amount in that address. Bitcoin works very " +"differently in that we generate a new address in the wallet for each " +"receive, and every time you receive sats to an address in your wallet you " +"are creating a new UTXO. Each UTXO can be seen and managed individually. You " +"can select specific UTXO's which you want to spend, and you can choose not " +"to spend certain UTXO's." +msgstr "" +"कोई भी लेन-देन प्रेषित करने से पहले यह अत्‍यंत महत्वपूर्ण हो जाता है कि आपके पास बिटकॉइन के अनस्पेंट " +"ट्रांजेक्शन आउटपुट (UTXO) सिस्टम का एक अच्छे मानसिक अवस्‍था का मॉडल हो। बिटकॉइन के काम करने " +"का तरीका एथेरियम जैसे कई अन्य ब्लॉकचेन से मौलिक रूप से भिन्न है। एथेरियम में आम तौर पर आपके पास " +"एक ही पता होता है जिसमें आप ईटीएच संग्रहीत करते हैं, और आप किसी भी ईटीएच के बीच अंतर नहीं कर " +"सकते हैं - यह उस पते पर कुल राशि का केवल एकमात्र एक ही मूल्य होता है। बिटकॉइन बहुत अलग तरीके से " +"काम करता है, इसमें हम प्रत्येक प्राप्ति के लिए वॉलेट में एक नया पता बनाते हैं, और हर बार अपने वॉलेट में " +"किसी पते पर सैट प्राप्त करते हैं तो इसका सीधा और स्‍पष्‍ट अर्थ यह है कि उस समय आप एक नया UTXO बना " +"रहे होते हैं। प्रत्येक UTXO को व्यक्तिगत रूप से देखा और प्रबंधित किया जा सकता है। आप किसी विशिष्ट " +"यूटीएक्सओ का चयन कर सकते हैं जिसे आप खर्च करना चाहते हैं, इसके प्रतिकूल आप कुछ यूटीएक्स को खर्च न " +"करने का विकल्प चयन कर सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:111 +msgid "" +"Some Bitcoin wallets do not expose this level of detail, and they just show " +"you a single summed up value of all the bitcoin in your wallet. However, " +"when sending inscriptions it is important that you use a wallet like Sparrow " +"which allows for UTXO control." +msgstr "" +"कुछ बिटकॉइन वॉलेट इस स्तर के विवरण प्रकट नहीं करते, और वे आपको केवल आपके वॉलेट में सभी बिटकॉइन " +"के कुल मूल्य का सारांश प्रकट करते हैं। हालाँकि, इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्रेषित करते समय यह महत्वपूर्ण " +"है कि आप स्पैरो जैसे वॉलेट का उपयोग करें जो UTXO नियंत्रण की अनुमति देता है।" + + +#: src/guides/collecting/sparrow-wallet.md:113 +msgid "Inspecting your inscription before sending" +msgstr "इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) प्रेषण से पहले अपने उनका निरीक्षण" + +#: src/guides/collecting/sparrow-wallet.md:114 +msgid "" +"Like we have previously described inscriptions are inscribed onto sats, and " +"sats are stored within UTXOs. UTXO's are a collection of satoshis with some " +"particular value of the number of satoshis (the output value). Usually (but " +"not always) the inscription will be inscribed on the first satoshi in the " +"UTXO." +msgstr "" +"जैसा कि हम पहले उल्‍लेख कर चुके हैं कि इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) सैट्स पर उत्‍कीर्ण/अंकित किए जाते " +"हैं, और सैट्स यूटीएक्सओ के भीतर संग्रहीत होते हैं। यूटीएक्सओ, सातोशी की संख्या (आउटपुट मूल्य) के कुछ " +"विशेष मूल्य के साथ सातोशी का एक संग्रह है। आमतौर पर (लेकिन हमेशा नहीं) इंस्‍क्रीप्‍शंस (डिजिटल " +"अभिलेख) यूटीएक्सओ के पहले सातोशी पर उत्‍कीर्ण/अंकित किए जाएंगे।" + +#: src/guides/collecting/sparrow-wallet.md:116 +msgid "" +"When inspecting your inscription before sending the main thing you will want " +"to check is which satoshi in the UTXO your inscription is inscribed on." +msgstr "" +"जब आप इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) का प्रेषण से पहले निरीक्षण करते हैं,उस समय आप सबसे पहले " +"यह जांचना चाहेंगे कि किस यूटीएक्सओ के सातोषी में आपका इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) उत्‍कीर्ण/अंकित " +"किए गये है।" + + +#: src/guides/collecting/sparrow-wallet.md:118 +msgid "" +"To do this, you can follow the [Validating / Viewing Received Inscriptions]" +"(./sparrow-wallet.md#validating--viewing-received-inscriptions) described " +"above to find the inscription page for your inscription on ordinals.com" +msgstr "" +"इसे करने के लिए, आप ordinals.com पर ऊपर उल्लिखित [Validating / Viewing Received" +"Inscriptions](./sparrow-wallet.md#validating--viewing-received-inscriptions) " +"का अनुसरण करके अपने इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) के लिए पृष्ठ खोज सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:120 +msgid "" +"There you will find some metadata about your inscription which looks like " +"the following:" +msgstr "" +"वहां पर आपको अपने इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) के बारे में कुछ मेटाडेटा मिलेंगे जो निम्नलिखित " +"जैसे दिखाई देते हैं:" + +#: src/guides/collecting/sparrow-wallet.md:122 +msgid "![](images/sending_01.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:124 +msgid "There is a few of important things to check here:" +msgstr "यहां जांचने योग्य कुछ महत्वपूर्ण तथ्‍य हैं:" + +#: src/guides/collecting/sparrow-wallet.md:125 +msgid "" +"The `output` identifier matches the identifier of the UTXO you are going to " +"send" +msgstr "`Output` आईडेंटिफॉयर (अभिज्ञापक) उस UTXO के उस अभिज्ञापक के अनुकूल है जिसे आप प्रेषित " +"करने जा रहे हैं" + +#: src/guides/collecting/sparrow-wallet.md:126 +msgid "" +"The `offset` of the inscription is `0` (this means that the inscription is " +"located on the first sat in the UTXO)" +msgstr "" +"इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) का `offset` `0` है (इसका अर्थ यह है कि इंस्‍क्रीप्‍शंस UTXO में " +"पहले सैट पर स्थित है)" + +#: src/guides/collecting/sparrow-wallet.md:127 +msgid "" +"the `output_value` has enough sats to cover the transaction fee (postage) " +"for sending the transaction. The exact amount you will need depends on the " +"fee rate you will select for the transaction" +msgstr "" +"`output_value` में लेनदेन प्रेषण हेतु लेनदेन शुल्क (डाक शुल्क) समावेश करने के लिए पर्याप्त सैट्स हैं। " +"आपको जिस समुचि‍त राशि की आवश्यकता होगी वह उस शुल्क दर पर निर्भर करती है जिसका चयन आप लेनदेन " +"के लिए करेंगे।" + +#: src/guides/collecting/sparrow-wallet.md:129 +msgid "" +"If all of the above are true for your inscription, it should be safe for you " +"to send it using the method below." +msgstr "" +"यदि उपरोक्त सभी तथ्‍य आपके इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) के लिए सही हैं, तब इसे नीचे दी गई विधि " +"का उपयोग करके प्रेषण आपके लिए सुरक्षित होगा।" + + +#: src/guides/collecting/sparrow-wallet.md:131 +msgid "" +"⚠️⚠️ Be very careful sending your inscription particularly if the `offset` " +"value is not `0`. It is not recommended to use this method if that is the " +"case, as doing so you could accidentally send your inscription to a bitcoin " +"miner unless you know what you are doing." +msgstr "" +"⚠️⚠️ अपना इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) प्रेषण करने में बहुत सावधानी बरतें, खासकर यदि `offset` मान " +"`0` नहीं है। यदि ऐसा मामला है तो इस पद्धति का उपयोग करने की सिफारिश नहीं की जाती, क्योंकि ऐसा करने " +"से आप गलती से अपना इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) बिटकॉइन माइनर को भेज सकते हैं जब तक कि आप नहीं " +"जानते कि आप क्या कर रहे हैं।" + + +#: src/guides/collecting/sparrow-wallet.md:133 +msgid "Sending your inscription" +msgstr "अपना इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) प्रेषित करना" + +#: src/guides/collecting/sparrow-wallet.md:134 +msgid "" +"To send an inscription navigate to the `UTXOs` tab, and find the UTXO which " +"you previously validated contains your inscription." +msgstr "" +"इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) प्रेषित करने के लिए `UTXOs` टैब पर जाएं, और उस UTXO की खोज करें " +"जिसे आपने पहले प्रमाणित किया था जिसमें आपका इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) शामिल है।" + +#: src/guides/collecting/sparrow-wallet.md:136 +msgid "" +"If you previously froze the UXTO you will need to right-click on it and " +"unfreeze it." +msgstr "" +"यदि आपने पहले UTXOs को फ़्रीज़ कर दिया था तो आपको उस पर राइट-क्लिक करके फ़्रीज़ " +"को निष्क्रिय करना होगा।" + +#: src/guides/collecting/sparrow-wallet.md:138 +msgid "" +"Select the UTXO you want to send, and ensure that is the _only_ UTXO is " +"selected. You should see `UTXOs 1/1` in the interface. Once you are sure " +"this is the case you can hit `Send Selected`." +msgstr "" +"उस UTXO का चयन करें जिसे आप प्रेषित करना चाहते हैं, और सुनिश्चित करें कि _केवल_ उसी UTXO का ही " +"चयन किया गया है। आपको इंटरफ़ेस में `UTXOs 1/1` देखना चाहिए। एक बार जब आप आश्वस्त हो जाते हैं " +"कि ऐसा मामला है तब आप `Send Selected` पर क्लिक कर सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:140 +msgid "![](images/sending_02.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:142 +msgid "" +"You will then be presented with the transaction construction interface. " +"There is a few things you need to check here to make sure that this is a " +"safe send:" +msgstr "" +"इसके बाद आपको लेनदेन निर्माण इंटरफ़ेस प्रस्तुत किया जाएगा। सुरक्षित प्रेषण सुनिश्चित करने के लिए " +"आपको यहां कुछ तथ्‍य की जांच करने की आवश्यकता होगी:" + +#: src/guides/collecting/sparrow-wallet.md:144 +msgid "" +"The transaction should have only 1 input, and this should be the UTXO with " +"the label you want to send" +msgstr "" +"लेन-देन में केवल 1 इनपुट होनी चाहिए, और यह उस लेबल के साथ UTXO होना चाहिए जिसका आप " +"प्रेषण करना चाहते हैं। " + +#: src/guides/collecting/sparrow-wallet.md:145 +msgid "" +"The transaction should have only 1 output, which is the address/label where " +"you want to send the inscription" +msgstr "" +"लेन-देन में केवल 1 आउटपुट होना चाहिए, जो कि पता/लेबल है जहां आप इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) " +"प्रेषि‍त करना चाहते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:147 +msgid "" +"If your transaction looks any different, for example you have multiple " +"inputs, or multiple outputs then this may not be a safe transfer of your " +"inscription, and you should abandon sending until you understand more, or " +"can import into the `ord` wallet." +msgstr "" +"यदि आपका लेनदेन कुछ अलग तरह का दिखाई देता है, उदाहरण के लिए आपके पास एक से अधिक इनपुट, " +"या एक से अधिक आउटपुट हैं तो यह आपके इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) का सुरक्षित हस्तांतरण नहीं हो सकता " +"है, और जब तक आप इसे अच्‍छे से समझ नहीं लेते, या ऑर्ड वॉलेट में इंपोर्ट नहीं कर लेते, तब तक आपको " +"इसे प्रेषित करने से बचना चाहिए।" + +#: src/guides/collecting/sparrow-wallet.md:149 +msgid "" +"You should set an appropriate transaction fee, Sparrow will usually " +"recommend a reasonable one, but you can also check [mempool.space](https://" +"mempool.space) to see what the recommended fee rate is for sending a " +"transaction." +msgstr "" +"आपको एक उचित लेनदेन शुल्क निर्धारित करना चाहिए, स्पैरो आमतौर पर उचित शुल्क की अनुशंसा करेगा, " +लेकिन लेनदेन प्रेषित करने के लिए अनुशंसित शुल्क दर क्या होगा इसकी जांच करने के लिए आप " +[mempool.space](https://mempool.space) पर देख सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:151 +msgid "" +"You should add a label for the recipient address, a label like `alice " +"address for inscription #123` would be ideal." +msgstr "" +"आपको प्राप्तकर्ता के पते के लिए एक लेबल जोड़ना चाहिए, `alice address for inscription #123` " +"जैसा लेबल इष्‍टतम होगा।" + +#: src/guides/collecting/sparrow-wallet.md:153 +msgid "" +"Once you have checked the transaction is a safe transaction using the checks " +"above, and you are confident to send it you can click `Create Transaction`." +msgstr "" +"एक बार जब आप ऊपर दिये गये जांच पैमानों का उपयोग करके जाँच लेते हैं कि लेन-देन एक सुरक्षित लेन-देन है, " +"और आप इसे प्रेषित करने के लिए आश्वस्त हैं तो आप लेन-देन को अंतिम रूप देने के लिए `Create Transaction` " +"पर क्लिक कर सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:155 +msgid "![](images/sending_03.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:157 +msgid "" +"Here again you can double check that your transaction looks safe, and once " +"you are confident you can click `Finalize Transaction for Signing`." +msgstr "" +"दुबारा आप नये सिरे से जांच कर सकते हैं कि आपका लेन-देन एक सुरक्षित लेन-देन है, एक बार जब " +"आप आश्‍वस्‍त हो जाते हैं तब आप `Finalize Transaction for Signing` पर क्लिक कर सकते हैं।" + + +#: src/guides/collecting/sparrow-wallet.md:159 +msgid "![](images/sending_04.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:161 +msgid "Here you can triple check everything before hitting `Sign`." +msgstr "यहां आप साइन दबाने से पहले हर तथ्‍य की तीन बार जांच कर सकते हैं।" + +#: src/guides/collecting/sparrow-wallet.md:163 +msgid "![](images/sending_05.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:165 +msgid "" +"And then actually you get very very last chance to check everything before " +"hitting `Broadcast Transaction`. Once you broadcast the transaction it is " +"sent to the bitcoin network, and starts being propagated into the mempool." +msgstr "" +"और फिर वास्तव में आपको `Broadcast Transaction` करने से पहले सब कुछ जांचने का आखिरी मौका " +"मिलता है। एक बार जब आप लेनदेन प्रसारित करते हैं तो इसे बिटकॉइन नेटवर्क पर प्रेषित किया जाता है, और " +"mempool में प्रसारित किया जाना शुरू हो जाता है।" + +#: src/guides/collecting/sparrow-wallet.md:167 +msgid "![](images/sending_06.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:169 +msgid "" +"If you want to track the status of your transaction you can copy the " +"`Transaction Id (Txid)` and paste that into [mempool.space](https://mempool." +"space)" +msgstr "" +"यदि आप अपने लेन-देन की स्थिति को ट्रैक करना चाहते हैं तो आप Transaction Id (Txid) " +"की प्रतिलिपि बना सकते हैं और उसे [mempool.space](https://mempool.space) में पेस्ट कर सकते हैं" + +#: src/guides/collecting/sparrow-wallet.md:171 +msgid "" +"Once the transaction has confirmed you can check the inscription page on " +"[ordinals.com](https://ordinals.com) to validate that it has moved to the " +"new output location and address." +msgstr "" +"जब लेनदेन की पुष्टि हो गई है, तो आप [ordinals.com](https://ordinals.com) पर इंस्क्रिप्शन " +"पृष्ठ की जाँच कर सकते हैं ताकि यह नए आउटपुट स्थान और पते पर स्थानांतरित हुआ है।" + +#: src/guides/collecting/sparrow-wallet.md:173 +msgid "Troubleshooting" +msgstr "समस्या सुलझाना" + +#: src/guides/collecting/sparrow-wallet.md:175 +msgid "" +"Sparrow wallet is not showing a transaction/UTXO, but I can see it on " +"mempool.space!" +msgstr "" +"स्पैरो वॉलेट transaction/UTXO नहीं दर्शा रहा है, लेकिन मैं इसे mempool.space पर देख सकता हूँ!" + +#: src/guides/collecting/sparrow-wallet.md:177 +msgid "" +"Make sure that your wallet is connected to a bitcoin node. To validate this, " +"head into the `Preferences`\\-> `Server` settings, and click `Edit Existing " +"Connection`." +msgstr "" +"सुनिश्चित करें कि आपका वॉलेट बिटकॉइन नोड से जुड़ा हुआ है। इसे प्रमाणित करने के लिए, +"`Preferences-> Server` सेटिंग्स पर जाएँ, और `Edit Existing Connection` पर क्लिक करें।" + + +#: src/guides/collecting/sparrow-wallet.md:179 +msgid "![](images/troubleshooting_01.png)" +msgstr "" + +#: src/guides/collecting/sparrow-wallet.md:181 +msgid "" +"From there you can select a node and click `Test Connection` to validate " +"that Sparrow is able to connect successfully." +msgstr "" +"वहां से आप एक नोड का चयन कर सकते हैं और यह प्रमाणित करने के लिए `Test Connection` पर क्लिक " +"कर सकते हैं कि स्पैरो सफलतापूर्वक जुड़ने में सक्षम है।" + +#: src/guides/collecting/sparrow-wallet.md:183 +msgid "![](images/troubleshooting_02.png)" +msgstr "" + +#: src/guides/testing.md:4 +msgid "" +"Ord can be tested using the following flags to specify the test network. For " +"more information on running Bitcoin Core for testing, see [Bitcoin's " +"developer documentation](https://developer.bitcoin.org/examples/testing." +"html)." +msgstr "" +"परीक्षण नेटवर्क को निर्दिष्ट करने के लिए ऑर्ड का परीक्षण निम्नलिखित फ़्लैग का उपयोग करके किया जा " +"सकता है। परीक्षण के लिए बिटकॉइन कोर संचालित करने के बारे में अधिक जानकारी के लिए, बिटकॉइन के " +"डेवलपर दस्तावेज़ देखें। [Bitcoin's developer documentation](https://developer.bitcoin.org" +"/examples/testing.html)." + +#: src/guides/testing.md:7 +msgid "" +"Most `ord` commands in [inscriptions](inscriptions.md) and [explorer]" +"(explorer.md) can be run with the following network flags:" +msgstr "" +"[इंस्‍क्रीप्‍शंस](inscriptions.md) और [एक्सप्लोरर](explorer.md) में अधिकांश `ऑर्ड` कमांड " +"निम्नलिखित नेटवर्क फ़्लैग के साथ संचालित किए जा सकते हैं:" + +#: src/guides/testing.md:10 +msgid "Network" +msgstr "नेटवर्क" + +#: src/guides/testing.md:10 +msgid "Flag" +msgstr "फ़्लैग" + +#: src/guides/testing.md:12 +msgid "Testnet" +msgstr "" + +#: src/guides/testing.md:12 +msgid "`--testnet` or `-t`" +msgstr "" + +#: src/guides/testing.md:13 +msgid "Signet" +msgstr "" + +#: src/guides/testing.md:13 +msgid "`--signet` or `-s`" +msgstr "" + +#: src/guides/testing.md:14 +msgid "Regtest" +msgstr "" + +#: src/guides/testing.md:14 +msgid "`--regtest` or `-r`" +msgstr "" + +#: src/guides/testing.md:16 +msgid "Regtest doesn't require downloading the blockchain or indexing ord." +msgstr "" +"Regtest के लिए ब्लॉकचेन या इंडेक्सिंग ऑर्ड डाउनलोड करने की आवश्यकता नहीं है।" + +#: src/guides/testing.md:21 +msgid "Run bitcoind in regtest with:" +msgstr "Regtest में bitcoind के साथ संचालित करें:" + +#: src/guides/testing.md:22 +msgid "" +"```\n" +"bitcoind -regtest -txindex\n" +"```" +msgstr "" + +#: src/guides/testing.md:25 +msgid "Create a wallet in regtest with:" +msgstr "regtest में इसके साथ एक वॉलेट बनाएं:" + +#: src/guides/testing.md:26 +msgid "" +"```\n" +"ord -r wallet create\n" +"```" +msgstr "" + +#: src/guides/testing.md:29 +msgid "Get a regtest receive address with:" +msgstr "इसके साथ regtest रिसीव पता प्राप्‍त करें:" + +#: src/guides/testing.md:30 +msgid "" +"```\n" +"ord -r wallet receive\n" +"```" +msgstr "" + +#: src/guides/testing.md:33 +msgid "Mine 101 blocks (to unlock the coinbase) with:" +msgstr "इसके साथ 101 ब्‍लॉक (कॉइनबेस को अनलॉक करने के लिए) खनन करें:" + +#: src/guides/testing.md:34 +msgid "" +"```\n" +"bitcoin-cli generatetoaddress 101 \n" +"```" +msgstr "" + +#: src/guides/testing.md:37 +msgid "Inscribe in regtest with:" +msgstr "regtest में इसके साथ उत्‍कीर्ण करें:" + +#: src/guides/testing.md:38 +msgid "" +"```\n" +"ord -r wallet inscribe --fee-rate 1 \n" +"```" +msgstr "" + +#: src/guides/testing.md:41 +msgid "Mine the inscription with:" +msgstr "इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) में इसके साथ खनन करें:" + +#: src/guides/testing.md:42 +msgid "" +"```\n" +"bitcoin-cli generatetoaddress 1 \n" +"```" +msgstr "" + +#: src/guides/testing.md:45 +msgid "View the inscription in the regtest explorer:" +msgstr "regtest एक्‍सप्‍लोर में इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) देखें:" + +#: src/guides/testing.md:46 +msgid "" +"```\n" +"ord -r server\n" +"```" +msgstr "" + +#: src/guides/testing.md:50 +msgid "Testing Recursion" +msgstr "टेस्टिंग रिकर्सन (परीक्षण प्रत्‍यावर्तन)" + +#: src/guides/testing.md:53 +msgid "" +"When testing out [recursion](../inscriptions/recursion.md), inscribe the " +"dependencies first (example with [p5.js](https://p5js.org)):" +msgstr "" +" [रिकर्सन](../inscriptions/recursion.md) का परीक्षण करते समय, पहले संभावी परिसम्‍पत्ति को " +"उत्‍कीर्ण करें (example with [p5.js](https://p5js.org)):" + +#: src/guides/testing.md:55 +msgid "" +"```\n" +"ord -r wallet inscribe --fee-rate 1 p5.js\n" +"```" +msgstr "" + +#: src/guides/testing.md:58 +msgid "" +"This should return a `inscription_id` which you can then reference in your " +"recursive inscription." +msgstr "" +"इसे एक `inscription_id` लौटाना चाहिए जिसका संदर्भ का उल्‍लेख आप अपने पुनरावर्ती " +"इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) में कर सकते हैं।" + +#: src/guides/testing.md:61 +msgid "" +"ATTENTION: These ids will be different when inscribing on mainnet or signet, " +"so be sure to change those in your recursive inscription for each chain." +msgstr "" +"ध्यान दें: ये आईडी अलग-अलग होंगी, जब आप मेननेट या सिग्नेट पर उत्‍कीर्ण करते हैं, इसलिए प्रत्येक " +"श्रृंखला के लिए अपने पुनरावर्ती इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) में इन्हें बदलना सुनिश्चित करें।" + +#: src/guides/testing.md:65 +msgid "Then you can inscribe your recursive inscription with:" +msgstr "उसके बाद आप अपना पुनरावर्ती इंस्‍क्रीप्‍शन (डिजिटल अभिलेख) इसके साथ उत्‍कीर्ण कर सकते हैं:" + +#: src/guides/testing.md:66 +msgid "" +"```\n" +"ord -r wallet inscribe --fee-rate 1 recursive-inscription.html\n" +"```" +msgstr "" + +#: src/guides/testing.md:69 +msgid "Finally you will have to mine some blocks and start the server:" +msgstr "" +"अंत में आपको कुछ ब्लॉक खनन करने होंगे और उसके बाद ही सर्वर शुरू करना होगा:" + +#: src/guides/testing.md:70 +msgid "" +"```\n" +"bitcoin-cli generatetoaddress 6 \n" +"ord -r server\n" +"```" +msgstr "" + +#: src/guides/moderation.md:4 +msgid "" +"`ord` includes a block explorer, which you can run locally with `ord server`." +msgstr "" +"`ऑर्ड` में एक ब्लॉक एक्सप्लोरर शामिल है, जिसे आप `ord server` के साथ स्थानीय रूप से चला सकते हैं।" + +#: src/guides/moderation.md:6 +msgid "" +"The block explorer allows viewing inscriptions. Inscriptions are user-" +"generated content, which may be objectionable or unlawful." +msgstr "" +"ब्लॉक एक्सप्लोरर इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) देखने में सक्षम करता है। इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) " +"उपयोगकर्ता-जनित विषय-व्‍स्‍तु है, जो आपत्तिजनक या गैरकानूनी हो सकती है।" + +#: src/guides/moderation.md:9 +msgid "" +"It is the responsibility of each individual who runs an ordinal block " +"explorer instance to understand their responsibilities with respect to " +"unlawful content, and decide what moderation policy is appropriate for their " +"instance." +msgstr "" +"ऑर्डिनल ब्लॉक एक्सप्लोरर के मामले संचालित करने वाले हर व्यक्ति की यह नैतिक जिम्मेदारी कि वह " +"गैरकानूनी सामग्री के संबंध में अपनी जिम्मेदारियों को बखूबी समझे और यह तय करे कि कथित मामलों के लिए " +"कौन सी मॉडरेशन नीति उपयुक्त है।" + +#: src/guides/moderation.md:13 +msgid "" +"In order to prevent particular inscriptions from being displayed on an `ord` " +"instance, they can be included in a YAML config file, which is loaded with " +"the `--config` option." +msgstr "" +"किसी `ऑर्ड` घटनाओं पर विशेष इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) के प्रदर्शन रोकने के लिए, जो YAML कॉन्फ़िगरेशन " +"फ़ाइल में शामिल किये जा सकते हैं, जिन्‍हें `--config` option के साथ लोड किया गया है।" + +#: src/guides/moderation.md:17 +msgid "" +"To hide inscriptions, first create a config file, with the inscription ID " +"you want to hide:" +msgstr "" +"इंस्‍क्रीप्‍शंस (डिजिटल अभिलेखों) छिपाने के लिए, उस इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) आईडी के साथ " +"पहले एक कॉन्फ़िगरेशन फ़ाइल बनाएं जिसे आप छिपाना चाहते हैं:" + +#: src/guides/moderation.md:20 +msgid "" +"```yaml\n" +"hidden:\n" +"- 0000000000000000000000000000000000000000000000000000000000000000i0\n" +"```" +msgstr "" + +#: src/guides/moderation.md:25 +msgid "" +"The suggested name for `ord` config files is `ord.yaml`, but any filename " +"can be used." +msgstr "" +"`Ord` कॉन्फिगर फ़ाइलों के लिए अनुशंसित नाम `ord.yaml` है, लेकिन किसी भी फ़ाइल " +"नाम का उपयोग किया जा सकता है।" + + +#: src/guides/moderation.md:28 +msgid "Then pass the file to `--config` when starting the server:" +msgstr "फिर सर्वर प्रारंभ करते समय फ़ाइल को `--config` पर पास कर दें:" + +#: src/guides/moderation.md:30 +msgid "`ord --config ord.yaml server`" +msgstr "" + +#: src/guides/moderation.md:32 +msgid "" +"Note that the `--config` option comes after `ord` but before the `server` " +"subcommand." +msgstr "" +"ध्यान दें कि `--config` विकल्प `ऑर्ड` के बाद लेकिन `सर्वर` सबकमांड से पहले आता है।" + +#: src/guides/moderation.md:35 +msgid "`ord` must be restarted in to load changes to the config file." +msgstr "" +"`ऑर्ड` को कॉन्फिग फ़ाइल में परिवर्तन लोड करने के लिए पुनः आरंभ करना चाहिए।" + +#: src/guides/moderation.md:37 +msgid "`ordinals.com`" +msgstr "" + +#: src/guides/moderation.md:40 +msgid "" +"The `ordinals.com` instances use `systemd` to run the `ord server` service, " +"which is called `ord`, with a config file located at `/var/lib/ord/ord.yaml`." +msgstr "" +"`Ordinals.com` घटनाएं `ord server` सेवा संचालित करने के लिए `/var/lib/ord/ord.yaml` " +"पर स्थित कॉन्फिगर फ़ाइल के साथ `systemd` का उपयोग करते हैं, जिन्‍हें ऑर्ड कहते हैं।" + +#: src/guides/moderation.md:43 +msgid "To hide an inscription on `ordinals.com`:" +msgstr "`Ordinals.com` पर एक इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) छिपाना:" + +#: src/guides/moderation.md:45 +msgid "SSH into the server" +msgstr "सर्वर के भीतर SSH" + +#: src/guides/moderation.md:46 +msgid "Add the inscription ID to `/var/lib/ord/ord.yaml`" +msgstr " इंस्‍क्रीप्‍शंस (डिजिटल अभिलेख) आईडी को `/var/lib/ord/ord.yaml` में जोड़ें" + +#: src/guides/moderation.md:47 +msgid "Restart the service with `systemctl restart ord`" +msgstr "`systemctl restart ord` के साथ सेवा को दुबारा स्‍टार्ट करें" + +#: src/guides/moderation.md:48 +msgid "Monitor the restart with `journalctl -u ord`" +msgstr "`journalctl -u ord` के साथ दुबारा स्‍टार्ट करने की निगरानी करें" + +#: src/guides/moderation.md:50 +msgid "" +"Currently, `ord` is slow to restart, so the site will not come back online " +"immediately." +msgstr "" +"वर्तमान में, `ऑर्ड` दुबारा स्‍टार्ट करने में धीमा है, इसलिए साइट तुरंत ऑनलाइन कनेक्‍ट नहीं होगी।" + +#: src/guides/reindexing.md:4 +msgid "" +"Sometimes the `ord` database must be reindexed, which means deleting the " +"database and restarting the indexing process with either `ord index update` or " +"`ord server`. Reasons to reindex are:" +msgstr "" +"कभी-कभी `ऑर्ड` डेटाबेस का पुन: अनुक्रमण किया जाना चाहिए, जिसका अर्थ डेटाबेस को हटाना " +"`ord index update` या `ord server` पर अनुक्रमण की प्रक्रिया को दुबारा शुरू करना है। " +"पुनः अनुक्रमणिका करने के निम्‍न कारण हैं:" + +#: src/guides/reindexing.md:8 +msgid "A new major release of ord, which changes the database scheme" +msgstr "" +"ऑर्ड का एक नया प्रमुख संस्‍करण, जो डेटाबेस की योजना को बदल देता है" + +#: src/guides/reindexing.md:9 +msgid "The database got corrupted somehow" +msgstr "डेटाबेस किसी तरह अनुपयोगी हो जाता है" + +#: src/guides/reindexing.md:11 +msgid "" +"The database `ord` uses is called [redb](https://github.com/cberner/redb), " +"so we give the index the default file name `index.redb`. By default we store " +"this file in different locations depending on your operating system." +msgstr "" +"`ऑर्ड` डेटाबेस के उपयोग को [redb](https://github.com/cberner/redb) कहा जाता है, " +"इसलिए हम इंडेक्स को डिफ़ॉल्ट फ़ाइल नाम `index.redb` कर देते हैं। डिफ़ॉल्ट रूप से हम इस फ़ाइल " +"को आपके ऑपरेटिंग सिस्टम के आधार पर विभिन्न स्थानों पर संग्रहीत करते हैं।" + + +#: src/guides/reindexing.md:15 +msgid "Platform" +msgstr "प्लेटफार्म" + +#: src/guides/reindexing.md:15 +msgid "Value" +msgstr "मूल्य" + +#: src/guides/reindexing.md:17 +msgid "Linux" +msgstr "" + +#: src/guides/reindexing.md:17 +msgid "`$XDG_DATA_HOME`/ord or `$HOME`/.local/share/ord" +msgstr "" + +#: src/guides/reindexing.md:17 +msgid "/home/alice/.local/share/ord" +msgstr "" + +#: src/guides/reindexing.md:18 +msgid "macOS" +msgstr "" + +#: src/guides/reindexing.md:18 +msgid "`$HOME`/Library/Application Support/ord" +msgstr "" + +#: src/guides/reindexing.md:18 +msgid "/Users/Alice/Library/Application Support/ord" +msgstr "" + +#: src/guides/reindexing.md:19 +msgid "Windows" +msgstr "" + +#: src/guides/reindexing.md:19 +msgid "`{FOLDERID_RoamingAppData}`\\\\ord" +msgstr "" + +#: src/guides/reindexing.md:19 +msgid "C:\\Users\\Alice\\AppData\\Roaming\\ord" +msgstr "" + +#: src/guides/reindexing.md:21 +msgid "" +"So to delete the database and reindex on MacOS you would have to run the " +"following commands in the terminal:" +msgstr "" +"इसलिए MacOS पर डेटाबेस और रिइंडेक्‍स (पुन: अनुक्रमण) को हटाने के लिए आपको टर्मिनल में " +"निम्नलिखित कमांड संचालित करनी होंगी:" + +#: src/guides/reindexing.md:24 +msgid "" +"```bash\n" +"rm ~/Library/Application Support/ord/index.redb\n" +"ord index update\n" +"```" +msgstr "" + +#: src/guides/reindexing.md:29 +msgid "" +"You can of course also set the location of the data directory yourself with " +"`ord --data-dir index update` or give it a specific filename and path " +"with `ord --index index update`." +msgstr "" +"आप निस्‍संदेह `ord --data-dir index update` के साथ डेटा निर्देशिका का स्थान स्वयं भी सेट " +"कर सकते हैं या इसे `ord --index index update` के साथ एक विशिष्ट फ़ाइल नाम और " +"पथ भी दे सकते हैं।" + + +#: src/bounties.md:1 +msgid "Ordinal Bounty Hunting Hints" +msgstr "ऑर्डिनल (क्रमसूचक संख्‍याएं) बाउंटी हंटिंग सलाहें" + +#: src/bounties.md:4 +msgid "" +"The `ord` wallet can send and receive specific satoshis. Additionally, " +"ordinal theory is extremely simple. A clever hacker should be able to write " +"code from scratch to manipulate satoshis using ordinal theory in no time." +msgstr "" +"`ऑर्ड` वॉलेट विशिष्ट सातोशी प्रेषित और प्राप्त कर सकता है। इसके अतिरिक्त, ऑर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) " +"बहुत आसान हैं। कोई भी चालाक हैकर ऑर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) का उपयोग करके सातोशी में तिकड़में " +"लगाकर स्क्रैच से कोड लिखने में सक्षम होना चाहिए।" + +#: src/bounties.md:8 +msgid "" +"For more information about ordinal theory, check out the [FAQ](./faq.md) for " +"an overview, the [BIP](https://github.com/ordinals/ord/blob/master/bip." +"mediawiki) for the technical details, and the [ord repo](https://github.com/" +"ordinals/ord) for the `ord` wallet and block explorer." +msgstr "" +"ऑर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) के बारे में विस्‍तृत जानकारी के लिए, अवलोकन के लिए [FAQ](./faq.md), " +"तकनीकी विवरणों के लिए [BIP](https://github.com/ordinals/ord/blob/master/bip." +"mediawiki), और `ऑर्ड` वॉलेट और ब्लॉक एक्सप्लोरर के लिए [ord repo](https://github.com/" +"ordinals/ord) देखें।" + +#: src/bounties.md:14 +msgid "" +"Satoshi was the original developer of ordinal theory. However, he knew that " +"others would consider it heretical and dangerous, so he hid his knowledge, " +"and it was lost to the sands of time. This potent theory is only now being " +"rediscovered. You can help by researching rare satoshis." +msgstr "" +"ऑर्डिनल थ्‍यौरी (क्रमसूचक सिद्धांत) मूल रूप से सातोशी द्वारा विकसित किए गये थे। हालाँकि, वह अच्‍छे से " +"जानते थे कि दूसरे लोग इसे अनधिकृत और खतरनाक मानेंगे, इसलिए उसने अपना ज्ञान छुपा दिया था, और " +"यह समय की गर्त में लुप्‍त हो गया था। इस शक्तिशाली सिद्धांत को अब फिर से खोजा जा रहा है। आप दुर्लभ " +"सातोशी पर शोध करके अपना योगदान और मदद कर सकते हैं।" + + +#: src/bounties.md:19 +msgid "Good luck and godspeed!" +msgstr "हार्दिक शुभकामनाएं और आपकी यह यात्रा सफल हो!" + +#: src/bounty/0.md:1 +msgid "Ordinal Bounty 0" +msgstr "ऑर्डिनल बाउंटी 0" + +#: src/bounty/0.md:4 src/bounty/1.md:4 src/bounty/2.md:4 src/bounty/3.md:4 +msgid "Criteria" +msgstr "मानदंड" + +#: src/bounty/0.md:7 +msgid "" +"Send a sat whose ordinal number ends with a zero to the submission address:" +msgstr "सबमिशन पते पर एक सैट प्रेषित करें जिसकी ऑर्डिनल (क्रमसूचक) संख्या शून्य के साथ समाप्त होती है:" + +#: src/bounty/0.md:9 +msgid "✅: [1857578125803250](https://ordinals.com/ordinal/1857578125803250)" +msgstr "" + +#: src/bounty/0.md:11 +msgid "❌: [1857578125803251](https://ordinals.com/ordinal/1857578125803251)" +msgstr "" + +#: src/bounty/0.md:13 +msgid "The sat must be the first sat of the output you send." +msgstr "सैट आपके द्वारा प्रेषित आउटपुट का पहला सैट होना चाहिए।" + +#: src/bounty/0.md:15 src/bounty/1.md:14 src/bounty/2.md:15 src/bounty/3.md:63 +msgid "Reward" +msgstr "पुरस्‍कार" + +#: src/bounty/0.md:18 +msgid "100,000 sats" +msgstr "100,000 सैट" + +#: src/bounty/0.md:20 src/bounty/1.md:19 src/bounty/2.md:20 src/bounty/3.md:70 +msgid "Submission Address" +msgstr "प्रस्‍तुति का पता" + +#: src/bounty/0.md:23 +msgid "" +"[`1PE7u4wbDP2RqfKN6geD1bG57v9Gj9FXm3`](https://mempool.space/" +"address/1PE7u4wbDP2RqfKN6geD1bG57v9Gj9FXm3)" +msgstr "" + +#: src/bounty/0.md:25 src/bounty/1.md:24 src/bounty/2.md:25 src/bounty/3.md:75 +msgid "Status" +msgstr "स्थिति" + +#: src/bounty/0.md:28 +msgid "" +"Claimed by [@count_null](https://twitter.com/rodarmor/" +"status/1560793241473400833)!" +msgstr "" +"[@count_null](https://twitter.com/rodarmor/status/1560793241473400833) " +"द्वारा दावा किया गया!" + +#: src/bounty/1.md:1 +msgid "Ordinal Bounty 1" +msgstr "ऑर्डिनल बाउंटी 1" + +#: src/bounty/1.md:7 +msgid "" +"The transaction that submits a UTXO containing the oldest sat, i.e., that " +"with the lowest number, amongst all submitted UTXOs will be judged the " +"winner." +msgstr "" +"लेन-देन जो सबसे पुराने सैट वाले यूटीएक्सओ को प्रस्‍तुत किया जाता है उसमें सबसे पुराना सैट है, अर्थात, " +"सभी प्रस्‍तुत किए गये यूटीएक्सओ के बीच सबसे न्‍यूनतम संख्या को विजेता के रूप में तय किया जाएगा। " + +#: src/bounty/1.md:10 +msgid "" +"The bounty is open for submissions until block 753984—the first block of " +"difficulty adjustment period 374. Submissions included in block 753984 or " +"later will not be considered." +msgstr "" +"बाउंटी ब्लॉक 753984 तक प्रस्‍तुति के लिए उन्‍मुक्‍त है - कठिन समायोजन अवधि 374 का पहला ब्लॉक है। " +"ब्लॉक 753984 या बाद में शामिल प्रस्‍तुति पर विचार नहीं किया जाएगा।" + +#: src/bounty/1.md:17 +msgid "200,000 sats" +msgstr "200,000 सैट" + +#: src/bounty/1.md:22 +msgid "" +"[`145Z7PFHyVrwiMWwEcUmDgFbmUbQSU9aap`](https://mempool.space/" +"address/145Z7PFHyVrwiMWwEcUmDgFbmUbQSU9aap)" +msgstr "" + +#: src/bounty/1.md:27 +msgid "" +"Claimed by [@ordinalsindex](https://twitter.com/rodarmor/" +"status/1569883266508853251)!" +msgstr "" +" [@ordinalsindex](https://twitter.com/rodarmor/status/1569883266508853251) " +"द्वारा दावा किया गया!" + +#: src/bounty/2.md:1 +msgid "Ordinal Bounty 2" +msgstr "ऑर्डिनल बाउंटी 2" + +#: src/bounty/2.md:7 +msgid "Send an " +msgstr "प्रस्‍तुति पते पर " + +#: src/bounty/2.md:7 +msgid "uncommon" +msgstr "एक असामान्य" + +#: src/bounty/2.md:7 +msgid " sat to the submission address:" +msgstr " सैट प्रेषित करें:" + +#: src/bounty/2.md:9 +msgid "✅: [347100000000000](https://ordinals.com/sat/347100000000000)" +msgstr "" + +#: src/bounty/2.md:11 +msgid "❌: [6685000001337](https://ordinals.com/sat/6685000001337)" +msgstr "" + +#: src/bounty/2.md:13 +msgid "" +"Confirm that the submission address has not received transactions before " +"submitting your entry. Only the first successful submission will be rewarded." +msgstr "" +"पुष्टि करें कि प्रस्‍तुति पते पर आपकी प्रविष्टि प्रस्‍तुत करने से पहले लेनदेन प्राप्त नहीं हुआ है। " +"केवल पहले सफल प्रस्तुतिकरण को ही पुरस्कृत किया जाएगा।" + +#: src/bounty/2.md:18 +msgid "300,000 sats" +msgstr "300,000 सैट" + +#: src/bounty/2.md:23 +msgid "" +"[`1Hyr94uypwWq5CQffaXHvwUMEyBPp3TUZH`](https://mempool.space/" +"address/1Hyr94uypwWq5CQffaXHvwUMEyBPp3TUZH)" +msgstr "" + +#: src/bounty/2.md:28 +msgid "" +"Claimed by [@utxoset](https://twitter.com/rodarmor/" +"status/1582424455615172608)!" +msgstr "" +"[@utxoset](https://twitter.com/rodarmor/status/1582424455615172608) " +"द्वारा दावा किया गया!" + +#: src/bounty/3.md:1 +msgid "Ordinal Bounty 3" +msgstr "ऑर्डिनल बाउंटी 3" + +#: src/bounty/3.md:7 +msgid "" +"Ordinal bounty 3 has two parts, both of which are based on _ordinal names_. " +"Ordinal names are a modified base-26 encoding of ordinal numbers. To avoid " +"locking short names inside the unspendable genesis block coinbase reward, " +"ordinal names get _shorter_ as the ordinal number gets _longer_. The name of " +"sat 0, the first sat to be mined is `nvtdijuwxlp` and the name of sat " +"2,099,999,997,689,999, the last sat to be mined, is `a`." +msgstr "" +"ऑर्डिनल बाउंटी 3 के दो भाग हैं, ये दोनों ऑर्डिनल (क्रमसूचक) नामों पर आधारित हैं। क्रमसूचक नाम, " +"क्रमसूचक संख्याओं की संशोधित मूल-26 एन्कोडिंग हैं। छोटे नामों को खर्च न किए जा सकने योग्‍य जेनेसिस " +"(उत्‍पति) कॉइनबेस इनाम रोकने के लिए, जैसे-जैसे ऑर्डिनल्स (क्रमसूचक) संख्‍याएं _लंबी_ होती हैं ऑर्डिनल्स " +"(क्रमसूचक) नाम _छोटे_ होते जाते हैं। सैट 0 का नाम, खनन किए जाने वाले पहले सैट का नाम `nvtdijuwxlp` " +"है और सैट का नाम 2,099,999,997,689,999 है, खनन किए जाने वाले अंतिम सैट `a` है। " + + +#: src/bounty/3.md:14 +msgid "" +"The bounty is open for submissions until block 840000—the first block after " +"the fourth halvening. Submissions included in block 840000 or later will not " +"be considered." +msgstr "" +"बांउटी, ब्लॉक 840000 तक प्रस्‍तुत करने के लिए उन्‍मुक्‍त है – जो चौथे पड़ाव (खनिकों को मिलने वाले पुरस्कारों " +"में एक योजनाबद्ध कटौती है। यह शब्द बिटकॉइन के कोड में उल्लिखित है) के बाद वाला पहला ब्लॉक है। " +"ब्लॉक 840000 या इसके बाद के संस्करण में शामिल प्रस्तुतियों पर विचार नहीं किया जाएगा।" + + +#: src/bounty/3.md:18 +msgid "" +"Both parts use [frequency.tsv](frequency.tsv), a list of words and the " +"number of times they occur in the [Google Books Ngram dataset](http://" +"storage.googleapis.com/books/ngrams/books/datasetsv2.html). filtered to only " +"include the names of sats which will have been mined by the end of the " +"submission period, that appear at least 5000 times in the corpus." +msgstr "" +"दोनों भाग [frequency.tsv](frequency.tsv), का उपयोग करते हैं, ये शब्दों की एक सूची है " +"जो [Google Books Ngram dataset](http://storage.googleapis.com/books/ngrams/" +"books/datasetsv2.html) में कितनी बार घटित हुए हैं उसकी संख्या का केवल उन सैटों के नाम शामिल " +"करने के लिए फ़िल्टर किये जाते हैं जिनकी प्रस्‍तुति अवधि के अंत तक खनन किया गया होगा, और जो कॉर्पस " +"में कम से कम 5000 बार दर्शाये गये हैं।" + +#: src/bounty/3.md:24 +msgid "" +"`frequency.tsv` is a file of tab-separated values. The first column is the " +"word, and the second is the number of times it appears in the corpus. The " +"entries are sorted from least-frequently occurring to most-frequently " +"occurring." +msgstr "" +"`frequency.tsv` टैब-पृथक करने वाले मानों की एक फ़ाइल है। पहला कॉलम शब्द है, और दूसरा कॉर्पस " +"में कितनी बार दिखाई दिया है। प्रविष्टियों को इस प्रकार से क्रमबद्ध किया जाता है बार-बार न्‍यूनतम से बार अधिकतम " +"घटित होने वाले क्रम में किया जाता है।" + +#: src/bounty/3.md:29 +msgid "" +"`frequency.tsv` was compiled using [this program](https://github.com/casey/" +"onegrams)." +msgstr "" +"`frequency.tsv` को [इस प्रोग्राम](https://github.com/casey/onegrams) " +"का उपयोग करके संकलित किया गया था।" + + +#: src/bounty/3.md:32 +msgid "" +"To search an `ord` wallet for sats with a name in `frequency.tsv`, use the " +"following [`ord`](https://github.com/ordinals/ord) command:" +msgstr "" +"`frequency.tsv` में नाम के साथ सैट्स के लिए एक `ऑर्ड` वॉलेट खोजने के लिए, " +"निम्नलिखित [`ord`](https://github.com/ordinals/ord) कमांड का उपयोग करें:" + +#: src/bounty/3.md:35 +msgid "" +"```\n" +"ord wallet sats --tsv frequency.tsv\n" +"```" +msgstr "" + +#: src/bounty/3.md:39 +msgid "" +"This command requires the sat index, so `--index-sats` must be passed to ord " +"when first creating the index." +msgstr "" +"इस कमांड के लिए सैट इंडेक्स की आवश्यकता होती है, इसलिए जब पहली बार इं‍डेक्‍स का सृजन किया " +"जाता है तो `--index-sats` को ord में पास किया जाना चाहिए।" + +#: src/bounty/3.md:42 +msgid "Part 0" +msgstr "भाग 0" + +#: src/bounty/3.md:44 +msgid "_Rare sats pair best with rare words._" +msgstr "_दुर्लभ सैट्स की जोड़ी दुर्लभ शब्दों के साथ सबसे अच्छी तरह संसर्ग करती है।_" + +#: src/bounty/3.md:46 +msgid "" +"The transaction that submits the UTXO containing the sat whose name appears " +"with the lowest number of occurrences in `frequency.tsv` shall be the winner " +"of part 0." +msgstr "" +"वह लेन-देन जो UTXO में सम्मिलित सैट प्रस्तुत करता है, जिसका नाम `frequency.tsv` में सबसे कम " +"संख्याओं की घटनाओं में दिखाई देता है, वह भाग 0 का विजेता होगा।" + +#: src/bounty/3.md:50 +msgid "Part 1" +msgstr "भाग 1" + +#: src/bounty/3.md:52 +msgid "_Popularity is the font of value._" +msgstr "_लोकप्रियता प्रतिष्‍ठा की पहचान है।_" + +#: src/bounty/3.md:54 +msgid "" +"The transaction that submits the UTXO containing the sat whose name appears " +"with the highest number of occurrences in `frequency.tsv` shall be the " +"winner of part 1." +msgstr "" +"वह लेन-देन जो UTXO में सम्मिलित सैट प्रस्तुत करता है, जिसका नाम `frequency.tsv` में सबसे " +"अधिक संख्याओं की घटनाओं में दिखाई देता है, वह भाग 1 का विजेता होगा।" + +#: src/bounty/3.md:58 +msgid "Tie Breaking" +msgstr "टाई-ब्रेकिंग" + +#: src/bounty/3.md:60 +msgid "" +"In the case of a tie, where two submissions occur with the same frequency, " +"the earlier submission shall be the winner." +msgstr "" +"टाई के मामले में, जहां दो प्रस्‍तुतियां एक ही आवृत्ति के साथ घटित होती हैं, पहली प्रस्‍तुति विजेता बन जाएगी।" + +#: src/bounty/3.md:66 +msgid "Part 0: 200,000 sats" +msgstr "भाग 0: 200,000 सैट्स" + +#: src/bounty/3.md:67 +msgid "Part 1: 200,000 sats" +msgstr "भाग 1: 200,000 सैट्स" + +#: src/bounty/3.md:68 +msgid "Total: 400,000 sats" +msgstr "कुल: 400,000 सैट्स" + +#: src/bounty/3.md:73 +msgid "" +"[`17m5rvMpi78zG8RUpCRd6NWWMJtWmu65kg`](https://mempool.space/" +"address/17m5rvMpi78zG8RUpCRd6NWWMJtWmu65kg)" +msgstr "" + +#: src/bounty/3.md:78 +msgid "Unclaimed!" +msgstr "बिना दावे के!" diff --git a/docs/theme/index.hbs b/docs/theme/index.hbs index 88e5235dc8..b5ae0bfc1e 100644 --- a/docs/theme/index.hbs +++ b/docs/theme/index.hbs @@ -207,6 +207,9 @@
  • +
  • ", - ) - .to_witness(), - )], - ..Default::default() - }); + let inscription_id = InscriptionId { txid, index: 0 }; server.mine_blocks(1); server.assert_response_csp( - format!("/preview/{}", InscriptionId { txid, index: 0 }), + format!("/preview/{}", inscription_id), StatusCode::OK, "default-src 'self'", - r".*
    <script>alert\('hello'\);</script>
    .*", + format!(".*.*", inscription_id), ); } @@ -3599,6 +3573,7 @@ mod tests { let response = reqwest::blocking::Client::builder() .default_headers(headers) + .brotli(false) .build() .unwrap() .get(server.join_url("/")) diff --git a/src/subcommand/server/accept_encoding.rs b/src/subcommand/server/accept_encoding.rs new file mode 100644 index 0000000000..be693edd44 --- /dev/null +++ b/src/subcommand/server/accept_encoding.rs @@ -0,0 +1,96 @@ +use {super::*, axum::extract::FromRef}; + +#[derive(Default)] +pub(crate) struct AcceptEncoding(Option); + +#[async_trait::async_trait] +impl axum::extract::FromRequestParts for AcceptEncoding +where + Arc: FromRef, + S: Send + Sync, +{ + type Rejection = (StatusCode, &'static str); + + async fn from_request_parts( + parts: &mut http::request::Parts, + _state: &S, + ) -> Result { + Ok(Self( + parts + .headers + .get("accept-encoding") + .map(|value| value.to_str().unwrap_or_default().to_owned()), + )) + } +} + +impl AcceptEncoding { + pub(crate) fn is_acceptable(&self, encoding: &HeaderValue) -> bool { + let Ok(encoding) = encoding.to_str() else { + return false; + }; + + self + .0 + .clone() + .unwrap_or_default() + .split(',') + .any(|value| value.split(';').next().unwrap_or_default().trim() == encoding) + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + axum::{extract::FromRequestParts, http::Request}, + http::header::ACCEPT_ENCODING, + }; + + #[tokio::test] + async fn single_encoding() { + let req = Request::builder() + .header(ACCEPT_ENCODING, "gzip") + .body(()) + .unwrap(); + + let encodings = AcceptEncoding::from_request_parts( + &mut req.into_parts().0, + &Arc::new(ServerConfig { + is_json_api_enabled: false, + }), + ) + .await + .unwrap(); + + assert_eq!(encodings.0, Some("gzip".to_string())); + } + + #[tokio::test] + async fn accepts_encoding() { + let req = Request::builder() + .header(ACCEPT_ENCODING, "deflate;q=0.5, gzip;q=1.0, br;q=0.8") + .body(()) + .unwrap(); + + let encodings = AcceptEncoding::from_request_parts( + &mut req.into_parts().0, + &Arc::new(ServerConfig { + is_json_api_enabled: false, + }), + ) + .await + .unwrap(); + + assert_eq!( + encodings.0, + Some("deflate;q=0.5, gzip;q=1.0, br;q=0.8".to_string()) + ); + + assert!(encodings.is_acceptable(&HeaderValue::from_static("deflate"))); + assert!(encodings.is_acceptable(&HeaderValue::from_static("gzip"))); + assert!(encodings.is_acceptable(&HeaderValue::from_static("br"))); + + assert!(!encodings.is_acceptable(&HeaderValue::from_static("bzip2"))); + } +} diff --git a/src/subcommand/server/error.rs b/src/subcommand/server/error.rs index cc994b6d0d..c66eeb282b 100644 --- a/src/subcommand/server/error.rs +++ b/src/subcommand/server/error.rs @@ -1,8 +1,10 @@ use super::*; +#[derive(Debug)] pub(super) enum ServerError { - Internal(Error), BadRequest(String), + Internal(Error), + NotAcceptable(String), NotFound(String), } @@ -22,6 +24,11 @@ impl IntoResponse for ServerError { ) .into_response() } + Self::NotAcceptable(content_type) => ( + StatusCode::NOT_ACCEPTABLE, + format!("inscription content type `{content_type}` is not acceptable"), + ) + .into_response(), Self::NotFound(message) => ( StatusCode::NOT_FOUND, [(header::CACHE_CONTROL, HeaderValue::from_static("no-store"))], diff --git a/src/subcommand/wallet/inscribe.rs b/src/subcommand/wallet/inscribe.rs index 9042cd443e..1efbe1f63a 100644 --- a/src/subcommand/wallet/inscribe.rs +++ b/src/subcommand/wallet/inscribe.rs @@ -70,6 +70,8 @@ pub(crate) struct Inscribe { help = "Use sats/vbyte for commit transaction.\nDefaults to if unset." )] pub(crate) commit_fee_rate: Option, + #[arg(long, help = "Compress inscription content with brotli.")] + pub(crate) compress: bool, #[arg(long, help = "Send inscription to .")] pub(crate) destination: Option>, #[arg(long, help = "Don't sign or broadcast transactions.")] @@ -138,6 +140,7 @@ impl Inscribe { None, self.metaprotocol, metadata, + self.compress, )?]; mode = Mode::SeparateOutputs; destinations = vec![match self.destination.clone() { @@ -155,6 +158,7 @@ impl Inscribe { parent_info.as_ref().map(|info| info.tx_out.value), metadata, postage, + self.compress, )?; mode = batchfile.mode; diff --git a/src/subcommand/wallet/inscribe/batch.rs b/src/subcommand/wallet/inscribe/batch.rs index df3164c8d6..9a7444eaf8 100644 --- a/src/subcommand/wallet/inscribe/batch.rs +++ b/src/subcommand/wallet/inscribe/batch.rs @@ -572,6 +572,7 @@ impl Batchfile { parent_value: Option, metadata: Option>, postage: Amount, + compress: bool, ) -> Result> { assert!(!self.inscriptions.is_empty()); @@ -596,6 +597,7 @@ impl Batchfile { Some(metadata) => Some(metadata.clone()), None => entry.metadata()?, }, + compress, )?); pointer += postage.to_sat(); diff --git a/src/templates/inscription.rs b/src/templates/inscription.rs index 9066449375..ac458fcaec 100644 --- a/src/templates/inscription.rs +++ b/src/templates/inscription.rs @@ -426,4 +426,32 @@ mod tests { .unindent() ); } + + #[test] + fn with_content_encoding() { + assert_regex_match!( + InscriptionHtml { + genesis_fee: 1, + inscription: Inscription { + content_encoding: Some("br".into()), + ..inscription("text/plain;charset=utf-8", "HELLOWORLD") + }, + inscription_id: inscription_id(1), + inscription_number: 1, + satpoint: satpoint(1, 0), + ..Default::default() + }, + " +

    Inscription 1

    + .* +
    + .* +
    content encoding
    +
    br
    + .* +
    + " + .unindent() + ); + } } diff --git a/src/templates/preview.rs b/src/templates/preview.rs index 6987e2df6f..6a260c5fa3 100644 --- a/src/templates/preview.rs +++ b/src/templates/preview.rs @@ -31,8 +31,8 @@ pub(crate) struct PreviewPdfHtml { } #[derive(boilerplate::Boilerplate)] -pub(crate) struct PreviewTextHtml<'a> { - pub(crate) text: &'a str, +pub(crate) struct PreviewTextHtml { + pub(crate) inscription_id: InscriptionId, } #[derive(boilerplate::Boilerplate)] diff --git a/static/preview-text.js b/static/preview-text.js index 1970ed4aa3..8a0e41108b 100644 --- a/static/preview-text.js +++ b/static/preview-text.js @@ -1,3 +1,11 @@ +const inscription = document.documentElement.dataset.inscription; + +const response = await fetch(`/content/${inscription}`); +const text = await response.text(); +for (const pre of document.querySelectorAll('pre')) { + pre.textContent = text; +} + let pre = document.querySelector('body > pre'); let { width, height } = pre.getBoundingClientRect(); let columns = width / 16; diff --git a/templates/inscription.html b/templates/inscription.html index 118f43857c..72917c36a4 100644 --- a/templates/inscription.html +++ b/templates/inscription.html @@ -75,6 +75,10 @@

    Inscription {{ self.inscription_number }}

    %% if let Some(content_type) = self.inscription.content_type() {
    content type
    {{ content_type }}
    +%% } +%% if let Some(content_encoding) = self.inscription.content_encoding() { +
    content encoding
    +
    {{ content_encoding.to_str().unwrap_or_default() }}
    %% }
    timestamp
    diff --git a/templates/preview-text.html b/templates/preview-text.html index 2c1a1c9f1b..d1a31868a5 100644 --- a/templates/preview-text.html +++ b/templates/preview-text.html @@ -1,15 +1,15 @@ - + - + -
    {{self.text}}
    +
    
         
       
     
    diff --git a/tests/test_server.rs b/tests/test_server.rs
    index cad36066c2..de20c59893 100644
    --- a/tests/test_server.rs
    +++ b/tests/test_server.rs
    @@ -97,7 +97,7 @@ impl TestServer {
           .unwrap()
       }
     
    -  fn sync_server(&self) {
    +  pub(crate) fn sync_server(&self) {
         let client = Client::new(&self.rpc_url, Auth::None).unwrap();
         let chain_block_count = client.get_block_count().unwrap() + 1;
     
    diff --git a/tests/wallet/inscribe.rs b/tests/wallet/inscribe.rs
    index 5138811b6d..0020bde3e0 100644
    --- a/tests/wallet/inscribe.rs
    +++ b/tests/wallet/inscribe.rs
    @@ -1,4 +1,4 @@
    -use super::*;
    +use {super::*, std::ops::Deref};
     
     #[test]
     fn inscribe_creates_inscriptions() {
    @@ -1242,3 +1242,104 @@ fn inscribe_does_not_pick_locked_utxos() {
         .stderr_regex("error: wallet contains no cardinal utxos\n")
         .run_and_extract_stdout();
     }
    +
    +#[test]
    +fn inscribe_can_compress() {
    +  let rpc_server = test_bitcoincore_rpc::spawn();
    +  rpc_server.mine_blocks(1);
    +
    +  create_wallet(&rpc_server);
    +
    +  let Inscribe { inscriptions, .. } =
    +    CommandBuilder::new("wallet inscribe --compress --file foo.txt --fee-rate 1".to_string())
    +      .write("foo.txt", [0; 350_000])
    +      .rpc_server(&rpc_server)
    +      .run_and_deserialize_output();
    +
    +  let inscription = inscriptions[0].id;
    +
    +  rpc_server.mine_blocks(1);
    +
    +  let test_server = TestServer::spawn_with_args(&rpc_server, &[]);
    +
    +  test_server.sync_server();
    +
    +  let client = reqwest::blocking::Client::builder()
    +    .brotli(false)
    +    .build()
    +    .unwrap();
    +
    +  let response = client
    +    .get(
    +      test_server
    +        .url()
    +        .join(format!("/content/{inscription}",).as_ref())
    +        .unwrap(),
    +    )
    +    .send()
    +    .unwrap();
    +
    +  assert_eq!(response.status(), StatusCode::NOT_ACCEPTABLE);
    +  assert_regex_match!(
    +    response.text().unwrap(),
    +    "inscription content type `br` is not acceptable"
    +  );
    +
    +  let client = reqwest::blocking::Client::builder()
    +    .brotli(true)
    +    .build()
    +    .unwrap();
    +
    +  let response = client
    +    .get(
    +      test_server
    +        .url()
    +        .join(format!("/content/{inscription}",).as_ref())
    +        .unwrap(),
    +    )
    +    .send()
    +    .unwrap();
    +
    +  assert_eq!(response.status(), StatusCode::OK);
    +  assert_eq!(response.bytes().unwrap().deref(), [0; 350_000]);
    +}
    +
    +#[test]
    +fn inscriptions_are_not_compressed_if_no_space_is_saved_by_compression() {
    +  let rpc_server = test_bitcoincore_rpc::spawn();
    +  rpc_server.mine_blocks(1);
    +
    +  create_wallet(&rpc_server);
    +
    +  let Inscribe { inscriptions, .. } =
    +    CommandBuilder::new("wallet inscribe --compress --file foo.txt --fee-rate 1".to_string())
    +      .write("foo.txt", "foo")
    +      .rpc_server(&rpc_server)
    +      .run_and_deserialize_output();
    +
    +  let inscription = inscriptions[0].id;
    +
    +  rpc_server.mine_blocks(1);
    +
    +  let test_server = TestServer::spawn_with_args(&rpc_server, &[]);
    +
    +  test_server.sync_server();
    +
    +  let client = reqwest::blocking::Client::builder()
    +    .brotli(false)
    +    .build()
    +    .unwrap();
    +
    +  let response = client
    +    .get(
    +      test_server
    +        .url()
    +        .join(format!("/content/{inscription}",).as_ref())
    +        .unwrap(),
    +    )
    +    .send()
    +    .unwrap();
    +
    +  assert_eq!(response.status(), StatusCode::OK);
    +  assert_eq!(response.text().unwrap(), "foo");
    +}
    
    From aa4ae24adcde817c96111d83af80dc9721fe72aa Mon Sep 17 00:00:00 2001
    From: Casey Rodarmor 
    Date: Thu, 16 Nov 2023 13:05:28 -0800
    Subject: [PATCH 09/41] Fix media table formatting (#2686)
    
    ---
     src/media.rs | 68 ++++++++++++++++++++++++++--------------------------
     1 file changed, 34 insertions(+), 34 deletions(-)
    
    diff --git a/src/media.rs b/src/media.rs
    index f54ac2b302..297ec3510c 100644
    --- a/src/media.rs
    +++ b/src/media.rs
    @@ -24,40 +24,40 @@ pub(crate) enum Media {
     impl Media {
       #[rustfmt::skip]
       const TABLE: &'static [(&'static str, BrotliEncoderMode, Media, &'static [&'static str])] = &[
    -    ("application/cbor",              BROTLI_MODE_GENERIC,   Media::Unknown,    &["cbor"]),
    -    ("application/json",              BROTLI_MODE_TEXT,      Media::Code,       &["json"]),
    -    ("application/pdf",               BROTLI_MODE_GENERIC,   Media::Pdf,        &["pdf"]),
    -    ("application/pgp-signature",     BROTLI_MODE_TEXT,      Media::Text,       &["asc"]),
    -    ("application/protobuf",          BROTLI_MODE_GENERIC,   Media::Unknown,    &["binpb"]),
    -    ("application/yaml",              BROTLI_MODE_TEXT,      Media::Code,       &["yaml", "yml"]),
    -    ("audio/flac",                    BROTLI_MODE_GENERIC,   Media::Audio,      &["flac"]),
    -    ("audio/mpeg",                    BROTLI_MODE_GENERIC,   Media::Audio,      &["mp3"]),
    -    ("audio/wav",                     BROTLI_MODE_GENERIC,   Media::Audio,      &["wav"]),
    -    ("font/otf",                      BROTLI_MODE_GENERIC,   Media::Unknown,    &["otf"]),
    -    ("font/ttf",                      BROTLI_MODE_GENERIC,   Media::Unknown,    &["ttf"]),
    -    ("font/woff",                     BROTLI_MODE_GENERIC,   Media::Unknown,    &["woff"]),
    -    ("font/woff2",                    BROTLI_MODE_FONT,      Media::Unknown,    &["woff2"]),
    -    ("image/apng",                    BROTLI_MODE_GENERIC,   Media::Image,      &["apng"]),
    -    ("image/avif",                    BROTLI_MODE_GENERIC,   Media::Image,      &[]),
    -    ("image/gif",                     BROTLI_MODE_GENERIC,   Media::Image,      &["gif"]),
    -    ("image/jpeg",                    BROTLI_MODE_GENERIC,   Media::Image,      &["jpg", "jpeg"]),
    -    ("image/png",                     BROTLI_MODE_GENERIC,   Media::Image,      &["png"]),
    -    ("image/svg+xml",                 BROTLI_MODE_TEXT,      Media::Iframe,     &["svg"]),
    -    ("image/webp",                    BROTLI_MODE_GENERIC,   Media::Image,      &["webp"]),
    -    ("model/gltf+json",               BROTLI_MODE_TEXT,      Media::Model,      &["gltf"]),
    -    ("model/gltf-binary",             BROTLI_MODE_GENERIC,   Media::Model,      &["glb"]),
    -    ("model/stl",                     BROTLI_MODE_GENERIC,   Media::Unknown,    &["stl"]),
    -    ("text/css",                      BROTLI_MODE_TEXT,      Media::Code,       &["css"]),
    -    ("text/html",                     BROTLI_MODE_TEXT,      Media::Iframe,     &[]),
    -    ("text/html;charset=utf-8",       BROTLI_MODE_TEXT,      Media::Iframe,     &["html"]),
    -    ("text/javascript",               BROTLI_MODE_TEXT,      Media::Code,       &["js"]),
    -    ("text/markdown",                 BROTLI_MODE_TEXT,      Media::Markdown,   &[]),
    -    ("text/markdown;charset=utf-8",   BROTLI_MODE_TEXT,      Media::Markdown,   &["md"]),
    -    ("text/plain",                    BROTLI_MODE_TEXT,      Media::Text,       &[]),
    -    ("text/plain;charset=utf-8",      BROTLI_MODE_TEXT,      Media::Text,       &["txt"]),
    -    ("text/x-python",                 BROTLI_MODE_TEXT,      Media::Code,       &["py"]),
    -    ("video/mp4",                     BROTLI_MODE_GENERIC,   Media::Video,      &["mp4"]),
    -    ("video/webm",                    BROTLI_MODE_GENERIC,   Media::Video,      &["webm"]),
    +    ("application/cbor",            BROTLI_MODE_GENERIC, Media::Unknown,  &["cbor"]),
    +    ("application/json",            BROTLI_MODE_TEXT,    Media::Code,     &["json"]),
    +    ("application/pdf",             BROTLI_MODE_GENERIC, Media::Pdf,      &["pdf"]),
    +    ("application/pgp-signature",   BROTLI_MODE_TEXT,    Media::Text,     &["asc"]),
    +    ("application/protobuf",        BROTLI_MODE_GENERIC, Media::Unknown,  &["binpb"]),
    +    ("application/yaml",            BROTLI_MODE_TEXT,    Media::Code,     &["yaml", "yml"]),
    +    ("audio/flac",                  BROTLI_MODE_GENERIC, Media::Audio,    &["flac"]),
    +    ("audio/mpeg",                  BROTLI_MODE_GENERIC, Media::Audio,    &["mp3"]),
    +    ("audio/wav",                   BROTLI_MODE_GENERIC, Media::Audio,    &["wav"]),
    +    ("font/otf",                    BROTLI_MODE_GENERIC, Media::Unknown,  &["otf"]),
    +    ("font/ttf",                    BROTLI_MODE_GENERIC, Media::Unknown,  &["ttf"]),
    +    ("font/woff",                   BROTLI_MODE_GENERIC, Media::Unknown,  &["woff"]),
    +    ("font/woff2",                  BROTLI_MODE_FONT,    Media::Unknown,  &["woff2"]),
    +    ("image/apng",                  BROTLI_MODE_GENERIC, Media::Image,    &["apng"]),
    +    ("image/avif",                  BROTLI_MODE_GENERIC, Media::Image,    &[]),
    +    ("image/gif",                   BROTLI_MODE_GENERIC, Media::Image,    &["gif"]),
    +    ("image/jpeg",                  BROTLI_MODE_GENERIC, Media::Image,    &["jpg", "jpeg"]),
    +    ("image/png",                   BROTLI_MODE_GENERIC, Media::Image,    &["png"]),
    +    ("image/svg+xml",               BROTLI_MODE_TEXT,    Media::Iframe,   &["svg"]),
    +    ("image/webp",                  BROTLI_MODE_GENERIC, Media::Image,    &["webp"]),
    +    ("model/gltf+json",             BROTLI_MODE_TEXT,    Media::Model,    &["gltf"]),
    +    ("model/gltf-binary",           BROTLI_MODE_GENERIC, Media::Model,    &["glb"]),
    +    ("model/stl",                   BROTLI_MODE_GENERIC, Media::Unknown,  &["stl"]),
    +    ("text/css",                    BROTLI_MODE_TEXT,    Media::Code,     &["css"]),
    +    ("text/html",                   BROTLI_MODE_TEXT,    Media::Iframe,   &[]),
    +    ("text/html;charset=utf-8",     BROTLI_MODE_TEXT,    Media::Iframe,   &["html"]),
    +    ("text/javascript",             BROTLI_MODE_TEXT,    Media::Code,     &["js"]),
    +    ("text/markdown",               BROTLI_MODE_TEXT,    Media::Markdown, &[]),
    +    ("text/markdown;charset=utf-8", BROTLI_MODE_TEXT,    Media::Markdown, &["md"]),
    +    ("text/plain",                  BROTLI_MODE_TEXT,    Media::Text,     &[]),
    +    ("text/plain;charset=utf-8",    BROTLI_MODE_TEXT,    Media::Text,     &["txt"]),
    +    ("text/x-python",               BROTLI_MODE_TEXT,    Media::Code,     &["py"]),
    +    ("video/mp4",                   BROTLI_MODE_GENERIC, Media::Video,    &["mp4"]),
    +    ("video/webm",                  BROTLI_MODE_GENERIC, Media::Video,    &["webm"]),
       ];
     
       pub(crate) fn content_type_for_path(
    
    From 86ddcf5a964635f3bb2e14af62ce8b6552deeecc Mon Sep 17 00:00:00 2001
    From: Casey Rodarmor 
    Date: Thu, 16 Nov 2023 14:48:43 -0800
    Subject: [PATCH 10/41] Update schema version for charms (#2687)
    
    ---
     src/index.rs | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/src/index.rs b/src/index.rs
    index 950c24ce0e..d96b6bb93c 100644
    --- a/src/index.rs
    +++ b/src/index.rs
    @@ -35,7 +35,7 @@ mod updater;
     #[cfg(test)]
     pub(crate) mod testing;
     
    -const SCHEMA_VERSION: u64 = 10;
    +const SCHEMA_VERSION: u64 = 11;
     
     macro_rules! define_table {
       ($name:ident, $key:ty, $value:ty) => {
    
    From f1e3c50a56036207fd96f5c3b3873032b5e1964a Mon Sep 17 00:00:00 2001
    From: raph 
    Date: Fri, 17 Nov 2023 00:02:21 +0100
    Subject: [PATCH 11/41] Fix unbound outpoint server error (#2479)
    
    ---
     src/index.rs             |  2 +-
     src/subcommand/server.rs | 13 ++++++++++++-
     tests/wallet/outputs.rs  | 19 +++++++++++++++++++
     3 files changed, 32 insertions(+), 2 deletions(-)
    
    diff --git a/src/index.rs b/src/index.rs
    index d96b6bb93c..4a0038b210 100644
    --- a/src/index.rs
    +++ b/src/index.rs
    @@ -1128,7 +1128,7 @@ impl Index {
       }
     
       pub(crate) fn list(&self, outpoint: OutPoint) -> Result> {
    -    if !self.index_sats {
    +    if !self.index_sats || outpoint == unbound_outpoint() {
           return Ok(None);
         }
     
    diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs
    index 5eca99481f..d7c81fcc89 100644
    --- a/src/subcommand/server.rs
    +++ b/src/subcommand/server.rs
    @@ -2575,7 +2575,7 @@ mod tests {
     
       #[test]
       fn unbound_output_receives_unbound_inscriptions() {
    -    let server = TestServer::new_with_regtest();
    +    let server = TestServer::new_with_regtest_with_index_sats();
     
         server.mine_blocks(1);
     
    @@ -2611,6 +2611,17 @@ mod tests {
       
    0000000000000000000000000000000000000000000000000000000000000000:0
    .*" ), ); + + server.assert_response_regex( + "/output/0000000000000000000000000000000000000000000000000000000000000000:0", + StatusCode::OK, + ".*

    Output 0000000000000000000000000000000000000000000000000000000000000000:0

    +
    +
    inscriptions
    +
    + +
    .*", + ); } #[test] diff --git a/tests/wallet/outputs.rs b/tests/wallet/outputs.rs index fcef95d39c..39a648e38e 100644 --- a/tests/wallet/outputs.rs +++ b/tests/wallet/outputs.rs @@ -35,3 +35,22 @@ fn outputs_includes_locked_outputs() { assert_eq!(output[0].output, outpoint); assert_eq!(output[0].amount, amount); } + +#[test] +fn outputs_includes_unbound_outputs() { + let rpc_server = test_bitcoincore_rpc::spawn(); + create_wallet(&rpc_server); + + let coinbase_tx = &rpc_server.mine_blocks_with_subsidy(1, 1_000_000)[0].txdata[0]; + let outpoint = OutPoint::new(coinbase_tx.txid(), 0); + let amount = coinbase_tx.output[0].value; + + rpc_server.lock(outpoint); + + let output = CommandBuilder::new("wallet outputs") + .rpc_server(&rpc_server) + .run_and_deserialize_output::>(); + + assert_eq!(output[0].output, outpoint); + assert_eq!(output[0].amount, amount); +} From 64434e41d5fcbd75ec67fe0e7f13bf7540ac5930 Mon Sep 17 00:00:00 2001 From: Eloc <42568538+elocremarc@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:11:14 -0800 Subject: [PATCH 12/41] Add binary media type (#2671) --- src/media.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/media.rs b/src/media.rs index 297ec3510c..2978bee038 100644 --- a/src/media.rs +++ b/src/media.rs @@ -29,6 +29,7 @@ impl Media { ("application/pdf", BROTLI_MODE_GENERIC, Media::Pdf, &["pdf"]), ("application/pgp-signature", BROTLI_MODE_TEXT, Media::Text, &["asc"]), ("application/protobuf", BROTLI_MODE_GENERIC, Media::Unknown, &["binpb"]), + ("application/octet-stream", BROTLI_MODE_GENERIC, Media::Unknown, &["bin"]), ("application/yaml", BROTLI_MODE_TEXT, Media::Code, &["yaml", "yml"]), ("audio/flac", BROTLI_MODE_GENERIC, Media::Audio, &["flac"]), ("audio/mpeg", BROTLI_MODE_GENERIC, Media::Audio, &["mp3"]), From 87c539499606f6d0be54927dedfcddf593cd644c Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Fri, 17 Nov 2023 07:17:49 +0800 Subject: [PATCH 13/41] Clean up install.sh (#2669) --- install.sh | 63 ++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/install.sh b/install.sh index 0e176fe1b4..a711ca2e89 100755 --- a/install.sh +++ b/install.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -euo pipefail + if [ ! -z ${GITHUB_ACTIONS-} ]; then set -x fi @@ -10,7 +11,7 @@ help() { Install a binary release of ord hosted on GitHub USAGE: - install [options] + install.sh [options] FLAGS: -h, --help Display this message @@ -23,25 +24,20 @@ OPTIONS: EOF } -git=ordinals/ord crate=ord url=https://github.com/ordinals/ord releases=$url/releases say() { - echo "install: $@" -} - -say_err() { - say "$@" >&2 + echo "install.sh: $*" >&2 } err() { - if [ ! -z ${td-} ]; then - rm -rf $td + if [ ! -z ${tempdir-} ]; then + rm -rf $tempdir fi - say_err "error: $@" + say "error: $*" exit 1 } @@ -86,17 +82,11 @@ need mkdir need mktemp need tar -# Optional dependencies +dest=${dest-"$HOME/bin"} + if [ -z ${tag-} ]; then need cut - need rev -fi -if [ -z ${dest-} ]; then - dest="$HOME/bin" -fi - -if [ -z ${tag-} ]; then tag=$(curl --proto =https --tlsv1.2 -sSf https://api.github.com/repos/ordinals/ord/releases/latest | grep tag_name | cut -d'"' -f4 @@ -111,34 +101,37 @@ if [ -z ${target-} ]; then x86_64-Darwin) target=x86_64-apple-darwin;; x86_64-Linux) target=x86_64-unknown-linux-gnu;; *) - err 'Could not determine target from output of `uname -m`-`uname -s`, please use `--target`:' $uname_target - err 'Target architecture is not supported by this install script.' - err 'Consider opening an issue or building from source: https://github.com/ordinals/ord' + say 'Could not determine target from output of `uname -m`-`uname -s`, please use `--target`:' $uname_target + say 'Target architecture is not supported by this install script.' + say 'Consider opening an issue or building from source: https://github.com/ordinals/ord' + exit 1 ;; esac fi archive="$releases/download/$tag/$crate-$tag-$target.tar.gz" -say_err "Repository: $url" -say_err "Crate: $crate" -say_err "Tag: $tag" -say_err "Target: $target" -say_err "Destination: $dest" -say_err "Archive: $archive" +say "Repository: $url" +say "Crate: $crate" +say "Tag: $tag" +say "Target: $target" +say "Destination: $dest" +say "Archive: $archive" + +tempdir=`mktemp -d || mktemp -d -t tmp` -td=$(mktemp -d || mktemp -d -t tmp) -curl --proto =https --tlsv1.2 -sSfL $archive | tar --directory $td --strip-components 1 -xz +curl --proto =https --tlsv1.2 -sSfL $archive | tar --directory $tempdir --strip-components 1 -xz -for f in $(ls $td); do - test -x $td/$f || continue +for name in `ls $tempdir`; do + file="$tempdir/$name" + test -x $file || continue - if [ -e "$dest/$f" ] && [ $force = false ]; then - err "$f already exists in $dest" + if [ -e "$dest/$name" ] && [ $force = false ]; then + err "$name already exists in $dest" else mkdir -p $dest - install -m 755 $td/$f $dest + install -m 755 $file $dest fi done -rm -rf $td +rm -rf $tempdir From b50b5360d4c71eac4a83c99ab93284905889cff5 Mon Sep 17 00:00:00 2001 From: ordinally <11798624+veryordinally@users.noreply.github.com> Date: Sat, 18 Nov 2023 21:07:51 +0100 Subject: [PATCH 14/41] Add /collections Page (#2561) --- src/index.rs | 28 ++++++++ src/subcommand/server.rs | 123 +++++++++++++++++++++++++++++++++-- src/templates.rs | 2 + src/templates/collections.rs | 65 ++++++++++++++++++ static/index.css | 9 +-- templates/collections.html | 18 +++++ templates/home.html | 2 + 7 files changed, 237 insertions(+), 10 deletions(-) create mode 100644 src/templates/collections.rs create mode 100644 templates/collections.html diff --git a/src/index.rs b/src/index.rs index 4a0038b210..bfb4252ff4 100644 --- a/src/index.rs +++ b/src/index.rs @@ -795,6 +795,34 @@ impl Index { self.client.get_block(&hash).into_option() } + pub(crate) fn get_collections_paginated( + &self, + page_size: usize, + page_index: usize, + ) -> Result<(Vec, bool)> { + let mut collections = self + .database + .begin_read()? + .open_multimap_table(INSCRIPTION_ID_TO_CHILDREN)? + .iter()? + .skip(page_index * page_size) + .take(page_size + 1) + .map(|result| { + result + .map(|(key, _value)| InscriptionId::load(*key.value())) + .map_err(|err| err.into()) + }) + .collect::>>()?; + + let more = collections.len() > page_size; + + if more { + collections.pop(); + } + + Ok((collections, more)) + } + #[cfg(test)] pub(crate) fn get_children_by_inscription_id( &self, diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index d7c81fcc89..6dcad557e8 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -10,12 +10,12 @@ use { page_config::PageConfig, runes::Rune, templates::{ - BlockHtml, BlockJson, BlocksHtml, ChildrenHtml, ClockSvg, HomeHtml, InputHtml, - InscriptionHtml, InscriptionJson, InscriptionsBlockHtml, InscriptionsHtml, InscriptionsJson, - OutputHtml, OutputJson, PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml, - PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, - PreviewUnknownHtml, PreviewVideoHtml, RangeHtml, RareTxt, RuneHtml, RunesHtml, SatHtml, - SatJson, TransactionHtml, + BlockHtml, BlockJson, BlocksHtml, ChildrenHtml, ClockSvg, CollectionsHtml, HomeHtml, + InputHtml, InscriptionHtml, InscriptionJson, InscriptionsBlockHtml, InscriptionsHtml, + InscriptionsJson, OutputHtml, OutputJson, PageContent, PageHtml, PreviewAudioHtml, + PreviewCodeHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, + PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, RangeHtml, RareTxt, RuneHtml, + RunesHtml, SatHtml, SatJson, TransactionHtml, }, }, axum::{ @@ -202,6 +202,8 @@ impl Server { get(Self::children_paginated), ) .route("/clock", get(Self::clock)) + .route("/collections", get(Self::collections)) + .route("/collections/:page", get(Self::collections_paginated)) .route("/content/:inscription_id", get(Self::content)) .route("/faq", get(Self::faq)) .route("/favicon.ico", get(Self::favicon)) @@ -1236,6 +1238,35 @@ impl Server { }) } + async fn collections( + Extension(page_config): Extension>, + Extension(index): Extension>, + ) -> ServerResult { + Self::collections_paginated(Extension(page_config), Extension(index), Path(0)).await + } + + async fn collections_paginated( + Extension(page_config): Extension>, + Extension(index): Extension>, + Path(page_index): Path, + ) -> ServerResult { + let (collections, more_collections) = index.get_collections_paginated(100, page_index)?; + + let prev = page_index.checked_sub(1); + + let next = more_collections.then_some(page_index + 1); + + Ok( + CollectionsHtml { + inscriptions: collections, + prev, + next, + } + .page(page_config) + .into_response(), + ) + } + async fn children( Extension(page_config): Extension>, Extension(index): Extension>, @@ -2675,6 +2706,8 @@ mod tests { Inscriptions \| Blocks + \| + Collections
    .* @@ -3552,6 +3585,84 @@ mod tests { ); } + #[test] + fn collections_page_prev_and_next() { + let server = TestServer::new_with_regtest_with_index_sats(); + + let mut parent_ids = Vec::new(); + + for i in 0..101 { + server.mine_blocks(1); + + parent_ids.push(InscriptionId { + txid: server.bitcoin_rpc_server.broadcast_tx(TransactionTemplate { + inputs: &[(i + 1, 0, 0, inscription("text/plain", "hello").to_witness())], + ..Default::default() + }), + index: 0, + }); + } + + for (i, parent_id) in parent_ids.iter().enumerate().take(101) { + server.mine_blocks(1); + + server.bitcoin_rpc_server.broadcast_tx(TransactionTemplate { + inputs: &[ + (i + 2, 1, 0, Default::default()), + ( + i + 102, + 0, + 0, + Inscription { + content_type: Some("text/plain".into()), + body: Some("hello".into()), + parent: Some(parent_id.parent_value()), + ..Default::default() + } + .to_witness(), + ), + ], + outputs: 2, + output_values: &[50 * COIN_VALUE, 50 * COIN_VALUE], + ..Default::default() + }); + } + + server.mine_blocks(1); + + server.assert_response_regex( + "/collections", + StatusCode::OK, + r".* +

    Collections

    +
    + + (.*\s*){99} +
    +
    +prev + +
    .*" + .to_string() + .unindent(), + ); + + server.assert_response_regex( + "/collections/1", + StatusCode::OK, + ".* +

    Collections

    +
    + +
    +
    + +next +
    .*" + .unindent(), + ); + } + #[test] fn responses_are_gzipped() { let server = TestServer::new(); diff --git a/src/templates.rs b/src/templates.rs index 23a26520dd..077a944dd1 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -5,6 +5,7 @@ pub(crate) use { blocks::BlocksHtml, children::ChildrenHtml, clock::ClockSvg, + collections::CollectionsHtml, home::HomeHtml, iframe::Iframe, input::InputHtml, @@ -30,6 +31,7 @@ pub mod block; mod blocks; mod children; mod clock; +pub mod collections; mod home; mod iframe; mod input; diff --git a/src/templates/collections.rs b/src/templates/collections.rs new file mode 100644 index 0000000000..fc1274b7de --- /dev/null +++ b/src/templates/collections.rs @@ -0,0 +1,65 @@ +use super::*; + +#[derive(Boilerplate)] +pub(crate) struct CollectionsHtml { + pub(crate) inscriptions: Vec, + pub(crate) prev: Option, + pub(crate) next: Option, +} + +impl PageContent for CollectionsHtml { + fn title(&self) -> String { + "Collections".into() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn without_prev_and_next() { + assert_regex_match!( + CollectionsHtml { + inscriptions: vec![inscription_id(1), inscription_id(2)], + prev: None, + next: None, + }, + " +

    Collections

    +
    + + +
    + .* + prev + next + .* + " + .unindent() + ); + } + + #[test] + fn with_prev_and_next() { + assert_regex_match!( + CollectionsHtml { + inscriptions: vec![inscription_id(1), inscription_id(2)], + prev: Some(1), + next: Some(2), + }, + " +

    Collections

    +
    + + +
    + .* + + + .* + " + .unindent() + ); + } +} diff --git a/static/index.css b/static/index.css index 46cfe38c26..8a2fccecbb 100644 --- a/static/index.css +++ b/static/index.css @@ -245,15 +245,16 @@ a.mythic { } .tabs > a { - flex: 1; - padding: 1rem; color: var(--light-fg); + padding: 1rem; } -.tabs > *:nth-child(1) { +.tabs > *:first-child { + flex: 1; text-align: right; } -.tabs > *:nth-child(3) { +.tabs > *:last-child { + flex: 1; text-align: left; } diff --git a/templates/collections.html b/templates/collections.html new file mode 100644 index 0000000000..96148916c6 --- /dev/null +++ b/templates/collections.html @@ -0,0 +1,18 @@ +

    Collections

    +
    +%% for id in &self.inscriptions { + {{Iframe::thumbnail(*id)}} +%% } +
    +
    +%% if let Some(prev) = self.prev { + +%% } else { +prev +%% } +%% if let Some(next) = self.next { + +%% } else { +next +%% } +
    diff --git a/templates/home.html b/templates/home.html index ab0d4306ed..9593c2ea7d 100644 --- a/templates/home.html +++ b/templates/home.html @@ -2,6 +2,8 @@ Inscriptions | Blocks + | + Collections
    %% for inscription in &self.inscriptions { From ad0fe30aa9c107a9e650a99c2f7b03a9d48ff14e Mon Sep 17 00:00:00 2001 From: Eloc <42568538+elocremarc@users.noreply.github.com> Date: Sun, 19 Nov 2023 08:59:04 -0800 Subject: [PATCH 15/41] Preview font inscriptions (#2692) --- src/media.rs | 9 +++++---- src/subcommand/server.rs | 35 ++++++++++++++++++++++++++++++++--- src/templates.rs | 4 ++-- src/templates/preview.rs | 5 +++++ static/preview-font.css | 19 +++++++++++++++++++ templates/preview-font.html | 16 ++++++++++++++++ 6 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 static/preview-font.css create mode 100644 templates/preview-font.html diff --git a/src/media.rs b/src/media.rs index 2978bee038..6fea7da71b 100644 --- a/src/media.rs +++ b/src/media.rs @@ -11,6 +11,7 @@ use { pub(crate) enum Media { Audio, Code, + Font, Iframe, Image, Markdown, @@ -34,10 +35,10 @@ impl Media { ("audio/flac", BROTLI_MODE_GENERIC, Media::Audio, &["flac"]), ("audio/mpeg", BROTLI_MODE_GENERIC, Media::Audio, &["mp3"]), ("audio/wav", BROTLI_MODE_GENERIC, Media::Audio, &["wav"]), - ("font/otf", BROTLI_MODE_GENERIC, Media::Unknown, &["otf"]), - ("font/ttf", BROTLI_MODE_GENERIC, Media::Unknown, &["ttf"]), - ("font/woff", BROTLI_MODE_GENERIC, Media::Unknown, &["woff"]), - ("font/woff2", BROTLI_MODE_FONT, Media::Unknown, &["woff2"]), + ("font/otf", BROTLI_MODE_GENERIC, Media::Font, &["otf"]), + ("font/ttf", BROTLI_MODE_GENERIC, Media::Font, &["ttf"]), + ("font/woff", BROTLI_MODE_GENERIC, Media::Font, &["woff"]), + ("font/woff2", BROTLI_MODE_FONT, Media::Font, &["woff2"]), ("image/apng", BROTLI_MODE_GENERIC, Media::Image, &["apng"]), ("image/avif", BROTLI_MODE_GENERIC, Media::Image, &[]), ("image/gif", BROTLI_MODE_GENERIC, Media::Image, &["gif"]), diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 6dcad557e8..61f6cea9bd 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -13,9 +13,9 @@ use { BlockHtml, BlockJson, BlocksHtml, ChildrenHtml, ClockSvg, CollectionsHtml, HomeHtml, InputHtml, InscriptionHtml, InscriptionJson, InscriptionsBlockHtml, InscriptionsHtml, InscriptionsJson, OutputHtml, OutputJson, PageContent, PageHtml, PreviewAudioHtml, - PreviewCodeHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, - PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, RangeHtml, RareTxt, RuneHtml, - RunesHtml, SatHtml, SatJson, TransactionHtml, + PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, + PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, RangeHtml, RareTxt, + RuneHtml, RunesHtml, SatHtml, SatJson, TransactionHtml, }, }, axum::{ @@ -1076,6 +1076,15 @@ impl Server { ) .into_response(), ), + Media::Font => Ok( + ( + [( + header::CONTENT_SECURITY_POLICY, + "script-src-elem 'self'; style-src 'self' 'unsafe-inline';", + )], + PreviewFontHtml { inscription_id } + ).into_response(), + ), Media::Iframe => Ok( Self::content_response(inscription, accept_encoding)? .ok_or_not_found(|| format!("inscription {inscription_id} content"))? @@ -3229,6 +3238,26 @@ mod tests { ); } + #[test] + fn font_preview() { + let server = TestServer::new_with_regtest(); + server.mine_blocks(1); + + let txid = server.bitcoin_rpc_server.broadcast_tx(TransactionTemplate { + inputs: &[(1, 0, 0, inscription("font/ttf", "hello").to_witness())], + ..Default::default() + }); + let inscription_id = InscriptionId { txid, index: 0 }; + + server.mine_blocks(1); + + server.assert_response_regex( + format!("/preview/{inscription_id}"), + StatusCode::OK, + format!(r".*src: url\(/content/{inscription_id}\).*"), + ); + } + #[test] fn pdf_preview() { let server = TestServer::new_with_regtest(); diff --git a/src/templates.rs b/src/templates.rs index 077a944dd1..32f6653776 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -16,8 +16,8 @@ pub(crate) use { output::{OutputHtml, OutputJson}, page_config::PageConfig, preview::{ - PreviewAudioHtml, PreviewCodeHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, - PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, + PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, PreviewMarkdownHtml, + PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, }, range::RangeHtml, rare::RareTxt, diff --git a/src/templates/preview.rs b/src/templates/preview.rs index 6a260c5fa3..8de6878233 100644 --- a/src/templates/preview.rs +++ b/src/templates/preview.rs @@ -10,6 +10,11 @@ pub(crate) struct PreviewCodeHtml { pub(crate) inscription_id: InscriptionId, } +#[derive(boilerplate::Boilerplate)] +pub(crate) struct PreviewFontHtml { + pub(crate) inscription_id: InscriptionId, +} + #[derive(boilerplate::Boilerplate)] pub(crate) struct PreviewImageHtml { pub(crate) inscription_id: InscriptionId, diff --git a/static/preview-font.css b/static/preview-font.css new file mode 100644 index 0000000000..9cfcf4d3c2 --- /dev/null +++ b/static/preview-font.css @@ -0,0 +1,19 @@ +html, body, textarea { + background-color: #292c2f; + height: 100%; +} + +body { + margin: 0; +} + +textarea { + border: 0; + box-sizing: border-box; + color: #a1adb8; + font-family: 'Inscription'; + font-size: 24px; + padding: 5vmin; + resize: none; + width: 100%; +} diff --git a/templates/preview-font.html b/templates/preview-font.html new file mode 100644 index 0000000000..a0dc562eae --- /dev/null +++ b/templates/preview-font.html @@ -0,0 +1,16 @@ + + + + + + + + + + + From 1a5c35febf0e2ffffde1c9a252ce26d4d524d822 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sun, 19 Nov 2023 17:20:30 -0600 Subject: [PATCH 16/41] Only load used language highlight module in code preview (#2696) --- src/media.rs | 108 ++++++++++++++++++++++++------------ src/subcommand/server.rs | 27 +++++---- src/templates/preview.rs | 1 + static/preview-code.js | 28 ++++------ templates/preview-code.html | 3 +- 5 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/media.rs b/src/media.rs index 6fea7da71b..a141ee1f1e 100644 --- a/src/media.rs +++ b/src/media.rs @@ -10,7 +10,7 @@ use { #[derive(Debug, PartialEq, Copy, Clone)] pub(crate) enum Media { Audio, - Code, + Code(Language), Font, Iframe, Image, @@ -22,44 +22,70 @@ pub(crate) enum Media { Video, } +#[derive(Debug, PartialEq, Copy, Clone)] +pub(crate) enum Language { + Css, + JavaScript, + Json, + Python, + Yaml, +} + +impl Display for Language { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Css => "css", + Self::JavaScript => "javascript", + Self::Json => "json", + Self::Python => "python", + Self::Yaml => "yaml", + } + ) + } +} + impl Media { #[rustfmt::skip] const TABLE: &'static [(&'static str, BrotliEncoderMode, Media, &'static [&'static str])] = &[ - ("application/cbor", BROTLI_MODE_GENERIC, Media::Unknown, &["cbor"]), - ("application/json", BROTLI_MODE_TEXT, Media::Code, &["json"]), - ("application/pdf", BROTLI_MODE_GENERIC, Media::Pdf, &["pdf"]), - ("application/pgp-signature", BROTLI_MODE_TEXT, Media::Text, &["asc"]), - ("application/protobuf", BROTLI_MODE_GENERIC, Media::Unknown, &["binpb"]), - ("application/octet-stream", BROTLI_MODE_GENERIC, Media::Unknown, &["bin"]), - ("application/yaml", BROTLI_MODE_TEXT, Media::Code, &["yaml", "yml"]), - ("audio/flac", BROTLI_MODE_GENERIC, Media::Audio, &["flac"]), - ("audio/mpeg", BROTLI_MODE_GENERIC, Media::Audio, &["mp3"]), - ("audio/wav", BROTLI_MODE_GENERIC, Media::Audio, &["wav"]), - ("font/otf", BROTLI_MODE_GENERIC, Media::Font, &["otf"]), - ("font/ttf", BROTLI_MODE_GENERIC, Media::Font, &["ttf"]), - ("font/woff", BROTLI_MODE_GENERIC, Media::Font, &["woff"]), - ("font/woff2", BROTLI_MODE_FONT, Media::Font, &["woff2"]), - ("image/apng", BROTLI_MODE_GENERIC, Media::Image, &["apng"]), - ("image/avif", BROTLI_MODE_GENERIC, Media::Image, &[]), - ("image/gif", BROTLI_MODE_GENERIC, Media::Image, &["gif"]), - ("image/jpeg", BROTLI_MODE_GENERIC, Media::Image, &["jpg", "jpeg"]), - ("image/png", BROTLI_MODE_GENERIC, Media::Image, &["png"]), - ("image/svg+xml", BROTLI_MODE_TEXT, Media::Iframe, &["svg"]), - ("image/webp", BROTLI_MODE_GENERIC, Media::Image, &["webp"]), - ("model/gltf+json", BROTLI_MODE_TEXT, Media::Model, &["gltf"]), - ("model/gltf-binary", BROTLI_MODE_GENERIC, Media::Model, &["glb"]), - ("model/stl", BROTLI_MODE_GENERIC, Media::Unknown, &["stl"]), - ("text/css", BROTLI_MODE_TEXT, Media::Code, &["css"]), - ("text/html", BROTLI_MODE_TEXT, Media::Iframe, &[]), - ("text/html;charset=utf-8", BROTLI_MODE_TEXT, Media::Iframe, &["html"]), - ("text/javascript", BROTLI_MODE_TEXT, Media::Code, &["js"]), - ("text/markdown", BROTLI_MODE_TEXT, Media::Markdown, &[]), - ("text/markdown;charset=utf-8", BROTLI_MODE_TEXT, Media::Markdown, &["md"]), - ("text/plain", BROTLI_MODE_TEXT, Media::Text, &[]), - ("text/plain;charset=utf-8", BROTLI_MODE_TEXT, Media::Text, &["txt"]), - ("text/x-python", BROTLI_MODE_TEXT, Media::Code, &["py"]), - ("video/mp4", BROTLI_MODE_GENERIC, Media::Video, &["mp4"]), - ("video/webm", BROTLI_MODE_GENERIC, Media::Video, &["webm"]), + ("application/cbor", BROTLI_MODE_GENERIC, Media::Unknown, &["cbor"]), + ("application/json", BROTLI_MODE_TEXT, Media::Code(Language::Json), &["json"]), + ("application/octet-stream", BROTLI_MODE_GENERIC, Media::Unknown, &["bin"]), + ("application/pdf", BROTLI_MODE_GENERIC, Media::Pdf, &["pdf"]), + ("application/pgp-signature", BROTLI_MODE_TEXT, Media::Text, &["asc"]), + ("application/protobuf", BROTLI_MODE_GENERIC, Media::Unknown, &["binpb"]), + ("application/x-javascript", BROTLI_MODE_TEXT, Media::Code(Language::JavaScript), &[]), + ("application/yaml", BROTLI_MODE_TEXT, Media::Code(Language::Yaml), &["yaml", "yml"]), + ("audio/flac", BROTLI_MODE_GENERIC, Media::Audio, &["flac"]), + ("audio/mpeg", BROTLI_MODE_GENERIC, Media::Audio, &["mp3"]), + ("audio/wav", BROTLI_MODE_GENERIC, Media::Audio, &["wav"]), + ("font/otf", BROTLI_MODE_GENERIC, Media::Font, &["otf"]), + ("font/ttf", BROTLI_MODE_GENERIC, Media::Font, &["ttf"]), + ("font/woff", BROTLI_MODE_GENERIC, Media::Font, &["woff"]), + ("font/woff2", BROTLI_MODE_FONT, Media::Font, &["woff2"]), + ("image/apng", BROTLI_MODE_GENERIC, Media::Image, &["apng"]), + ("image/avif", BROTLI_MODE_GENERIC, Media::Image, &[]), + ("image/gif", BROTLI_MODE_GENERIC, Media::Image, &["gif"]), + ("image/jpeg", BROTLI_MODE_GENERIC, Media::Image, &["jpg", "jpeg"]), + ("image/png", BROTLI_MODE_GENERIC, Media::Image, &["png"]), + ("image/svg+xml", BROTLI_MODE_TEXT, Media::Iframe, &["svg"]), + ("image/webp", BROTLI_MODE_GENERIC, Media::Image, &["webp"]), + ("model/gltf+json", BROTLI_MODE_TEXT, Media::Model, &["gltf"]), + ("model/gltf-binary", BROTLI_MODE_GENERIC, Media::Model, &["glb"]), + ("model/stl", BROTLI_MODE_GENERIC, Media::Unknown, &["stl"]), + ("text/css", BROTLI_MODE_TEXT, Media::Code(Language::Css), &["css"]), + ("text/html", BROTLI_MODE_TEXT, Media::Iframe, &[]), + ("text/html;charset=utf-8", BROTLI_MODE_TEXT, Media::Iframe, &["html"]), + ("text/javascript", BROTLI_MODE_TEXT, Media::Code(Language::JavaScript), &["js"]), + ("text/markdown", BROTLI_MODE_TEXT, Media::Markdown, &[]), + ("text/markdown;charset=utf-8", BROTLI_MODE_TEXT, Media::Markdown, &["md"]), + ("text/plain", BROTLI_MODE_TEXT, Media::Text, &[]), + ("text/plain;charset=utf-8", BROTLI_MODE_TEXT, Media::Text, &["txt"]), + ("text/x-python", BROTLI_MODE_TEXT, Media::Code(Language::Python), &["py"]), + ("video/mp4", BROTLI_MODE_GENERIC, Media::Video, &["mp4"]), + ("video/webm", BROTLI_MODE_GENERIC, Media::Video, &["webm"]), ]; pub(crate) fn content_type_for_path( @@ -172,4 +198,14 @@ mod tests { fn av1_in_mp4_is_rejected() { assert!(Media::check_mp4_codec(Path::new("examples/av1.mp4")).is_err(),); } + + #[test] + fn no_duplicate_exensions() { + let mut set = HashSet::new(); + for (_, _, _, extensions) in Media::TABLE { + for extension in *extensions { + assert!(set.insert(extension), "duplicate extension `{extension}`"); + } + } + } } diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 61f6cea9bd..29d210712d 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -1066,24 +1066,28 @@ impl Server { match inscription.media() { Media::Audio => Ok(PreviewAudioHtml { inscription_id }.into_response()), - Media::Code => Ok( + Media::Code(language) => Ok( ( [( header::CONTENT_SECURITY_POLICY, - "script-src-elem 'self' https://cdn.jsdelivr.net; href-src 'self' https://cdn.jsdelivr.net", + "script-src-elem 'self' https://cdn.jsdelivr.net", )], - PreviewCodeHtml { inscription_id }, + PreviewCodeHtml { + inscription_id, + language, + }, ) .into_response(), ), Media::Font => Ok( ( [( - header::CONTENT_SECURITY_POLICY, - "script-src-elem 'self'; style-src 'self' 'unsafe-inline';", + header::CONTENT_SECURITY_POLICY, + "script-src-elem 'self'; style-src 'self' 'unsafe-inline';", )], - PreviewFontHtml { inscription_id } - ).into_response(), + PreviewFontHtml { inscription_id }, + ) + .into_response(), ), Media::Iframe => Ok( Self::content_response(inscription, accept_encoding)? @@ -1130,12 +1134,7 @@ impl Server { ) .into_response(), ), - Media::Text => { - Ok( - PreviewTextHtml { inscription_id } - .into_response(), - ) - } + Media::Text => Ok(PreviewTextHtml { inscription_id }.into_response()), Media::Unknown => Ok(PreviewUnknownHtml.into_response()), Media::Video => Ok(PreviewVideoHtml { inscription_id }.into_response()), } @@ -3161,7 +3160,7 @@ mod tests { server.assert_response_regex( format!("/preview/{inscription_id}"), StatusCode::OK, - format!(r".*.*"), + format!(r".*.*"), ); } diff --git a/src/templates/preview.rs b/src/templates/preview.rs index 8de6878233..b69ffcea21 100644 --- a/src/templates/preview.rs +++ b/src/templates/preview.rs @@ -8,6 +8,7 @@ pub(crate) struct PreviewAudioHtml { #[derive(boilerplate::Boilerplate)] pub(crate) struct PreviewCodeHtml { pub(crate) inscription_id: InscriptionId, + pub(crate) language: media::Language, } #[derive(boilerplate::Boilerplate)] diff --git a/static/preview-code.js b/static/preview-code.js index 1e45f3c073..c41096215e 100644 --- a/static/preview-code.js +++ b/static/preview-code.js @@ -1,22 +1,14 @@ import hljs from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/highlight.min.js'; -import css from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/css.min.js'; -import javascript from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/javascript.min.js'; -import json from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/json.min.js'; -import python from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/python.min.js'; -import yaml from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/yaml.min.js'; - -hljs.registerLanguage('css', css); -hljs.registerLanguage('javascript', javascript); -hljs.registerLanguage('json', json); -hljs.registerLanguage('python', python); -hljs.registerLanguage('yaml', yaml); const inscription = document.documentElement.dataset.inscription; +const language = document.documentElement.dataset.language; + +const definition = await import(`https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/${language}.min.js`); + +hljs.registerLanguage(language, definition.default); + const response = await fetch(`/content/${inscription}`); -const contentType = response.headers.get("content-type"); -let language = contentType.split("/")[1]; -if (language === "x-python") { - language = "python"; -} -const code = await response.text(); -document.body.innerHTML = `
    ${hljs.highlight(code, {language, ignoreIllegals: true}).value}
    `; +const text = await response.text(); +const code = document.querySelector('code'); + +code.innerHTML = hljs.highlight(text, {language, ignoreIllegals: true}).value; diff --git a/templates/preview-code.html b/templates/preview-code.html index 8aefcb3095..a50caa05b9 100644 --- a/templates/preview-code.html +++ b/templates/preview-code.html @@ -1,10 +1,11 @@ - + +
    From a2943f56c025cc26efa0327cf3d5d7fc35b6e727 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Mon, 20 Nov 2023 14:45:13 -0600 Subject: [PATCH 17/41] Only try to create the database if it wasn't found (#2703) --- src/index.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/index.rs b/src/index.rs index bfb4252ff4..c9a21be799 100644 --- a/src/index.rs +++ b/src/index.rs @@ -17,8 +17,8 @@ use { indicatif::{ProgressBar, ProgressStyle}, log::log_enabled, redb::{ - Database, MultimapTable, MultimapTableDefinition, ReadableMultimapTable, ReadableTable, Table, - TableDefinition, WriteTransaction, + Database, DatabaseError, MultimapTable, MultimapTableDefinition, ReadableMultimapTable, + ReadableTable, StorageError, Table, TableDefinition, WriteTransaction, }, std::collections::{BTreeSet, HashMap}, std::io::{BufWriter, Read, Write}, @@ -261,7 +261,9 @@ impl Index { database } - Err(_) => { + Err(DatabaseError::Storage(StorageError::Io(error))) + if error.kind() == io::ErrorKind::NotFound => + { let database = Database::builder() .set_cache_size(db_cache_size) .create(&path)?; @@ -312,6 +314,7 @@ impl Index { database } + Err(error) => bail!("failed to open index: {error}"), }; let genesis_block_coinbase_transaction = From 1b0bde9646fce5925d810aa9edc7b766b2ea945e Mon Sep 17 00:00:00 2001 From: raph Date: Mon, 20 Nov 2023 23:17:08 +0100 Subject: [PATCH 18/41] Move postage into batch file (#2705) --- batch.yaml | 3 +++ src/subcommand/wallet/inscribe.rs | 17 +++++++++++++---- src/subcommand/wallet/inscribe/batch.rs | 6 ++++-- tests/wallet/inscribe.rs | 8 ++++---- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/batch.yaml b/batch.yaml index ded5e7879a..29a972b6b0 100644 --- a/batch.yaml +++ b/batch.yaml @@ -8,6 +8,9 @@ mode: separate-outputs # parent inscription: parent: 6ac5cacb768794f4fd7a78bf00f2074891fce68bd65c4ff36e77177237aacacai0 +# postage for each inscription: +postage: 12345 + # inscriptions to inscribe # # each inscription has the following fields: diff --git a/src/subcommand/wallet/inscribe.rs b/src/subcommand/wallet/inscribe.rs index 1efbe1f63a..6cf74f9b76 100644 --- a/src/subcommand/wallet/inscribe.rs +++ b/src/subcommand/wallet/inscribe.rs @@ -55,7 +55,7 @@ pub(crate) struct Inscribe { long, help = "Inscribe a multiple inscriptions defines in a yaml .", conflicts_with_all = &[ - "file", "destination", "cbor_metadata", "json_metadata", "satpoint", "reinscribe", "metaprotocol", "parent" + "cbor_metadata", "destination", "file", "json_metadata", "metaprotocol", "parent", "postage", "reinscribe", "satpoint" ] )] pub(crate) batch: Option, @@ -123,8 +123,7 @@ impl Inscribe { let chain = options.chain(); - let postage = self.postage.unwrap_or(TransactionBuilder::TARGET_POSTAGE); - + let postage; let destinations; let inscriptions; let mode; @@ -133,6 +132,9 @@ impl Inscribe { match (self.file, self.batch) { (Some(file), None) => { parent_info = Inscribe::get_parent_info(self.parent, &index, &utxos, &client, chain)?; + + postage = self.postage.unwrap_or(TransactionBuilder::TARGET_POSTAGE); + inscriptions = vec![Inscription::from_file( chain, file, @@ -142,7 +144,9 @@ impl Inscribe { metadata, self.compress, )?]; + mode = Mode::SeparateOutputs; + destinations = vec![match self.destination.clone() { Some(destination) => destination.require_network(chain.network())?, None => get_change_address(&client, chain)?, @@ -153,6 +157,11 @@ impl Inscribe { parent_info = Inscribe::get_parent_info(batchfile.parent, &index, &utxos, &client, chain)?; + postage = batchfile + .postage + .map(Amount::from_sat) + .unwrap_or(TransactionBuilder::TARGET_POSTAGE); + inscriptions = batchfile.inscriptions( chain, parent_info.as_ref().map(|info| info.tx_out.value), @@ -797,7 +806,7 @@ inscriptions: } ], parent: Some(parent), - mode: Mode::SeparateOutputs, + ..Default::default() } ); } diff --git a/src/subcommand/wallet/inscribe/batch.rs b/src/subcommand/wallet/inscribe/batch.rs index 9a7444eaf8..093c9a4d7b 100644 --- a/src/subcommand/wallet/inscribe/batch.rs +++ b/src/subcommand/wallet/inscribe/batch.rs @@ -518,8 +518,9 @@ impl Batch { } } -#[derive(PartialEq, Debug, Copy, Clone, Serialize, Deserialize)] +#[derive(PartialEq, Debug, Copy, Clone, Serialize, Deserialize, Default)] pub(crate) enum Mode { + #[default] #[serde(rename = "separate-outputs")] SeparateOutputs, #[serde(rename = "shared-output")] @@ -547,12 +548,13 @@ impl BatchEntry { } } -#[derive(Deserialize, PartialEq, Debug, Clone)] +#[derive(Deserialize, PartialEq, Debug, Clone, Default)] #[serde(deny_unknown_fields)] pub(crate) struct Batchfile { pub(crate) inscriptions: Vec, pub(crate) mode: Mode, pub(crate) parent: Option, + pub(crate) postage: Option, } impl Batchfile { diff --git a/tests/wallet/inscribe.rs b/tests/wallet/inscribe.rs index 0020bde3e0..f3c29e7004 100644 --- a/tests/wallet/inscribe.rs +++ b/tests/wallet/inscribe.rs @@ -1014,13 +1014,13 @@ fn batch_in_same_output_with_non_default_postage() { create_wallet(&rpc_server); - let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --batch batch.yaml --postage 777sat") + let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --batch batch.yaml") .write("inscription.txt", "Hello World") .write("tulip.png", [0; 555]) .write("meow.wav", [0; 2048]) .write( "batch.yaml", - "mode: shared-output\ninscriptions:\n- file: inscription.txt\n- file: tulip.png\n- file: meow.wav\n" + "mode: shared-output\npostage: 777\ninscriptions:\n- file: inscription.txt\n- file: tulip.png\n- file: meow.wav\n" ) .rpc_server(&rpc_server) .run_and_deserialize_output::(); @@ -1168,13 +1168,13 @@ fn batch_in_separate_outputs_with_parent_and_non_default_postage() { let parent_id = parent_output.inscriptions[0].id; - let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --batch batch.yaml --postage 777sat") + let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --batch batch.yaml") .write("inscription.txt", "Hello World") .write("tulip.png", [0; 555]) .write("meow.wav", [0; 2048]) .write( "batch.yaml", - format!("parent: {parent_id}\nmode: separate-outputs\ninscriptions:\n- file: inscription.txt\n- file: tulip.png\n- file: meow.wav\n") + format!("parent: {parent_id}\nmode: separate-outputs\npostage: 777\ninscriptions:\n- file: inscription.txt\n- file: tulip.png\n- file: meow.wav\n") ) .rpc_server(&rpc_server) .run_and_deserialize_output::(); From dd56f2c5a187f1347756cc140646c80920530781 Mon Sep 17 00:00:00 2001 From: raph Date: Tue, 21 Nov 2023 03:22:09 +0100 Subject: [PATCH 19/41] Add destination field to batch (#2701) --- batch.yaml | 2 + src/subcommand/wallet/inscribe.rs | 12 +--- src/subcommand/wallet/inscribe/batch.rs | 36 +++++++++- test-bitcoincore-rpc/src/lib.rs | 4 ++ test-bitcoincore-rpc/src/server.rs | 1 + test-bitcoincore-rpc/src/state.rs | 2 + tests/wallet/inscribe.rs | 91 +++++++++++++++++++++++++ 7 files changed, 136 insertions(+), 12 deletions(-) diff --git a/batch.yaml b/batch.yaml index 29a972b6b0..ffe29ac596 100644 --- a/batch.yaml +++ b/batch.yaml @@ -28,6 +28,7 @@ inscriptions: metus est et odio. Nullam venenatis, urna et molestie vestibulum, orci mi efficitur risus, eu malesuada diam lorem sed velit. Nam fermentum dolor et luctus euismod. + destination: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 - file: token.json metaprotocol: brc-20 @@ -35,3 +36,4 @@ inscriptions: - file: tulip.png metadata: author: Satoshi Nakamoto + destination: bc1pdqrcrxa8vx6gy75mfdfj84puhxffh4fq46h3gkp6jxdd0vjcsdyspfxcv6 diff --git a/src/subcommand/wallet/inscribe.rs b/src/subcommand/wallet/inscribe.rs index 6cf74f9b76..b12b5e67a8 100644 --- a/src/subcommand/wallet/inscribe.rs +++ b/src/subcommand/wallet/inscribe.rs @@ -162,7 +162,8 @@ impl Inscribe { .map(Amount::from_sat) .unwrap_or(TransactionBuilder::TARGET_POSTAGE); - inscriptions = batchfile.inscriptions( + (inscriptions, destinations) = batchfile.inscriptions( + &client, chain, parent_info.as_ref().map(|info| info.tx_out.value), metadata, @@ -171,15 +172,6 @@ impl Inscribe { )?; mode = batchfile.mode; - - let destination_count = match batchfile.mode { - Mode::SharedOutput => 1, - Mode::SeparateOutputs => inscriptions.len(), - }; - - destinations = (0..destination_count) - .map(|_| get_change_address(&client, chain)) - .collect::>>()?; } _ => unreachable!(), } diff --git a/src/subcommand/wallet/inscribe/batch.rs b/src/subcommand/wallet/inscribe/batch.rs index 093c9a4d7b..cc38055cc5 100644 --- a/src/subcommand/wallet/inscribe/batch.rs +++ b/src/subcommand/wallet/inscribe/batch.rs @@ -530,6 +530,7 @@ pub(crate) enum Mode { #[derive(Deserialize, Default, PartialEq, Debug, Clone)] #[serde(deny_unknown_fields)] pub(crate) struct BatchEntry { + pub(crate) destination: Option>, pub(crate) file: PathBuf, pub(crate) metadata: Option, pub(crate) metaprotocol: Option, @@ -570,14 +571,26 @@ impl Batchfile { pub(crate) fn inscriptions( &self, + client: &Client, chain: Chain, parent_value: Option, metadata: Option>, postage: Amount, compress: bool, - ) -> Result> { + ) -> Result<(Vec, Vec
    )> { assert!(!self.inscriptions.is_empty()); + if self + .inscriptions + .iter() + .any(|entry| entry.destination.is_some()) + && self.mode == Mode::SharedOutput + { + return Err(anyhow!( + "individual inscription destinations cannot be set in shared-output mode" + )); + } + if metadata.is_some() { assert!(self .inscriptions @@ -605,6 +618,25 @@ impl Batchfile { pointer += postage.to_sat(); } - Ok(inscriptions) + let destinations = match self.mode { + Mode::SharedOutput => vec![get_change_address(client, chain)?], + Mode::SeparateOutputs => self + .inscriptions + .iter() + .map(|entry| { + entry.destination.as_ref().map_or_else( + || get_change_address(client, chain), + |address| { + address + .clone() + .require_network(chain.network()) + .map_err(|e| e.into()) + }, + ) + }) + .collect::, _>>()?, + }; + + Ok((inscriptions, destinations)) } } diff --git a/test-bitcoincore-rpc/src/lib.rs b/test-bitcoincore-rpc/src/lib.rs index b29cc95d98..56c50e45a8 100644 --- a/test-bitcoincore-rpc/src/lib.rs +++ b/test-bitcoincore-rpc/src/lib.rs @@ -242,6 +242,10 @@ impl Handle { pub fn loaded_wallets(&self) -> BTreeSet { self.state().loaded_wallets.clone() } + + pub fn get_change_addresses(&self) -> Vec
    { + self.state().change_addresses.clone() + } } impl Drop for Handle { diff --git a/test-bitcoincore-rpc/src/server.rs b/test-bitcoincore-rpc/src/server.rs index 96d8ae83aa..006f04b028 100644 --- a/test-bitcoincore-rpc/src/server.rs +++ b/test-bitcoincore-rpc/src/server.rs @@ -479,6 +479,7 @@ impl Api for Server { let key_pair = KeyPair::new(&secp256k1, &mut rand::thread_rng()); let (public_key, _parity) = XOnlyPublicKey::from_keypair(&key_pair); let address = Address::p2tr(&secp256k1, public_key, None, self.network); + self.state().change_addresses.push(address.clone()); Ok(address) } diff --git a/test-bitcoincore-rpc/src/state.rs b/test-bitcoincore-rpc/src/state.rs index b2d09b0110..870794c471 100644 --- a/test-bitcoincore-rpc/src/state.rs +++ b/test-bitcoincore-rpc/src/state.rs @@ -2,6 +2,7 @@ use super::*; pub(crate) struct State { pub(crate) blocks: BTreeMap, + pub(crate) change_addresses: Vec
    , pub(crate) descriptors: Vec, pub(crate) fail_lock_unspent: bool, pub(crate) hashes: Vec, @@ -29,6 +30,7 @@ impl State { Self { blocks, + change_addresses: Vec::new(), descriptors: Vec::new(), fail_lock_unspent, hashes, diff --git a/tests/wallet/inscribe.rs b/tests/wallet/inscribe.rs index f3c29e7004..3f189ffb1b 100644 --- a/tests/wallet/inscribe.rs +++ b/tests/wallet/inscribe.rs @@ -1343,3 +1343,94 @@ fn inscriptions_are_not_compressed_if_no_space_is_saved_by_compression() { assert_eq!(response.status(), StatusCode::OK); assert_eq!(response.text().unwrap(), "foo"); } + +#[test] +fn batch_inscribe_fails_if_invalid_network_destination_address() { + let rpc_server = test_bitcoincore_rpc::builder() + .network(Network::Regtest) + .build(); + + rpc_server.mine_blocks(1); + + assert_eq!(rpc_server.descriptors().len(), 0); + + create_wallet(&rpc_server); + + CommandBuilder::new("--regtest wallet inscribe --fee-rate 2.1 --batch batch.yaml") + .write("inscription.txt", "Hello World") + .write("batch.yaml", "mode: separate-outputs\ninscriptions:\n- file: inscription.txt\n destination: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4") + .rpc_server(&rpc_server) + .stderr_regex("error: address bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 belongs to network bitcoin which is different from required regtest\n") + .expected_exit_code(1) + .run_and_extract_stdout(); +} + +#[test] +fn batch_inscribe_fails_with_shared_output_and_destination_set() { + let rpc_server = test_bitcoincore_rpc::spawn(); + rpc_server.mine_blocks(1); + + assert_eq!(rpc_server.descriptors().len(), 0); + + create_wallet(&rpc_server); + + CommandBuilder::new("wallet inscribe --fee-rate 2.1 --batch batch.yaml") + .write("inscription.txt", "Hello World") + .write("tulip.png", "") + .write("batch.yaml", "mode: shared-output\ninscriptions:\n- file: inscription.txt\n destination: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4\n- file: tulip.png") + .rpc_server(&rpc_server) + .expected_exit_code(1) + .stderr_regex("error: individual inscription destinations cannot be set in shared-output mode\n") + .run_and_extract_stdout(); +} + +#[test] +fn batch_inscribe_works_with_some_destinations_set_and_others_not() { + let rpc_server = test_bitcoincore_rpc::spawn(); + rpc_server.mine_blocks(1); + + assert_eq!(rpc_server.descriptors().len(), 0); + + create_wallet(&rpc_server); + + let output = CommandBuilder::new("wallet inscribe --batch batch.yaml --fee-rate 55") + .write("inscription.txt", "Hello World") + .write("tulip.png", [0; 555]) + .write("meow.wav", [0; 2048]) + .write( + "batch.yaml", + "mode: separate-outputs\ninscriptions:\n- file: inscription.txt\n destination: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4\n- file: tulip.png\n- file: meow.wav\n destination: bc1pxwww0ct9ue7e8tdnlmug5m2tamfn7q06sahstg39ys4c9f3340qqxrdu9k\n" + ) + .rpc_server(&rpc_server) + .run_and_deserialize_output::(); + + rpc_server.mine_blocks(1); + + assert_eq!(rpc_server.descriptors().len(), 3); + + let ord_server = TestServer::spawn_with_args(&rpc_server, &[]); + + ord_server.assert_response_regex( + format!("/inscription/{}", output.inscriptions[0].id), + ".* +
    address
    +
    bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
    .*", + ); + + ord_server.assert_response_regex( + format!("/inscription/{}", output.inscriptions[1].id), + format!( + ".* +
    address
    +
    {}
    .*", + rpc_server.get_change_addresses()[0] + ), + ); + + ord_server.assert_response_regex( + format!("/inscription/{}", output.inscriptions[2].id), + ".* +
    address
    +
    bc1pxwww0ct9ue7e8tdnlmug5m2tamfn7q06sahstg39ys4c9f3340qqxrdu9k
    .*", + ); +} From 8f703d1a8cb4e00188f5cfc347bd6e3cb5e918c5 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 21 Nov 2023 14:18:58 -0800 Subject: [PATCH 20/41] Use sequence numbers database keys (#2664) --- Cargo.lock | 160 +++--- Cargo.toml | 2 +- justfile | 13 + src/chain.rs | 2 +- src/degree.rs | 26 +- src/epoch.rs | 24 +- src/height.rs | 28 +- src/index.rs | 589 ++++++++++++----------- src/index/entry.rs | 363 +++++--------- src/index/reorg.rs | 35 +- src/index/rtx.rs | 4 +- src/index/updater.rs | 85 ++-- src/index/updater/inscription_updater.rs | 169 ++++--- src/index/updater/rune_updater.rs | 69 +-- src/lib.rs | 7 +- src/options.rs | 6 +- src/rarity.rs | 12 +- src/runes/etching.rs | 2 +- src/runes/rune.rs | 6 +- src/runes/runestone.rs | 2 +- src/sat.rs | 38 +- src/subcommand/info.rs | 6 +- src/subcommand/server.rs | 44 +- src/subcommand/supply.rs | 2 +- src/subcommand/traits.rs | 8 +- src/teleburn.rs | 8 +- src/templates/block.rs | 4 +- src/templates/blocks.rs | 4 +- src/templates/children.rs | 2 +- src/templates/clock.rs | 9 +- src/templates/input.rs | 2 +- src/templates/inscription.rs | 8 +- src/templates/inscriptions.rs | 20 +- src/templates/inscriptions_block.rs | 10 +- src/templates/sat.rs | 8 +- templates/blocks.html | 4 +- 36 files changed, 849 insertions(+), 932 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c1dcbf815..6ff7f69431 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,20 +160,22 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.9.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 3.1.0", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-compression" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2" +checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5" dependencies = [ "brotli", "flate2", @@ -202,11 +204,11 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "cfg-if 1.0.0", "concurrent-queue", - "futures-lite", + "futures-lite 1.13.0", "log", "parking", "polling", @@ -222,7 +224,18 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655b9c7fe787d3b25cc0f804a1a8401790f0c5bc395beb5a64dc77d8de079105" +dependencies = [ + "event-listener 3.1.0", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -233,7 +246,7 @@ checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" dependencies = [ "async-io", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] @@ -286,7 +299,7 @@ dependencies = [ "async-io", "base64 0.13.1", "futures", - "futures-lite", + "futures-lite 1.13.0", "generic_static", "http", "log", @@ -438,9 +451,9 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.30.1" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e99ff7289b20a7385f66a0feda78af2fc119d28fb56aea8886a9cd0a4abdd75" +checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ "bech32", "bitcoin-private", @@ -495,16 +508,16 @@ dependencies = [ [[package]] name = "blocking" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ "async-channel", - "async-lock", + "async-lock 3.1.1", "async-task", "fastrand 2.0.1", "futures-io", - "futures-lite", + "futures-lite 2.0.1", "piper", "tracing", ] @@ -636,9 +649,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.7" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" +checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" dependencies = [ "clap_builder", "clap_derive", @@ -646,9 +659,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.7" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" +checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" dependencies = [ "anstream", "anstyle", @@ -1018,9 +1031,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -1037,9 +1050,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys 0.48.0", @@ -1051,6 +1064,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +dependencies = [ + "event-listener 3.1.0", + "pin-project-lite", +] + [[package]] name = "executable-path" version = "1.0.0" @@ -1175,6 +1209,16 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.29" @@ -1311,9 +1355,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -1321,7 +1365,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap", "slab", "tokio", "tokio-util 0.7.10", @@ -1334,12 +1378,6 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.2" @@ -1402,9 +1440,9 @@ checksum = "459a0ca33ee92551e0a3bb1774f2d3bdd1c09fb6341845736662dd25e1fcb52a" [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1522,16 +1560,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.1.0" @@ -1539,7 +1567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown", ] [[package]] @@ -1588,7 +1616,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -2287,16 +2315,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "pyo3-build-config" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5" -dependencies = [ - "once_cell", - "target-lexicon", -] - [[package]] name = "quick-xml" version = "0.30.0" @@ -2381,11 +2399,9 @@ dependencies = [ [[package]] name = "redb" version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58f6da33e3b54de2ef82201ce2b465e67f337deb15d45f54355e0f77202bb4" +source = "git+https://github.com/cberner/redb.git?rev=c29eed6f866d50a2c79042fe55cf898a5aba1579#c29eed6f866d50a2c79042fe55cf898a5aba1579" dependencies = [ "libc", - "pyo3-build-config", ] [[package]] @@ -2601,9 +2617,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.4.1", "errno", @@ -2614,9 +2630,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", "ring 0.17.5", @@ -2795,7 +2811,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.1.0", + "indexmap", "itoa", "ryu", "serde", @@ -2829,7 +2845,7 @@ version = "0.9.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" dependencies = [ - "indexmap 2.1.0", + "indexmap", "itoa", "ryu", "serde", @@ -3019,12 +3035,6 @@ dependencies = [ "libc", ] -[[package]] -name = "target-lexicon" -version = "0.12.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" - [[package]] name = "tempfile" version = "3.8.1" @@ -3034,15 +3044,15 @@ dependencies = [ "cfg-if 1.0.0", "fastrand 2.0.1", "redox_syscall 0.4.1", - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] diff --git a/Cargo.toml b/Cargo.toml index d9570eae39..bbaeed4494 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ mime_guess = "2.0.4" miniscript = "10.0.0" mp4 = "0.14.0" ord-bitcoincore-rpc = "0.17.1" -redb = "1.0.5" +redb = { git = "https://github.com/cberner/redb.git", rev = "c29eed6f866d50a2c79042fe55cf898a5aba1579" } regex = "1.6.0" rss = "2.0.1" rust-embed = "8.0.0" diff --git a/justfile b/justfile index 04c9dcd284..3ecc95c785 100644 --- a/justfile +++ b/justfile @@ -162,6 +162,19 @@ benchmark-revision rev: rsync -avz benchmark/checkout root@ordinals.net:benchmark/checkout ssh root@ordinals.net 'cd benchmark && ./checkout {{rev}}' +benchmark-branch branch: + #/usr/bin/env bash + # rm -f master.redb + rm -f {{branch}}.redb + # git checkout master + # cargo build --release + # time ./target/release/ord --index master.redb index update + # ll master.redb + git checkout {{branch}} + cargo build --release + time ./target/release/ord --index {{branch}}.redb index update + ll {{branch}}.redb + build-snapshots: #!/usr/bin/env bash set -euxo pipefail diff --git a/src/chain.rs b/src/chain.rs index 3cb1e1401a..89c8123bfd 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -38,7 +38,7 @@ impl Chain { } } - pub(crate) fn first_inscription_height(self) -> u64 { + pub(crate) fn first_inscription_height(self) -> u32 { match self { Self::Mainnet => 767430, Self::Regtest => 0, diff --git a/src/degree.rs b/src/degree.rs index d41d872e59..fb1d77157b 100644 --- a/src/degree.rs +++ b/src/degree.rs @@ -2,9 +2,9 @@ use super::*; #[derive(PartialEq, Debug)] pub(crate) struct Degree { - pub(crate) hour: u64, - pub(crate) minute: u64, - pub(crate) second: u64, + pub(crate) hour: u32, + pub(crate) minute: u32, + pub(crate) second: u32, pub(crate) third: u64, } @@ -34,7 +34,7 @@ impl From for Degree { mod tests { use super::*; - fn case(sat: u64, hour: u64, minute: u64, second: u64, third: u64) { + fn case(sat: u64, hour: u32, minute: u32, second: u32, third: u64) { assert_eq!( Degree::from(Sat(sat)), Degree { @@ -52,20 +52,22 @@ mod tests { case(1, 0, 0, 0, 1); case(5_000_000_000, 0, 1, 1, 0); case( - 5_000_000_000 * DIFFCHANGE_INTERVAL, + 5_000_000_000 * u64::from(DIFFCHANGE_INTERVAL), 0, DIFFCHANGE_INTERVAL, 0, 0, ); - case(5_000_000_000 * SUBSIDY_HALVING_INTERVAL, 0, 0, 336, 0); case( - 5_000_000_000 * SUBSIDY_HALVING_INTERVAL - + 2_500_000_000 * SUBSIDY_HALVING_INTERVAL - + 1_250_000_000 * SUBSIDY_HALVING_INTERVAL - + 625_000_000 * SUBSIDY_HALVING_INTERVAL - + 312_500_000 * SUBSIDY_HALVING_INTERVAL - + 156_250_000 * SUBSIDY_HALVING_INTERVAL, + 5_000_000_000 * u64::from(SUBSIDY_HALVING_INTERVAL), + 0, + 0, + 336, + 0, + ); + case( + (5_000_000_000 + 2_500_000_000 + 1_250_000_000 + 625_000_000 + 312_500_000 + 156_250_000) + * u64::from(SUBSIDY_HALVING_INTERVAL), 1, 0, 0, diff --git a/src/epoch.rs b/src/epoch.rs index 328b09af32..d8157897d8 100644 --- a/src/epoch.rs +++ b/src/epoch.rs @@ -1,7 +1,7 @@ use super::*; #[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Serialize, PartialOrd)] -pub(crate) struct Epoch(pub(crate) u64); +pub(crate) struct Epoch(pub(crate) u32); impl Epoch { pub(crate) const STARTING_SATS: [Sat; 34] = [ @@ -61,8 +61,8 @@ impl Epoch { } } -impl PartialEq for Epoch { - fn eq(&self, other: &u64) -> bool { +impl PartialEq for Epoch { + fn eq(&self, other: &u32) -> bool { self.0 == *other } } @@ -156,11 +156,11 @@ mod tests { assert_eq!(Epoch(0).starting_sat(), 0); assert_eq!( Epoch(1).starting_sat(), - Epoch(0).subsidy() * SUBSIDY_HALVING_INTERVAL + Epoch(0).subsidy() * u64::from(SUBSIDY_HALVING_INTERVAL) ); assert_eq!( Epoch(2).starting_sat(), - (Epoch(0).subsidy() + Epoch(1).subsidy()) * SUBSIDY_HALVING_INTERVAL + (Epoch(0).subsidy() + Epoch(1).subsidy()) * u64::from(SUBSIDY_HALVING_INTERVAL) ); assert_eq!(Epoch(33).starting_sat(), Sat(Sat::SUPPLY)); assert_eq!(Epoch(34).starting_sat(), Sat(Sat::SUPPLY)); @@ -174,7 +174,7 @@ mod tests { for epoch in 0..34 { epoch_sats.push(sat); - sat += SUBSIDY_HALVING_INTERVAL * Epoch(epoch).subsidy(); + sat += u64::from(SUBSIDY_HALVING_INTERVAL) * Epoch(epoch).subsidy(); } assert_eq!(Epoch::STARTING_SATS.as_slice(), epoch_sats); @@ -209,11 +209,17 @@ mod tests { if epoch > 0 { assert_eq!( Epoch::from(Sat(starting_sat.n() - 1)), - Epoch(epoch as u64 - 1) + Epoch(u32::try_from(epoch).unwrap() - 1) ); } - assert_eq!(Epoch::from(starting_sat), Epoch(epoch as u64)); - assert_eq!(Epoch::from(starting_sat + 1), Epoch(epoch as u64)); + assert_eq!( + Epoch::from(starting_sat), + Epoch(u32::try_from(epoch).unwrap()) + ); + assert_eq!( + Epoch::from(starting_sat + 1), + Epoch(u32::try_from(epoch).unwrap()) + ); } assert_eq!(Epoch::from(Sat(0)), 0); assert_eq!(Epoch::from(Sat(1)), 0); diff --git a/src/height.rs b/src/height.rs index 75ac7ec8ab..e96a66f8f4 100644 --- a/src/height.rs +++ b/src/height.rs @@ -1,10 +1,10 @@ use super::*; #[derive(Copy, Clone, Debug, Display, FromStr, Ord, Eq, Serialize, PartialEq, PartialOrd)] -pub(crate) struct Height(pub(crate) u64); +pub(crate) struct Height(pub(crate) u32); impl Height { - pub(crate) fn n(self) -> u64 { + pub(crate) fn n(self) -> u32 { self.0 } @@ -16,32 +16,32 @@ impl Height { let epoch = Epoch::from(self); let epoch_starting_sat = epoch.starting_sat(); let epoch_starting_height = epoch.starting_height(); - epoch_starting_sat + (self - epoch_starting_height.n()).n() * epoch.subsidy() + epoch_starting_sat + u64::from(self.n() - epoch_starting_height.n()) * epoch.subsidy() } - pub(crate) fn period_offset(self) -> u64 { + pub(crate) fn period_offset(self) -> u32 { self.0 % DIFFCHANGE_INTERVAL } } -impl Add for Height { +impl Add for Height { type Output = Self; - fn add(self, other: u64) -> Height { + fn add(self, other: u32) -> Height { Self(self.0 + other) } } -impl Sub for Height { +impl Sub for Height { type Output = Self; - fn sub(self, other: u64) -> Height { + fn sub(self, other: u32) -> Height { Self(self.0 - other) } } -impl PartialEq for Height { - fn eq(&self, other: &u64) -> bool { +impl PartialEq for Height { + fn eq(&self, other: &u32) -> bool { self.0 == *other } } @@ -95,18 +95,18 @@ mod tests { assert_eq!(Height(1).starting_sat(), 5000000000); assert_eq!( Height(SUBSIDY_HALVING_INTERVAL - 1).starting_sat(), - (SUBSIDY_HALVING_INTERVAL - 1) * 5000000000 + (u64::from(SUBSIDY_HALVING_INTERVAL) - 1) * 5000000000 ); assert_eq!( Height(SUBSIDY_HALVING_INTERVAL).starting_sat(), - SUBSIDY_HALVING_INTERVAL * 5000000000 + u64::from(SUBSIDY_HALVING_INTERVAL) * 5000000000 ); assert_eq!( Height(SUBSIDY_HALVING_INTERVAL + 1).starting_sat(), - SUBSIDY_HALVING_INTERVAL * 5000000000 + 2500000000 + u64::from(SUBSIDY_HALVING_INTERVAL) * 5000000000 + 2500000000 ); assert_eq!( - Height(u64::max_value()).starting_sat(), + Height(u32::max_value()).starting_sat(), *Epoch::STARTING_SATS.last().unwrap() ); } diff --git a/src/index.rs b/src/index.rs index c9a21be799..eef4051eaa 100644 --- a/src/index.rs +++ b/src/index.rs @@ -35,7 +35,7 @@ mod updater; #[cfg(test)] pub(crate) mod testing; -const SCHEMA_VERSION: u64 = 11; +const SCHEMA_VERSION: u64 = 12; macro_rules! define_table { ($name:ident, $key:ty, $value:ty) => { @@ -50,26 +50,26 @@ macro_rules! define_multimap_table { }; } -define_multimap_table! { INSCRIPTION_ID_TO_CHILDREN, &InscriptionIdValue, &InscriptionIdValue } -define_multimap_table! { SATPOINT_TO_INSCRIPTION_ID, &SatPointValue, &InscriptionIdValue } -define_multimap_table! { SAT_TO_INSCRIPTION_ID, u64, &InscriptionIdValue } -define_table! { HEIGHT_TO_BLOCK_HASH, u64, &BlockHashValue } -define_table! { HEIGHT_TO_LAST_SEQUENCE_NUMBER, u64, u64 } -define_table! { HOME_INSCRIPTIONS, u64, &InscriptionIdValue } -define_table! { INSCRIPTION_ID_TO_INSCRIPTION_ENTRY, &InscriptionIdValue, InscriptionEntryValue } -define_table! { INSCRIPTION_ID_TO_RUNE, &InscriptionIdValue, u128 } -define_table! { INSCRIPTION_ID_TO_SATPOINT, &InscriptionIdValue, &SatPointValue } -define_table! { INSCRIPTION_NUMBER_TO_INSCRIPTION_ID, i64, &InscriptionIdValue } +define_multimap_table! { SATPOINT_TO_SEQUENCE_NUMBER, &SatPointValue, u32 } +define_multimap_table! { SAT_TO_SEQUENCE_NUMBER, u64, u32 } +define_multimap_table! { SEQUENCE_NUMBER_TO_CHILDREN, u32, u32 } +define_table! { HEIGHT_TO_BLOCK_HASH, u32, &BlockHashValue } +define_table! { HEIGHT_TO_LAST_SEQUENCE_NUMBER, u32, u32 } +define_table! { HOME_INSCRIPTIONS, u32, InscriptionIdValue } +define_table! { INSCRIPTION_ID_TO_SEQUENCE_NUMBER, InscriptionIdValue, u32 } +define_table! { INSCRIPTION_NUMBER_TO_SEQUENCE_NUMBER, i32, u32 } define_table! { OUTPOINT_TO_RUNE_BALANCES, &OutPointValue, &[u8] } define_table! { OUTPOINT_TO_SAT_RANGES, &OutPointValue, &[u8] } define_table! { OUTPOINT_TO_VALUE, &OutPointValue, u64} define_table! { RUNE_ID_TO_RUNE_ENTRY, RuneIdValue, RuneEntryValue } define_table! { RUNE_TO_RUNE_ID, u128, RuneIdValue } define_table! { SAT_TO_SATPOINT, u64, &SatPointValue } -define_table! { SEQUENCE_NUMBER_TO_INSCRIPTION_ID, u64, &InscriptionIdValue } +define_table! { SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY, u32, InscriptionEntryValue } +define_table! { SEQUENCE_NUMBER_TO_RUNE, u32, u128 } +define_table! { SEQUENCE_NUMBER_TO_SATPOINT, u32, &SatPointValue } define_table! { STATISTIC_TO_COUNT, u64, u64 } define_table! { TRANSACTION_ID_TO_RUNE, &TxidValue, u128 } -define_table! { WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP, u64, u128 } +define_table! { WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP, u32, u128 } #[derive(Debug, PartialEq)] pub enum List { @@ -106,7 +106,7 @@ impl From for u64 { #[derive(Serialize)] pub(crate) struct Info { - pub(crate) blocks_indexed: u64, + pub(crate) blocks_indexed: u32, pub(crate) branch_pages: u64, pub(crate) fragmented_bytes: u64, pub(crate) index_file_size: u64, @@ -124,7 +124,7 @@ pub(crate) struct Info { #[derive(Serialize)] pub(crate) struct TransactionInfo { - pub(crate) starting_block_count: u64, + pub(crate) starting_block_count: u32, pub(crate) starting_timestamp: u128, } @@ -155,10 +155,10 @@ pub(crate) struct Index { client: Client, database: Database, durability: redb::Durability, - first_inscription_height: u64, + first_inscription_height: u32, genesis_block_coinbase_transaction: Transaction, genesis_block_coinbase_txid: Txid, - height_limit: Option, + height_limit: Option, index_runes: bool, index_sats: bool, options: Options, @@ -272,22 +272,22 @@ impl Index { tx.set_durability(durability); - tx.open_multimap_table(INSCRIPTION_ID_TO_CHILDREN)?; - tx.open_multimap_table(SATPOINT_TO_INSCRIPTION_ID)?; - tx.open_multimap_table(SAT_TO_INSCRIPTION_ID)?; + tx.open_multimap_table(SATPOINT_TO_SEQUENCE_NUMBER)?; + tx.open_multimap_table(SAT_TO_SEQUENCE_NUMBER)?; + tx.open_multimap_table(SEQUENCE_NUMBER_TO_CHILDREN)?; tx.open_table(HEIGHT_TO_BLOCK_HASH)?; tx.open_table(HEIGHT_TO_LAST_SEQUENCE_NUMBER)?; tx.open_table(HOME_INSCRIPTIONS)?; - tx.open_table(INSCRIPTION_ID_TO_INSCRIPTION_ENTRY)?; - tx.open_table(INSCRIPTION_ID_TO_RUNE)?; - tx.open_table(INSCRIPTION_ID_TO_SATPOINT)?; - tx.open_table(INSCRIPTION_NUMBER_TO_INSCRIPTION_ID)?; + tx.open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)?; + tx.open_table(INSCRIPTION_NUMBER_TO_SEQUENCE_NUMBER)?; tx.open_table(OUTPOINT_TO_RUNE_BALANCES)?; tx.open_table(OUTPOINT_TO_VALUE)?; tx.open_table(RUNE_ID_TO_RUNE_ENTRY)?; tx.open_table(RUNE_TO_RUNE_ID)?; tx.open_table(SAT_TO_SATPOINT)?; - tx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID)?; + tx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; + tx.open_table(SEQUENCE_NUMBER_TO_RUNE)?; + tx.open_table(SEQUENCE_NUMBER_TO_SATPOINT)?; tx.open_table(TRANSACTION_ID_TO_RUNE)?; tx.open_table(WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP)?; @@ -515,25 +515,26 @@ impl Index { log::info!("exporting database tables to {filename}"); - let inscription_entries = rtx.open_table(INSCRIPTION_ID_TO_INSCRIPTION_ENTRY)?; + let sequence_number_to_satpoint = rtx.open_table(SEQUENCE_NUMBER_TO_SATPOINT)?; - for result in rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID)?.iter()? { - let (_number, id) = result?; - let inscription_id = InscriptionId::load(*id.value()); - - let satpoint = self - .get_inscription_satpoint_by_id(inscription_id)? - .unwrap(); + for result in rtx + .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)? + .iter()? + { + let entry = result?; + let sequence_number = entry.0.value(); + let entry = InscriptionEntry::load(entry.1.value()); + let satpoint = SatPoint::load( + *sequence_number_to_satpoint + .get(sequence_number)? + .unwrap() + .value(), + ); write!( writer, "{}\t{}\t{}", - inscription_entries - .get(&id.value())? - .map(|entry| InscriptionEntry::load(entry.value()).inscription_number) - .unwrap(), - inscription_id, - satpoint + entry.inscription_number, entry.id, satpoint )?; if include_addresses { @@ -605,7 +606,7 @@ impl Index { .unwrap_or(0) } - pub(crate) fn block_count(&self) -> Result { + pub(crate) fn block_count(&self) -> Result { self.begin_read()?.block_count() } @@ -613,11 +614,11 @@ impl Index { self.begin_read()?.block_height() } - pub(crate) fn block_hash(&self, height: Option) -> Result> { + pub(crate) fn block_hash(&self, height: Option) -> Result> { self.begin_read()?.block_hash(height) } - pub(crate) fn blocks(&self, take: usize) -> Result> { + pub(crate) fn blocks(&self, take: usize) -> Result> { let rtx = self.begin_read()?; let block_count = rtx.block_count()?; @@ -705,7 +706,7 @@ impl Index { &self, outpoint: OutPoint, ) -> Result> { - let rtx = &self.database.begin_read()?; + let rtx = self.database.begin_read()?; let outpoint_to_balances = rtx.open_table(OUTPOINT_TO_RUNE_BALANCES)?; @@ -783,11 +784,11 @@ impl Index { self.client.get_block_header_info(&hash).into_option() } - pub(crate) fn get_block_by_height(&self, height: u64) -> Result> { + pub(crate) fn get_block_by_height(&self, height: u32) -> Result> { Ok( self .client - .get_block_hash(height) + .get_block_hash(height.into()) .into_option()? .map(|hash| self.client.get_block(&hash)) .transpose()?, @@ -803,16 +804,23 @@ impl Index { page_size: usize, page_index: usize, ) -> Result<(Vec, bool)> { - let mut collections = self - .database - .begin_read()? - .open_multimap_table(INSCRIPTION_ID_TO_CHILDREN)? + let rtx = self.database.begin_read()?; + + let sequence_number_to_inscription_entry = + rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; + + let mut collections = rtx + .open_multimap_table(SEQUENCE_NUMBER_TO_CHILDREN)? .iter()? - .skip(page_index * page_size) - .take(page_size + 1) + .skip(page_index.saturating_mul(page_size)) + .take(page_size.saturating_add(1)) .map(|result| { result - .map(|(key, _value)| InscriptionId::load(*key.value())) + .and_then(|(parent, _children)| { + sequence_number_to_inscription_entry + .get(parent.value()) + .map(|entry| InscriptionEntry::load(entry.unwrap().value()).id) + }) .map_err(|err| err.into()) }) .collect::>>()?; @@ -831,35 +839,83 @@ impl Index { &self, inscription_id: InscriptionId, ) -> Result> { - self - .database - .begin_read()? - .open_multimap_table(INSCRIPTION_ID_TO_CHILDREN)? + let rtx = self.database.begin_read()?; + + let Some(sequence_number) = rtx + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? .get(&inscription_id.store())? - .map(|result| { - result - .map(|inscription_id| InscriptionId::load(*inscription_id.value())) - .map_err(|err| err.into()) - }) - .collect() + .map(|sequence_number| sequence_number.value()) + else { + return Ok(Vec::new()); + }; + + self + .get_children_by_sequence_number_paginated(sequence_number, usize::max_value(), 0) + .map(|(children, _more)| children) } - pub(crate) fn get_children_by_inscription_id_paginated( + #[cfg(test)] + pub(crate) fn get_parent_by_inscription_id( &self, inscription_id: InscriptionId, + ) -> InscriptionId { + let rtx = self.database.begin_read().unwrap(); + + let sequence_number = rtx + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER) + .unwrap() + .get(&inscription_id.store()) + .unwrap() + .unwrap() + .value(); + + let sequence_number_to_inscription_entry = rtx + .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY) + .unwrap(); + + let parent_sequence_number = InscriptionEntry::load( + sequence_number_to_inscription_entry + .get(sequence_number) + .unwrap() + .unwrap() + .value(), + ) + .parent + .unwrap(); + + let entry = InscriptionEntry::load( + sequence_number_to_inscription_entry + .get(parent_sequence_number) + .unwrap() + .unwrap() + .value(), + ); + + entry.id + } + + pub(crate) fn get_children_by_sequence_number_paginated( + &self, + sequence_number: u32, page_size: usize, page_index: usize, ) -> Result<(Vec, bool)> { - let mut children = self - .database - .begin_read()? - .open_multimap_table(INSCRIPTION_ID_TO_CHILDREN)? - .get(&inscription_id.store())? + let rtx = self.database.begin_read()?; + + let sequence_number_to_entry = rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; + + let mut children = rtx + .open_multimap_table(SEQUENCE_NUMBER_TO_CHILDREN)? + .get(sequence_number)? .skip(page_index * page_size) - .take(page_size + 1) + .take(page_size.saturating_add(1)) .map(|result| { result - .map(|inscription_id| InscriptionId::load(*inscription_id.value())) + .and_then(|sequence_number| { + sequence_number_to_entry + .get(sequence_number.value()) + .map(|entry| InscriptionEntry::load(entry.unwrap().value()).id) + }) .map_err(|err| err.into()) }) .collect::>>()?; @@ -884,110 +940,111 @@ impl Index { ) } - pub(crate) fn get_rune_by_inscription_id( - &self, - inscription_id: InscriptionId, - ) -> Result> { + pub(crate) fn get_rune_by_sequence_number(&self, sequence_number: u32) -> Result> { Ok( self .database .begin_read()? - .open_table(INSCRIPTION_ID_TO_RUNE)? - .get(&inscription_id.store())? + .open_table(SEQUENCE_NUMBER_TO_RUNE)? + .get(sequence_number)? .map(|entry| Rune(entry.value())), ) } pub(crate) fn get_inscription_ids_by_sat(&self, sat: Sat) -> Result> { - let rtx = &self.database.begin_read()?; + let rtx = self.database.begin_read()?; + + let sequence_number_to_inscription_entry = + rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; - let ids = rtx - .open_multimap_table(SAT_TO_INSCRIPTION_ID)? + let mut ids = rtx + .open_multimap_table(SAT_TO_SEQUENCE_NUMBER)? .get(&sat.n())? .map(|result| { result - .map(|inscription_id| InscriptionId::load(*inscription_id.value())) + .and_then(|sequence_number| { + let sequence_number = sequence_number.value(); + sequence_number_to_inscription_entry + .get(sequence_number) + .map(|entry| { + ( + sequence_number, + InscriptionEntry::load(entry.unwrap().value()).id, + ) + }) + }) .map_err(|err| err.into()) }) - .collect::>>()?; - - if ids.len() > 1 { - let inscription_id_to_entry = rtx.open_table(INSCRIPTION_ID_TO_INSCRIPTION_ENTRY)?; - - let mut seq_nums = Vec::new(); - for id in &ids { - seq_nums.push( - InscriptionEntry::load(inscription_id_to_entry.get(&id.store())?.unwrap().value()) - .sequence_number, - ) - } + .collect::>>()?; - let mut ids = seq_nums - .into_iter() - .zip(ids) - .collect::>(); - - ids.sort_by_key(|(sequence_number, _)| *sequence_number); + ids.sort_by_key(|(sequence_number, _id)| *sequence_number); - Ok(ids.into_iter().map(|(_, id)| id).collect()) - } else { - Ok(ids) - } + Ok(ids.into_iter().map(|(_sequence_number, id)| id).collect()) } pub(crate) fn get_inscription_id_by_sequence_number( &self, - n: u64, + n: u32, ) -> Result> { Ok( self .database .begin_read()? - .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID)? + .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)? .get(&n)? - .map(|id| Entry::load(*id.value())), + .map(|entry| InscriptionEntry::load(entry.value()).id), ) } pub(crate) fn get_inscription_id_by_inscription_number( &self, - n: i64, + inscription_number: i32, ) -> Result> { - Ok( - self - .database - .begin_read()? - .open_table(INSCRIPTION_NUMBER_TO_INSCRIPTION_ID)? - .get(&n)? - .map(|id| Entry::load(*id.value())), - ) + let rtx = self.database.begin_read()?; + + let Some(sequence_number) = rtx + .open_table(INSCRIPTION_NUMBER_TO_SEQUENCE_NUMBER)? + .get(inscription_number)? + .map(|guard| guard.value()) + else { + return Ok(None); + }; + + let inscription_id = rtx + .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)? + .get(&sequence_number)? + .map(|entry| InscriptionEntry::load(entry.value()).id); + + Ok(inscription_id) } pub(crate) fn get_inscription_satpoint_by_id( &self, inscription_id: InscriptionId, ) -> Result> { - Ok( - self - .database - .begin_read()? - .open_table(INSCRIPTION_ID_TO_SATPOINT)? - .get(&inscription_id.store())? - .map(|satpoint| Entry::load(*satpoint.value())), - ) + let rtx = self.database.begin_read()?; + + let Some(sequence_number) = rtx + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? + .get(&inscription_id.store())? + .map(|guard| guard.value()) + else { + return Ok(None); + }; + + let satpoint = rtx + .open_table(SEQUENCE_NUMBER_TO_SATPOINT)? + .get(sequence_number)? + .map(|satpoint| Entry::load(*satpoint.value())); + + Ok(satpoint) } pub(crate) fn get_inscription_by_id( &self, inscription_id: InscriptionId, ) -> Result> { - if self - .database - .begin_read()? - .open_table(INSCRIPTION_ID_TO_SATPOINT)? - .get(&inscription_id.store())? - .is_none() - { + if !self.inscription_exists(inscription_id)? { return Ok(None); } @@ -1004,7 +1061,7 @@ impl Index { self .database .begin_read()? - .open_table(INSCRIPTION_ID_TO_SATPOINT)? + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? .get(&inscription_id.store())? .is_some(), ) @@ -1014,11 +1071,16 @@ impl Index { &self, outpoint: OutPoint, ) -> Result> { - let rtx = &self.database.begin_read()?; - let sat_to_id = rtx.open_multimap_table(SATPOINT_TO_INSCRIPTION_ID)?; - let inscription_id_to_entry = rtx.open_table(INSCRIPTION_ID_TO_INSCRIPTION_ENTRY)?; + let rtx = self.database.begin_read()?; + let satpoint_to_sequence_number = rtx.open_multimap_table(SATPOINT_TO_SEQUENCE_NUMBER)?; + let sequence_number_to_inscription_entry = + rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; - Self::inscriptions_on_output_ordered(&inscription_id_to_entry, &sat_to_id, outpoint) + Self::inscriptions_on_output( + &satpoint_to_sequence_number, + &sequence_number_to_inscription_entry, + outpoint, + ) } pub(crate) fn get_inscriptions_on_output( @@ -1225,9 +1287,15 @@ impl Index { let mut result = BTreeMap::new(); - let table = rtx.open_multimap_table(SATPOINT_TO_INSCRIPTION_ID)?; + let satpoint_to_sequence_number = rtx.open_multimap_table(SATPOINT_TO_SEQUENCE_NUMBER)?; + let sequence_number_to_inscription_entry = + rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; for utxo in utxos.keys() { - result.extend(Self::inscriptions_on_output_unordered(&table, *utxo)?); + result.extend(Self::inscriptions_on_output( + &satpoint_to_sequence_number, + &sequence_number_to_inscription_entry, + *utxo, + )?); } Ok(result) @@ -1236,26 +1304,29 @@ impl Index { pub(crate) fn get_latest_inscriptions_with_prev_and_next( &self, n: usize, - from: Option, - ) -> Result<(Vec, Option, Option, u64, u64)> { + from: Option, + ) -> Result<(Vec, Option, Option, u32, u32)> { let rtx = self.database.begin_read()?; - let sequence_number_to_inscription_id = rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID)?; + let sequence_number_to_inscription_entry = + rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; - let highest = match sequence_number_to_inscription_id.iter()?.next_back() { - Some(Ok((number, _id))) => number.value(), + let highest = match sequence_number_to_inscription_entry.iter()?.next_back() { + Some(Ok((number, _entry))) => number.value(), Some(Err(_)) | None => return Ok(Default::default()), }; - let lowest = match sequence_number_to_inscription_id.iter()?.next() { - Some(Ok((number, _id))) => number.value(), + let lowest = match sequence_number_to_inscription_entry.iter()?.next() { + Some(Ok((number, _entry))) => number.value(), Some(Err(_)) | None => return Ok(Default::default()), }; let from = from.unwrap_or(highest); let prev = if let Some(prev) = from.checked_sub(n.try_into()?) { - sequence_number_to_inscription_id.get(&prev)?.map(|_| prev) + sequence_number_to_inscription_entry + .get(&prev)? + .map(|_| prev) } else { None }; @@ -1271,21 +1342,22 @@ impl Index { None }; - let inscriptions = sequence_number_to_inscription_id + let inscriptions = sequence_number_to_inscription_entry .range(..=from)? .rev() .take(n) - .flat_map(|result| result.map(|(_number, id)| Entry::load(*id.value()))) + .flat_map(|result| result.map(|(_number, entry)| InscriptionEntry::load(entry.value()).id)) .collect(); Ok((inscriptions, prev, next, lowest, highest)) } - pub(crate) fn get_inscriptions_in_block(&self, block_height: u64) -> Result> { + pub(crate) fn get_inscriptions_in_block(&self, block_height: u32) -> Result> { let rtx = self.database.begin_read()?; let height_to_last_sequence_number = rtx.open_table(HEIGHT_TO_LAST_SEQUENCE_NUMBER)?; - let sequence_number_to_inscription_id = rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID)?; + let sequence_number_to_inscription_entry = + rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; let Some(newest_sequence_number) = height_to_last_sequence_number .get(&block_height)? @@ -1300,8 +1372,8 @@ impl Index { .unwrap_or(0); (oldest_sequence_number..newest_sequence_number) - .map(|num| match sequence_number_to_inscription_id.get(&num) { - Ok(Some(inscription_id)) => Ok(InscriptionId::load(*inscription_id.value())), + .map(|num| match sequence_number_to_inscription_entry.get(&num) { + Ok(Some(inscription_id)) => Ok(InscriptionEntry::load(inscription_id.value()).id), Ok(None) => Err(anyhow!( "could not find inscription for inscription number {num}" )), @@ -1312,7 +1384,7 @@ impl Index { pub(crate) fn get_highest_paying_inscriptions_in_block( &self, - block_height: u64, + block_height: u32, n: usize, ) -> Result<(Vec, usize)> { let inscription_ids = self.get_inscriptions_in_block(block_height)?; @@ -1349,21 +1421,23 @@ impl Index { .open_table(HOME_INSCRIPTIONS)? .iter()? .rev() - .flat_map(|result| result.map(|(_number, id)| InscriptionId::load(*id.value()))) + .flat_map(|result| result.map(|(_number, id)| InscriptionId::load(id.value()))) .collect(), ) } - pub(crate) fn get_feed_inscriptions(&self, n: usize) -> Result> { + pub(crate) fn get_feed_inscriptions(&self, n: usize) -> Result> { Ok( self .database .begin_read()? - .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID)? + .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)? .iter()? .rev() .take(n) - .flat_map(|result| result.map(|(number, id)| (number.value(), Entry::load(*id.value())))) + .flat_map(|result| { + result.map(|(number, entry)| (number.value(), InscriptionEntry::load(entry.value()).id)) + }) .collect(), ) } @@ -1372,14 +1446,22 @@ impl Index { &self, inscription_id: InscriptionId, ) -> Result> { - Ok( - self - .database - .begin_read()? - .open_table(INSCRIPTION_ID_TO_INSCRIPTION_ENTRY)? - .get(&inscription_id.store())? - .map(|value| InscriptionEntry::load(value.value())), - ) + let rtx = self.database.begin_read()?; + + let Some(sequence_number) = rtx + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? + .get(&inscription_id.store())? + .map(|guard| guard.value()) + else { + return Ok(None); + }; + + let entry = rtx + .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)? + .get(sequence_number)? + .map(|value| InscriptionEntry::load(value.value())); + + Ok(entry) } #[cfg(test)] @@ -1391,19 +1473,29 @@ impl Index { ) { let rtx = self.database.begin_read().unwrap(); - let satpoint_to_inscription_id = rtx.open_multimap_table(SATPOINT_TO_INSCRIPTION_ID).unwrap(); + let satpoint_to_sequence_number = rtx + .open_multimap_table(SATPOINT_TO_SEQUENCE_NUMBER) + .unwrap(); - let inscription_id_to_satpoint = rtx.open_table(INSCRIPTION_ID_TO_SATPOINT).unwrap(); + let sequence_number_to_satpoint = rtx.open_table(SEQUENCE_NUMBER_TO_SATPOINT).unwrap(); + + let sequence_number = rtx + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER) + .unwrap() + .get(&inscription_id.store()) + .unwrap() + .unwrap() + .value(); assert_eq!( - satpoint_to_inscription_id.len().unwrap(), - inscription_id_to_satpoint.len().unwrap(), + satpoint_to_sequence_number.len().unwrap(), + sequence_number_to_satpoint.len().unwrap(), ); assert_eq!( SatPoint::load( - *inscription_id_to_satpoint - .get(&inscription_id.store()) + *sequence_number_to_satpoint + .get(sequence_number) .unwrap() .unwrap() .value() @@ -1411,22 +1503,23 @@ impl Index { satpoint, ); - assert!(satpoint_to_inscription_id + assert!(satpoint_to_sequence_number .get(&satpoint.store()) .unwrap() - .any(|id| InscriptionId::load(*id.unwrap().value()) == inscription_id)); + .any(|result| result.unwrap().value() == sequence_number)); match sat { Some(sat) => { if self.index_sats { // unbound inscriptions should not be assigned to a sat assert!(satpoint.outpoint != unbound_outpoint()); + assert!(rtx - .open_multimap_table(SAT_TO_INSCRIPTION_ID) + .open_multimap_table(SAT_TO_SEQUENCE_NUMBER) .unwrap() .get(&sat) .unwrap() - .any(|id| InscriptionId::load(*id.unwrap().value()) == inscription_id)); + .any(|entry| entry.unwrap().value() == sequence_number)); // we do not track common sats (only the sat ranges) if !Sat(sat).is_common() { @@ -1453,67 +1546,11 @@ impl Index { } } - #[cfg(test)] - fn assert_non_existence_of_inscription(&self, inscription_id: InscriptionId) { - let rtx = self.database.begin_read().unwrap(); - - let inscription_id_to_satpoint = rtx.open_table(INSCRIPTION_ID_TO_SATPOINT).unwrap(); - assert!(inscription_id_to_satpoint - .get(&inscription_id.store()) - .unwrap() - .is_none()); - - let inscription_id_to_entry = rtx.open_table(INSCRIPTION_ID_TO_INSCRIPTION_ENTRY).unwrap(); - assert!(inscription_id_to_entry - .get(&inscription_id.store()) - .unwrap() - .is_none()); - - for range in rtx - .open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID) - .unwrap() - .iter() - .into_iter() - { - for entry in range.into_iter() { - let (_number, id) = entry.unwrap(); - assert!(InscriptionId::load(*id.value()) != inscription_id); - } - } - - for range in rtx - .open_multimap_table(SATPOINT_TO_INSCRIPTION_ID) - .unwrap() - .iter() - .into_iter() - { - for entry in range.into_iter() { - let (_satpoint, ids) = entry.unwrap(); - assert!(!ids - .into_iter() - .any(|id| InscriptionId::load(*id.unwrap().value()) == inscription_id)) - } - } - - for range in rtx - .open_multimap_table(SAT_TO_INSCRIPTION_ID) - .unwrap() - .iter() - .into_iter() - { - for entry in range.into_iter() { - let (_sat, ids) = entry.unwrap(); - assert!(!ids - .into_iter() - .any(|id| InscriptionId::load(*id.unwrap().value()) == inscription_id)) - } - } - } - - fn inscriptions_on_output_unordered<'a: 'tx, 'tx>( - satpoint_to_id: &'a impl ReadableMultimapTable<&'static SatPointValue, &'static InscriptionIdValue>, + fn inscriptions_on_output<'a: 'tx, 'tx>( + satpoint_to_sequence_number: &'a impl ReadableMultimapTable<&'static SatPointValue, u32>, + sequence_number_to_inscription_entry: &'a impl ReadableTable, outpoint: OutPoint, - ) -> Result + 'tx> { + ) -> Result> { let start = SatPoint { outpoint, offset: 0, @@ -1528,41 +1565,29 @@ impl Index { let mut inscriptions = Vec::new(); - for range in satpoint_to_id.range::<&[u8; 44]>(&start..=&end)? { - let (satpoint, ids) = range?; - for id_result in ids { - let id = id_result?; - inscriptions.push((Entry::load(*satpoint.value()), Entry::load(*id.value()))); + for range in satpoint_to_sequence_number.range::<&[u8; 44]>(&start..=&end)? { + let (satpoint, sequence_numbers) = range?; + for sequence_number_result in sequence_numbers { + let sequence_number = sequence_number_result?.value(); + let entry = sequence_number_to_inscription_entry + .get(sequence_number)? + .unwrap(); + inscriptions.push(( + sequence_number, + SatPoint::load(*satpoint.value()), + InscriptionEntry::load(entry.value()).id, + )); } } - Ok(inscriptions.into_iter()) - } + inscriptions.sort_by_key(|(sequence_number, _, _)| *sequence_number); - fn inscriptions_on_output_ordered<'a: 'tx, 'tx>( - inscription_id_to_entry: &'a impl ReadableTable<&'static InscriptionIdValue, InscriptionEntryValue>, - satpoint_to_id: &'a impl ReadableMultimapTable<&'static SatPointValue, &'static InscriptionIdValue>, - outpoint: OutPoint, - ) -> Result> { - let mut result = Self::inscriptions_on_output_unordered(satpoint_to_id, outpoint)? - .collect::>(); - - if result.len() <= 1 { - return Ok(result); - } - - result.sort_by_key(|(_satpoint, inscription_id)| { - match inscription_id_to_entry - .get(&inscription_id.store()) - .unwrap() - .map(|entry| InscriptionEntry::load(entry.value())) - { - Some(entry) => entry.sequence_number + 1, // remove at next index refactor - None => 0, - } - }); - - Ok(result) + Ok( + inscriptions + .into_iter() + .map(|(_sequence_number, satpoint, inscription_id)| (satpoint, inscription_id)) + .collect(), + ) } } @@ -3867,7 +3892,7 @@ mod tests { .index .assert_inscription_location(first_id, first_location, Some(50 * COIN_VALUE)); - context.index.assert_non_existence_of_inscription(second_id); + assert!(!context.index.inscription_exists(second_id).unwrap()); } } @@ -3922,7 +3947,7 @@ mod tests { context.mine_blocks(4); - context.index.assert_non_existence_of_inscription(second_id); + assert!(!context.index.inscription_exists(second_id).unwrap()); context.rpc_server.invalidate_tip(); @@ -3987,7 +4012,7 @@ mod tests { context.mine_blocks(9); - context.index.assert_non_existence_of_inscription(second_id); + assert!(!context.index.inscription_exists(second_id).unwrap()); context .index @@ -4104,13 +4129,7 @@ mod tests { let inscription_id = InscriptionId { txid, index: 0 }; assert_eq!( - context - .index - .get_inscription_entry(inscription_id) - .unwrap() - .unwrap() - .parent - .unwrap(), + context.index.get_parent_by_inscription_id(inscription_id), parent_inscription_id ); @@ -4165,13 +4184,7 @@ mod tests { let inscription_id = InscriptionId { txid, index: 0 }; assert_eq!( - context - .index - .get_inscription_entry(inscription_id) - .unwrap() - .unwrap() - .parent - .unwrap(), + context.index.get_parent_by_inscription_id(inscription_id), parent_inscription_id ); @@ -4226,13 +4239,7 @@ mod tests { let inscription_id = InscriptionId { txid, index: 0 }; assert_eq!( - context - .index - .get_inscription_entry(inscription_id) - .unwrap() - .unwrap() - .parent - .unwrap(), + context.index.get_parent_by_inscription_id(inscription_id), parent_inscription_id ); @@ -4503,11 +4510,7 @@ mod tests { assert_eq!( context .index - .get_inscription_entry(child_inscription_id) - .unwrap() - .unwrap() - .parent - .unwrap(), + .get_parent_by_inscription_id(child_inscription_id), parent_inscription_id ); diff --git a/src/index/entry.rs b/src/index/entry.rs index 59e8934b17..5d835c8be8 100644 --- a/src/index/entry.rs +++ b/src/index/entry.rs @@ -26,7 +26,7 @@ impl Entry for BlockHash { pub(crate) struct RuneEntry { pub(crate) burned: u128, pub(crate) divisibility: u8, - pub(crate) end: Option, + pub(crate) end: Option, pub(crate) etching: Txid, pub(crate) limit: Option, pub(crate) number: u64, @@ -39,13 +39,13 @@ pub(crate) struct RuneEntry { pub(super) type RuneEntryValue = ( u128, // burned u8, // divisibility - u64, // end + Option, // end (u128, u128), // etching - u128, // limit + Option, // limit u64, // number u128, // rune u128, // supply - u32, // symbol + Option, // symbol u32, // timestamp ); @@ -75,7 +75,7 @@ impl Entry for RuneEntry { Self { burned, divisibility, - end: (end != u64::max_value()).then_some(end), + end, etching: { let low = etching.0.to_le_bytes(); let high = etching.1.to_le_bytes(); @@ -86,11 +86,11 @@ impl Entry for RuneEntry { high[14], high[15], ]) }, - limit: (limit != u128::max_value()).then_some(limit), + limit, number, rune: Rune(rune), supply, - symbol: char::from_u32(symbol), + symbol: symbol.map(|symbol| char::from_u32(symbol).unwrap()), timestamp, } } @@ -99,7 +99,7 @@ impl Entry for RuneEntry { ( self.burned, self.divisibility, - self.end.unwrap_or(u64::max_value()), + self.end, { let bytes = self.etching.to_byte_array(); ( @@ -113,11 +113,11 @@ impl Entry for RuneEntry { ]), ) }, - self.limit.unwrap_or(u128::max_value()), + self.limit, self.number, self.rune.0, self.supply, - self.symbol.map(u32::from).unwrap_or(u32::max_value()), + self.symbol.map(u32::from), self.timestamp, ) } @@ -141,42 +141,52 @@ impl Entry for RuneId { pub(crate) struct InscriptionEntry { pub(crate) charms: u16, pub(crate) fee: u64, - pub(crate) height: u64, - pub(crate) inscription_number: i64, - pub(crate) parent: Option, + pub(crate) height: u32, + pub(crate) id: InscriptionId, + pub(crate) inscription_number: i32, + pub(crate) parent: Option, pub(crate) sat: Option, - pub(crate) sequence_number: u64, + pub(crate) sequence_number: u32, pub(crate) timestamp: u32, } pub(crate) type InscriptionEntryValue = ( - u16, // charms - u64, // fee - u64, // height - i64, // inscription number - ParentValue, // parent - u64, // sat - u64, // sequence number - u32, // timestamp + u16, // charms + u64, // fee + u32, // height + InscriptionIdValue, // inscription id + i32, // inscription number + Option, // parent + Option, // sat + u32, // sequence number + u32, // timestamp ); impl Entry for InscriptionEntry { type Value = InscriptionEntryValue; + #[rustfmt::skip] fn load( - (charms, fee, height, inscription_number, parent, sat, sequence_number, timestamp): InscriptionEntryValue, + ( + charms, + fee, + height, + id, + inscription_number, + parent, + sat, + sequence_number, + timestamp, + ): InscriptionEntryValue, ) -> Self { Self { charms, fee, height, + id: InscriptionId::load(id), inscription_number, - parent: ParentEntry::load(parent), - sat: if sat == u64::MAX { - None - } else { - Some(Sat(sat)) - }, + parent, + sat: sat.map(Sat), sequence_number, timestamp, } @@ -187,106 +197,71 @@ impl Entry for InscriptionEntry { self.charms, self.fee, self.height, + self.id.store(), self.inscription_number, - self.parent.store(), - match self.sat { - Some(sat) => sat.n(), - None => u64::MAX, - }, + self.parent, + self.sat.map(Sat::n), self.sequence_number, self.timestamp, ) } } -pub(super) type InscriptionIdValue = [u8; 36]; +pub(crate) type InscriptionIdValue = (u128, u128, u32); impl Entry for InscriptionId { type Value = InscriptionIdValue; fn load(value: Self::Value) -> Self { - let (txid, index) = value.split_at(32); - Self { - txid: Txid::from_raw_hash(Hash::from_slice(txid).unwrap()), - index: u32::from_be_bytes(index.try_into().unwrap()), - } - } - - fn store(self) -> Self::Value { - let mut value = [0; 36]; - let (txid, index) = value.split_at_mut(32); - txid.copy_from_slice(self.txid.as_ref()); - index.copy_from_slice(&self.index.to_be_bytes()); - value - } -} - -type ParentValue = (u128, u128, u32); -type ParentEntry = Option; + let (head, tail, index) = value; + let head_array = head.to_le_bytes(); + let tail_array = tail.to_le_bytes(); + let array = [ + head_array[0], + head_array[1], + head_array[2], + head_array[3], + head_array[4], + head_array[5], + head_array[6], + head_array[7], + head_array[8], + head_array[9], + head_array[10], + head_array[11], + head_array[12], + head_array[13], + head_array[14], + head_array[15], + tail_array[0], + tail_array[1], + tail_array[2], + tail_array[3], + tail_array[4], + tail_array[5], + tail_array[6], + tail_array[7], + tail_array[8], + tail_array[9], + tail_array[10], + tail_array[11], + tail_array[12], + tail_array[13], + tail_array[14], + tail_array[15], + ]; -impl Entry for ParentEntry { - type Value = ParentValue; - - fn load(value: Self::Value) -> Self { - if (0, 0, 0) == value { - None - } else { - let (head, tail, index) = value; - let head_array = head.to_le_bytes(); - let tail_array = tail.to_le_bytes(); - let index_array = index.to_be_bytes(); - let array = [ - head_array[0], - head_array[1], - head_array[2], - head_array[3], - head_array[4], - head_array[5], - head_array[6], - head_array[7], - head_array[8], - head_array[9], - head_array[10], - head_array[11], - head_array[12], - head_array[13], - head_array[14], - head_array[15], - tail_array[0], - tail_array[1], - tail_array[2], - tail_array[3], - tail_array[4], - tail_array[5], - tail_array[6], - tail_array[7], - tail_array[8], - tail_array[9], - tail_array[10], - tail_array[11], - tail_array[12], - tail_array[13], - tail_array[14], - tail_array[15], - index_array[0], - index_array[1], - index_array[2], - index_array[3], - ]; - - Some(InscriptionId::load(array)) + Self { + txid: Txid::from_byte_array(array), + index, } } fn store(self) -> Self::Value { - if let Some(inscription_id) = self { - let txid_entry = inscription_id.txid.store(); - let little_end = u128::from_le_bytes(txid_entry[..16].try_into().unwrap()); - let big_end = u128::from_le_bytes(txid_entry[16..].try_into().unwrap()); - (little_end, big_end, inscription_id.index) - } else { - (0, 0, 0) - } + let txid_entry = self.txid.store(); + let little_end = u128::from_le_bytes(txid_entry[..16].try_into().unwrap()); + let big_end = u128::from_le_bytes(txid_entry[16..].try_into().unwrap()); + (little_end, big_end, self.index) } } @@ -368,47 +343,10 @@ mod tests { use super::*; #[test] - fn parent_entry() { - let inscription_id: Option = None; - - assert_eq!(inscription_id.store(), (0, 0, 0)); - assert_eq!( - as Entry>::load((0, 0, 0)), - inscription_id - ); - - let inscription_id = Some( - "0000000000000000000000000000000000000000000000000000000000000000i1" - .parse::() - .unwrap(), - ); - - assert_eq!(inscription_id.store(), (0, 0, 1)); - assert_eq!( - as Entry>::load((0, 0, 1)), - inscription_id - ); - - let inscription_id = Some( - "ffffffffffffffffffffffffffffffff00000000000000000000000000000000i0" - .parse::() - .unwrap(), - ); - - assert_eq!(inscription_id.store(), (0, u128::MAX, 0)); - assert_eq!( - as Entry>::load((0, u128::MAX, 0)), - inscription_id - ); - } - - #[test] - fn parent_entry_individual_byte_order() { - let inscription_id = Some( - "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefi0" - .parse::() - .unwrap(), - ); + fn inscription_id_entry() { + let inscription_id = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefi0" + .parse::() + .unwrap(); assert_eq!( inscription_id.store(), @@ -420,7 +358,7 @@ mod tests { ); assert_eq!( - as Entry>::load(( + InscriptionId::load(( 0x0123456789abcdef0123456789abcdef, 0x0123456789abcdef0123456789abcdef, 0 @@ -431,23 +369,26 @@ mod tests { #[test] fn parent_entry_index() { - let inscription_id = Some( - "0000000000000000000000000000000000000000000000000000000000000000i1" - .parse::() - .unwrap(), - ); + let inscription_id = "0000000000000000000000000000000000000000000000000000000000000000i1" + .parse::() + .unwrap(); assert_eq!(inscription_id.store(), (0, 0, 1)); - assert_eq!( - as Entry>::load((0, 0, 1)), - inscription_id - ); + assert_eq!(InscriptionId::load((0, 0, 1)), inscription_id); + + let inscription_id = "0000000000000000000000000000000000000000000000000000000000000000i256" + .parse::() + .unwrap(); + + assert_eq!(inscription_id.store(), (0, 0, 256)); + + assert_eq!(InscriptionId::load((0, 0, 256)), inscription_id); } #[test] fn rune_entry() { - let rune_entry = RuneEntry { + let entry = RuneEntry { burned: 1, divisibility: 2, end: Some(3), @@ -464,88 +405,24 @@ mod tests { timestamp: 6, }; - assert_eq!( - rune_entry.store(), + let value = ( + 1, + 2, + Some(3), ( - 1, - 2, - 3, - ( - 0x0F0E0D0C0B0A09080706050403020100, - 0x1F1E1D1C1B1A19181716151413121110 - ), - 4, - 5, - 6, - 7, - u32::from('a'), - 6, - ) + 0x0F0E0D0C0B0A09080706050403020100, + 0x1F1E1D1C1B1A19181716151413121110, + ), + Some(4), + 5, + 6, + 7, + Some(u32::from('a')), + 6, ); - assert_eq!( - RuneEntry::load(( - 1, - 2, - 3, - ( - 0x0F0E0D0C0B0A09080706050403020100, - 0x1F1E1D1C1B1A19181716151413121110 - ), - 4, - 5, - 6, - 7, - u32::from('a'), - 6, - )), - rune_entry - ); - - let rune_entry = RuneEntry { - symbol: None, - limit: None, - end: None, - ..rune_entry - }; - - assert_eq!( - rune_entry.store(), - ( - 1, - 2, - u64::max_value(), - ( - 0x0F0E0D0C0B0A09080706050403020100, - 0x1F1E1D1C1B1A19181716151413121110 - ), - u128::max_value(), - 5, - 6, - 7, - u32::max_value(), - 6, - ) - ); - - assert_eq!( - RuneEntry::load(( - 1, - 2, - u64::max_value(), - ( - 0x0F0E0D0C0B0A09080706050403020100, - 0x1F1E1D1C1B1A19181716151413121110 - ), - u128::max_value(), - 5, - 6, - 7, - u32::max_value(), - 6, - )), - rune_entry - ); + assert_eq!(entry.store(), value); + assert_eq!(RuneEntry::load(value), entry); } #[test] diff --git a/src/index/reorg.rs b/src/index/reorg.rs index 3102cdc7d7..d81f7a2577 100644 --- a/src/index/reorg.rs +++ b/src/index/reorg.rs @@ -2,7 +2,7 @@ use {super::*, updater::BlockData}; #[derive(Debug, PartialEq)] pub(crate) enum ReorgError { - Recoverable { height: u64, depth: u64 }, + Recoverable { height: u32, depth: u32 }, Unrecoverable, } @@ -19,27 +19,27 @@ impl fmt::Display for ReorgError { impl std::error::Error for ReorgError {} -const MAX_SAVEPOINTS: usize = 2; -const SAVEPOINT_INTERVAL: u64 = 10; -const CHAIN_TIP_DISTANCE: u64 = 21; +const MAX_SAVEPOINTS: u32 = 2; +const SAVEPOINT_INTERVAL: u32 = 10; +const CHAIN_TIP_DISTANCE: u32 = 21; pub(crate) struct Reorg {} impl Reorg { - pub(crate) fn detect_reorg(block: &BlockData, height: u64, index: &Index) -> Result { + pub(crate) fn detect_reorg(block: &BlockData, height: u32, index: &Index) -> Result { let bitcoind_prev_blockhash = block.header.prev_blockhash; match index.block_hash(height.checked_sub(1))? { Some(index_prev_blockhash) if index_prev_blockhash == bitcoind_prev_blockhash => Ok(()), Some(index_prev_blockhash) if index_prev_blockhash != bitcoind_prev_blockhash => { let max_recoverable_reorg_depth = - (MAX_SAVEPOINTS as u64 - 1) * SAVEPOINT_INTERVAL + height % SAVEPOINT_INTERVAL; + (MAX_SAVEPOINTS - 1) * SAVEPOINT_INTERVAL + height % SAVEPOINT_INTERVAL; for depth in 1..max_recoverable_reorg_depth { let index_block_hash = index.block_hash(height.checked_sub(depth))?; let bitcoind_block_hash = index .client - .get_block_hash(height.saturating_sub(depth)) + .get_block_hash(u64::from(height.saturating_sub(depth))) .into_option()?; if index_block_hash == bitcoind_block_hash { @@ -53,7 +53,7 @@ impl Reorg { } } - pub(crate) fn handle_reorg(index: &Index, height: u64, depth: u64) -> Result { + pub(crate) fn handle_reorg(index: &Index, height: u32, depth: u32) -> Result { log::info!("rolling back database after reorg of depth {depth} at height {height}"); if let redb::Durability::None = index.durability { @@ -78,25 +78,28 @@ impl Reorg { Ok(()) } - pub(crate) fn update_savepoints(index: &Index, height: u64) -> Result { + pub(crate) fn update_savepoints(index: &Index, height: u32) -> Result { if let redb::Durability::None = index.durability { return Ok(()); } if (height < SAVEPOINT_INTERVAL || height % SAVEPOINT_INTERVAL == 0) - && index - .options - .bitcoin_rpc_client()? - .get_blockchain_info()? - .headers - .saturating_sub(height) + && u32::try_from( + index + .options + .bitcoin_rpc_client()? + .get_blockchain_info()? + .headers, + ) + .unwrap() + .saturating_sub(height) <= CHAIN_TIP_DISTANCE { let wtx = index.begin_write()?; let savepoints = wtx.list_persistent_savepoints()?.collect::>(); - if savepoints.len() >= MAX_SAVEPOINTS { + if savepoints.len() >= usize::try_from(MAX_SAVEPOINTS).unwrap() { wtx.delete_persistent_savepoint(savepoints.into_iter().min().unwrap())?; } diff --git a/src/index/rtx.rs b/src/index/rtx.rs index 4f6b03c694..810e900fff 100644 --- a/src/index/rtx.rs +++ b/src/index/rtx.rs @@ -15,7 +15,7 @@ impl Rtx<'_> { ) } - pub(crate) fn block_count(&self) -> Result { + pub(crate) fn block_count(&self) -> Result { Ok( self .0 @@ -28,7 +28,7 @@ impl Rtx<'_> { ) } - pub(crate) fn block_hash(&self, height: Option) -> Result> { + pub(crate) fn block_hash(&self, height: Option) -> Result> { match height { Some(height) => Ok( self diff --git a/src/index/updater.rs b/src/index/updater.rs index d7a6695e37..515869255a 100644 --- a/src/index/updater.rs +++ b/src/index/updater.rs @@ -32,7 +32,7 @@ impl From for BlockData { pub(crate) struct Updater<'index> { range_cache: HashMap>, - height: u64, + height: u32, index: &'index Index, sat_ranges_since_flush: u64, outputs_cached: u64, @@ -55,7 +55,7 @@ impl<'index> Updater<'_> { pub(crate) fn update_index(&mut self) -> Result { let mut wtx = self.index.begin_write()?; - let starting_height = self.index.client.get_block_count()? + 1; + let starting_height = u32::try_from(self.index.client.get_block_count()?).unwrap() + 1; wtx .open_table(WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP)? @@ -74,8 +74,8 @@ impl<'index> Updater<'_> { { None } else { - let progress_bar = ProgressBar::new(starting_height); - progress_bar.set_position(self.height); + let progress_bar = ProgressBar::new(starting_height.into()); + progress_bar.set_position(self.height.into()); progress_bar.set_style( ProgressStyle::with_template("[indexing blocks] {wide_bar} {pos}/{len}").unwrap(), ); @@ -158,7 +158,7 @@ impl<'index> Updater<'_> { fn fetch_blocks_from( index: &Index, - mut height: u64, + mut height: u32, index_sats: bool, ) -> Result> { let (tx, rx) = mpsc::sync_channel(32); @@ -197,14 +197,14 @@ impl<'index> Updater<'_> { fn get_block_with_retries( client: &Client, - height: u64, + height: u32, index_sats: bool, - first_inscription_height: u64, + first_inscription_height: u32, ) -> Result> { let mut errors = 0; loop { match client - .get_block_hash(height) + .get_block_hash(height.into()) .into_option() .and_then(|option| { option @@ -379,16 +379,16 @@ impl<'index> Updater<'_> { let mut height_to_block_hash = wtx.open_table(HEIGHT_TO_BLOCK_HASH)?; let mut height_to_last_sequence_number = wtx.open_table(HEIGHT_TO_LAST_SEQUENCE_NUMBER)?; let mut home_inscriptions = wtx.open_table(HOME_INSCRIPTIONS)?; - let mut inscription_id_to_children = wtx.open_multimap_table(INSCRIPTION_ID_TO_CHILDREN)?; - let mut inscription_id_to_inscription_entry = - wtx.open_table(INSCRIPTION_ID_TO_INSCRIPTION_ENTRY)?; - let mut inscription_id_to_satpoint = wtx.open_table(INSCRIPTION_ID_TO_SATPOINT)?; - let mut inscription_number_to_inscription_id = - wtx.open_table(INSCRIPTION_NUMBER_TO_INSCRIPTION_ID)?; - let mut sat_to_inscription_id = wtx.open_multimap_table(SAT_TO_INSCRIPTION_ID)?; - let mut satpoint_to_inscription_id = wtx.open_multimap_table(SATPOINT_TO_INSCRIPTION_ID)?; - let mut sequence_number_to_inscription_id = - wtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ID)?; + let mut inscription_id_to_sequence_number = + wtx.open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)?; + let mut inscription_number_to_sequence_number = + wtx.open_table(INSCRIPTION_NUMBER_TO_SEQUENCE_NUMBER)?; + let mut sat_to_sequence_number = wtx.open_multimap_table(SAT_TO_SEQUENCE_NUMBER)?; + let mut satpoint_to_sequence_number = wtx.open_multimap_table(SATPOINT_TO_SEQUENCE_NUMBER)?; + let mut sequence_number_to_children = wtx.open_multimap_table(SEQUENCE_NUMBER_TO_CHILDREN)?; + let mut sequence_number_to_inscription_entry = + wtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; + let mut sequence_number_to_satpoint = wtx.open_table(SEQUENCE_NUMBER_TO_SATPOINT)?; let mut statistic_to_count = wtx.open_table(STATISTIC_TO_COUNT)?; let mut lost_sats = statistic_to_count @@ -411,7 +411,7 @@ impl<'index> Updater<'_> { .map(|unbound_inscriptions| unbound_inscriptions.value()) .unwrap_or(0); - let next_sequence_number = sequence_number_to_inscription_id + let next_sequence_number = sequence_number_to_inscription_entry .iter()? .next_back() .and_then(|result| result.ok()) @@ -427,17 +427,17 @@ impl<'index> Updater<'_> { height: self.height, home_inscription_count, home_inscriptions: &mut home_inscriptions, - id_to_children: &mut inscription_id_to_children, - id_to_entry: &mut inscription_id_to_inscription_entry, - id_to_satpoint: &mut inscription_id_to_satpoint, - inscription_number_to_id: &mut inscription_number_to_inscription_id, + id_to_sequence_number: &mut inscription_id_to_sequence_number, + inscription_number_to_sequence_number: &mut inscription_number_to_sequence_number, lost_sats, next_sequence_number, outpoint_to_value: &mut outpoint_to_value, reward: Height(self.height).subsidy(), - sat_to_inscription_id: &mut sat_to_inscription_id, - satpoint_to_id: &mut satpoint_to_inscription_id, - sequence_number_to_id: &mut sequence_number_to_inscription_id, + sat_to_sequence_number: &mut sat_to_sequence_number, + satpoint_to_sequence_number: &mut satpoint_to_sequence_number, + sequence_number_to_children: &mut sequence_number_to_children, + sequence_number_to_entry: &mut sequence_number_to_inscription_entry, + sequence_number_to_satpoint: &mut sequence_number_to_satpoint, timestamp: block.header.time, unbound_inscriptions, value_cache, @@ -573,19 +573,28 @@ impl<'index> Updater<'_> { let mut outpoint_to_rune_balances = wtx.open_table(OUTPOINT_TO_RUNE_BALANCES)?; let mut rune_id_to_rune_entry = wtx.open_table(RUNE_ID_TO_RUNE_ENTRY)?; let mut rune_to_rune_id = wtx.open_table(RUNE_TO_RUNE_ID)?; - let mut inscription_id_to_rune = wtx.open_table(INSCRIPTION_ID_TO_RUNE)?; + let mut sequence_number_to_rune = wtx.open_table(SEQUENCE_NUMBER_TO_RUNE)?; let mut transaction_id_to_rune = wtx.open_table(TRANSACTION_ID_TO_RUNE)?; - let mut rune_updater = RuneUpdater::new( - self.height, - &mut rune_id_to_rune_entry, - &inscription_id_to_inscription_entry, - &mut inscription_id_to_rune, - &mut outpoint_to_rune_balances, - &mut rune_to_rune_id, - &mut statistic_to_count, - block.header.time, - &mut transaction_id_to_rune, - )?; + + let runes = statistic_to_count + .get(&Statistic::Runes.into())? + .map(|x| x.value()) + .unwrap_or(0); + + let mut rune_updater = RuneUpdater { + height: self.height, + id_to_entry: &mut rune_id_to_rune_entry, + inscription_id_to_sequence_number: &mut inscription_id_to_sequence_number, + minimum: Rune::minimum_at_height(Height(self.height)), + outpoint_to_balances: &mut outpoint_to_rune_balances, + rune_to_id: &mut rune_to_rune_id, + runes, + sequence_number_to_rune: &mut sequence_number_to_rune, + statistic_to_count: &mut statistic_to_count, + timestamp: block.header.time, + transaction_id_to_rune: &mut transaction_id_to_rune, + }; + for (i, (tx, txid)) in block.txdata.iter().enumerate() { rune_updater.index_runes(i, tx, *txid)?; } diff --git a/src/index/updater/inscription_updater.rs b/src/index/updater/inscription_updater.rs index 15a6afef3a..a224da67cb 100644 --- a/src/index/updater/inscription_updater.rs +++ b/src/index/updater/inscription_updater.rs @@ -36,32 +36,28 @@ enum Origin { } pub(super) struct InscriptionUpdater<'a, 'db, 'tx> { + pub(super) blessed_inscription_count: u64, + pub(super) cursed_inscription_count: u64, pub(super) flotsam: Vec, - pub(super) height: u64, + pub(super) height: u32, pub(super) home_inscription_count: u64, - pub(super) home_inscriptions: &'a mut Table<'db, 'tx, u64, &'static InscriptionIdValue>, - pub(super) id_to_children: - &'a mut MultimapTable<'db, 'tx, &'static InscriptionIdValue, &'static InscriptionIdValue>, - pub(super) id_to_satpoint: - &'a mut Table<'db, 'tx, &'static InscriptionIdValue, &'static SatPointValue>, - pub(super) value_receiver: &'a mut Receiver, - pub(super) id_to_entry: - &'a mut Table<'db, 'tx, &'static InscriptionIdValue, InscriptionEntryValue>, + pub(super) home_inscriptions: &'a mut Table<'db, 'tx, u32, InscriptionIdValue>, + pub(super) id_to_sequence_number: &'a mut Table<'db, 'tx, InscriptionIdValue, u32>, + pub(super) inscription_number_to_sequence_number: &'a mut Table<'db, 'tx, i32, u32>, pub(super) lost_sats: u64, - pub(super) cursed_inscription_count: u64, - pub(super) blessed_inscription_count: u64, - pub(super) next_sequence_number: u64, - pub(super) inscription_number_to_id: &'a mut Table<'db, 'tx, i64, &'static InscriptionIdValue>, - pub(super) sequence_number_to_id: &'a mut Table<'db, 'tx, u64, &'static InscriptionIdValue>, + pub(super) next_sequence_number: u32, pub(super) outpoint_to_value: &'a mut Table<'db, 'tx, &'static OutPointValue, u64>, pub(super) reward: u64, - pub(super) sat_to_inscription_id: - &'a mut MultimapTable<'db, 'tx, u64, &'static InscriptionIdValue>, - pub(super) satpoint_to_id: - &'a mut MultimapTable<'db, 'tx, &'static SatPointValue, &'static InscriptionIdValue>, + pub(super) sat_to_sequence_number: &'a mut MultimapTable<'db, 'tx, u64, u32>, + pub(super) satpoint_to_sequence_number: + &'a mut MultimapTable<'db, 'tx, &'static SatPointValue, u32>, + pub(super) sequence_number_to_children: &'a mut MultimapTable<'db, 'tx, u32, u32>, + pub(super) sequence_number_to_entry: &'a mut Table<'db, 'tx, u32, InscriptionEntryValue>, + pub(super) sequence_number_to_satpoint: &'a mut Table<'db, 'tx, u32, &'static SatPointValue>, pub(super) timestamp: u32, pub(super) unbound_inscriptions: u64, pub(super) value_cache: &'a mut HashMap, + pub(super) value_receiver: &'a mut Receiver, } impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { @@ -85,9 +81,9 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { } // find existing inscriptions on input (transfers of inscriptions) - for (old_satpoint, inscription_id) in Index::inscriptions_on_output_ordered( - self.id_to_entry, - self.satpoint_to_id, + for (old_satpoint, inscription_id) in Index::inscriptions_on_output( + self.satpoint_to_sequence_number, + self.sequence_number_to_entry, tx_in.previous_output, )? { let offset = total_input_value + old_satpoint.offset; @@ -99,8 +95,8 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { inscribed_offsets .entry(offset) - .and_modify(|(_id, count)| *count += 1) - .or_insert((inscription_id, 0)); + .or_insert((inscription_id, 0)) + .1 += 1; } let offset = total_input_value; @@ -136,7 +132,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { index: id_counter, }; - let reinscription = inscribed_offsets.contains_key(&offset); + let inscribed_offset = inscribed_offsets.get(&offset); let curse = if inscription.payload.unrecognized_even_field { Some(Curse::UnrecognizedEvenField) @@ -152,44 +148,41 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { Some(Curse::Pointer) } else if inscription.pushnum { Some(Curse::Pushnum) - } else if reinscription { - Some(Curse::Reinscription) + } else if let Some((id, count)) = inscribed_offset { + if *count > 1 { + Some(Curse::Reinscription) + } else { + let initial_inscription_sequence_number = + self.id_to_sequence_number.get(id.store())?.unwrap().value(); + + let initial_inscription_is_cursed = InscriptionEntry::load( + self + .sequence_number_to_entry + .get(initial_inscription_sequence_number)? + .unwrap() + .value(), + ) + .inscription_number + < 0; + + if initial_inscription_is_cursed { + None + } else { + Some(Curse::Reinscription) + } + } } else { None }; - let cursed = if let Some(Curse::Reinscription) = curse { - let first_reinscription = inscribed_offsets - .get(&offset) - .map(|(_id, count)| count == &0) - .unwrap_or(false); - - let initial_inscription_is_cursed = inscribed_offsets - .get(&offset) - .and_then(|(inscription_id, _count)| { - match self.id_to_entry.get(&inscription_id.store()) { - Ok(option) => option.map(|entry| { - let loaded_entry = InscriptionEntry::load(entry.value()); - loaded_entry.inscription_number < 0 - }), - Err(_) => None, - } - }) - .unwrap_or(false); - - !(initial_inscription_is_cursed && first_reinscription) - } else { - curse.is_some() - }; - let unbound = current_input_value == 0 || curse == Some(Curse::UnrecognizedEvenField); floating_inscriptions.push(Flotsam { inscription_id, offset, origin: Origin::New { - reinscription, - cursed, + reinscription: inscribed_offset.is_some(), + cursed: curse.is_some(), fee: 0, hidden: inscription.payload.hidden(), parent: inscription.payload.parent(), @@ -353,12 +346,21 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { flotsam: Flotsam, new_satpoint: SatPoint, ) -> Result { - let inscription_id = flotsam.inscription_id.store(); - let unbound = match flotsam.origin { + let inscription_id = flotsam.inscription_id; + let (unbound, sequence_number) = match flotsam.origin { Origin::Old { old_satpoint } => { - self.satpoint_to_id.remove_all(&old_satpoint.store())?; + self + .satpoint_to_sequence_number + .remove_all(&old_satpoint.store())?; - false + ( + false, + self + .id_to_sequence_number + .get(&inscription_id.store())? + .unwrap() + .value(), + ) } Origin::New { cursed, @@ -370,28 +372,24 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { unbound, } => { let inscription_number = if cursed { - let number: i64 = self.cursed_inscription_count.try_into().unwrap(); + let number: i32 = self.cursed_inscription_count.try_into().unwrap(); self.cursed_inscription_count += 1; // because cursed numbers start at -1 -(number + 1) } else { - let number: i64 = self.blessed_inscription_count.try_into().unwrap(); + let number: i32 = self.blessed_inscription_count.try_into().unwrap(); self.blessed_inscription_count += 1; number }; - self - .inscription_number_to_id - .insert(inscription_number, &inscription_id)?; - let sequence_number = self.next_sequence_number; self.next_sequence_number += 1; self - .sequence_number_to_id - .insert(sequence_number, &inscription_id)?; + .inscription_number_to_sequence_number + .insert(inscription_number, sequence_number)?; let sat = if unbound { None @@ -432,15 +430,32 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { } if let Some(Sat(n)) = sat { - self.sat_to_inscription_id.insert(&n, &inscription_id)?; + self.sat_to_sequence_number.insert(&n, &sequence_number)?; } - self.id_to_entry.insert( - &inscription_id, + let parent = match parent { + Some(parent_id) => { + let parent_sequence_number = self + .id_to_sequence_number + .get(&parent_id.store())? + .unwrap() + .value(); + self + .sequence_number_to_children + .insert(parent_sequence_number, sequence_number)?; + + Some(parent_sequence_number) + } + None => None, + }; + + self.sequence_number_to_entry.insert( + sequence_number, &InscriptionEntry { charms, fee, height: self.height, + id: inscription_id, inscription_number, parent, sat, @@ -450,16 +465,14 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { .store(), )?; - if let Some(parent) = parent { - self - .id_to_children - .insert(&parent.store(), &inscription_id)?; - } + self + .id_to_sequence_number + .insert(&inscription_id.store(), sequence_number)?; if !hidden { self .home_inscriptions - .insert(&sequence_number, &inscription_id)?; + .insert(&sequence_number, inscription_id.store())?; if self.home_inscription_count == 100 { self.home_inscriptions.pop_first()?; @@ -468,7 +481,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { } } - unbound + (unbound, sequence_number) } }; @@ -483,8 +496,12 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> { new_satpoint.store() }; - self.satpoint_to_id.insert(&satpoint, &inscription_id)?; - self.id_to_satpoint.insert(&inscription_id, &satpoint)?; + self + .satpoint_to_sequence_number + .insert(&satpoint, sequence_number)?; + self + .sequence_number_to_satpoint + .insert(sequence_number, &satpoint)?; Ok(()) } diff --git a/src/index/updater/rune_updater.rs b/src/index/updater/rune_updater.rs index 74568b4b9a..3c7f1b6ef0 100644 --- a/src/index/updater/rune_updater.rs +++ b/src/index/updater/rune_updater.rs @@ -10,7 +10,7 @@ fn claim(id: u128) -> Option { struct Allocation { balance: u128, divisibility: u8, - end: Option, + end: Option, id: u128, limit: Option, rune: Rune, @@ -18,56 +18,20 @@ struct Allocation { } pub(super) struct RuneUpdater<'a, 'db, 'tx> { - height: u64, - id_to_entry: &'a mut Table<'db, 'tx, RuneIdValue, RuneEntryValue>, - inscription_id_to_inscription_entry: - &'a Table<'db, 'tx, &'static InscriptionIdValue, InscriptionEntryValue>, - inscription_id_to_rune: &'a mut Table<'db, 'tx, &'static InscriptionIdValue, u128>, - minimum: Rune, - outpoint_to_balances: &'a mut Table<'db, 'tx, &'static OutPointValue, &'static [u8]>, - rune_to_id: &'a mut Table<'db, 'tx, u128, RuneIdValue>, - runes: u64, - statistic_to_count: &'a mut Table<'db, 'tx, u64, u64>, - timestamp: u32, - transaction_id_to_rune: &'a mut Table<'db, 'tx, &'static TxidValue, u128>, + pub(super) height: u32, + pub(super) id_to_entry: &'a mut Table<'db, 'tx, RuneIdValue, RuneEntryValue>, + pub(super) inscription_id_to_sequence_number: &'a Table<'db, 'tx, InscriptionIdValue, u32>, + pub(super) minimum: Rune, + pub(super) outpoint_to_balances: &'a mut Table<'db, 'tx, &'static OutPointValue, &'static [u8]>, + pub(super) rune_to_id: &'a mut Table<'db, 'tx, u128, RuneIdValue>, + pub(super) runes: u64, + pub(super) sequence_number_to_rune: &'a mut Table<'db, 'tx, u32, u128>, + pub(super) statistic_to_count: &'a mut Table<'db, 'tx, u64, u64>, + pub(super) timestamp: u32, + pub(super) transaction_id_to_rune: &'a mut Table<'db, 'tx, &'static TxidValue, u128>, } impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> { - pub(super) fn new( - height: u64, - id_to_entry: &'a mut Table<'db, 'tx, RuneIdValue, RuneEntryValue>, - inscription_id_to_inscription_entry: &'a Table< - 'db, - 'tx, - &'static InscriptionIdValue, - InscriptionEntryValue, - >, - inscription_id_to_rune: &'a mut Table<'db, 'tx, &'static InscriptionIdValue, u128>, - outpoint_to_balances: &'a mut Table<'db, 'tx, &'static OutPointValue, &'static [u8]>, - rune_to_id: &'a mut Table<'db, 'tx, u128, RuneIdValue>, - statistic_to_count: &'a mut Table<'db, 'tx, u64, u64>, - timestamp: u32, - transaction_id_to_rune: &'a mut Table<'db, 'tx, &'static TxidValue, u128>, - ) -> Result { - let runes = statistic_to_count - .get(&Statistic::Runes.into())? - .map(|x| x.value()) - .unwrap_or(0); - Ok(Self { - height, - id_to_entry, - inscription_id_to_inscription_entry, - inscription_id_to_rune, - minimum: Rune::minimum_at_height(Height(height)), - outpoint_to_balances, - rune_to_id, - runes, - statistic_to_count, - timestamp, - transaction_id_to_rune, - }) - } - pub(super) fn index_runes(&mut self, index: usize, tx: &Transaction, txid: Txid) -> Result<()> { let runestone = Runestone::from_transaction(tx); @@ -303,14 +267,13 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> { let inscription_id = InscriptionId { txid, index: 0 }; - if self - .inscription_id_to_inscription_entry + if let Some(sequence_number) = self + .inscription_id_to_sequence_number .get(&inscription_id.store())? - .is_some() { self - .inscription_id_to_rune - .insert(&inscription_id.store(), rune.0)?; + .sequence_number_to_rune + .insert(sequence_number.value(), rune.0)?; } } } diff --git a/src/lib.rs b/src/lib.rs index a760a92038..2a970f5b1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,10 +139,9 @@ mod wallet; type Result = std::result::Result; -const DIFFCHANGE_INTERVAL: u64 = bitcoin::blockdata::constants::DIFFCHANGE_INTERVAL as u64; -const SUBSIDY_HALVING_INTERVAL: u64 = - bitcoin::blockdata::constants::SUBSIDY_HALVING_INTERVAL as u64; -const CYCLE_EPOCHS: u64 = 6; +const DIFFCHANGE_INTERVAL: u32 = bitcoin::blockdata::constants::DIFFCHANGE_INTERVAL; +const SUBSIDY_HALVING_INTERVAL: u32 = bitcoin::blockdata::constants::SUBSIDY_HALVING_INTERVAL; +const CYCLE_EPOCHS: u32 = 6; static SHUTTING_DOWN: AtomicBool = AtomicBool::new(false); static LISTENERS: Mutex> = Mutex::new(Vec::new()); diff --git a/src/options.rs b/src/options.rs index 0b5d486457..a10ad40739 100644 --- a/src/options.rs +++ b/src/options.rs @@ -37,9 +37,9 @@ pub(crate) struct Options { long, help = "Don't look for inscriptions below ." )] - pub(crate) first_inscription_height: Option, + pub(crate) first_inscription_height: Option, #[arg(long, help = "Limit index to blocks.")] - pub(crate) height_limit: Option, + pub(crate) height_limit: Option, #[arg(long, help = "Use index at .")] pub(crate) index: Option, #[arg( @@ -74,7 +74,7 @@ impl Options { } } - pub(crate) fn first_inscription_height(&self) -> u64 { + pub(crate) fn first_inscription_height(&self) -> u32 { if self.chain() == Chain::Regtest { self.first_inscription_height.unwrap_or(0) } else if integration_test() { diff --git a/src/rarity.rs b/src/rarity.rs index 9ff71e8066..65f1eb788f 100644 --- a/src/rarity.rs +++ b/src/rarity.rs @@ -122,28 +122,28 @@ mod tests { assert_eq!(Sat(50 * COIN_VALUE + 1).rarity(), Rarity::Common); assert_eq!( - Sat(50 * COIN_VALUE * DIFFCHANGE_INTERVAL - 1).rarity(), + Sat(50 * COIN_VALUE * u64::from(DIFFCHANGE_INTERVAL) - 1).rarity(), Rarity::Common ); assert_eq!( - Sat(50 * COIN_VALUE * DIFFCHANGE_INTERVAL).rarity(), + Sat(50 * COIN_VALUE * u64::from(DIFFCHANGE_INTERVAL)).rarity(), Rarity::Rare ); assert_eq!( - Sat(50 * COIN_VALUE * DIFFCHANGE_INTERVAL + 1).rarity(), + Sat(50 * COIN_VALUE * u64::from(DIFFCHANGE_INTERVAL) + 1).rarity(), Rarity::Common ); assert_eq!( - Sat(50 * COIN_VALUE * SUBSIDY_HALVING_INTERVAL - 1).rarity(), + Sat(50 * COIN_VALUE * u64::from(SUBSIDY_HALVING_INTERVAL) - 1).rarity(), Rarity::Common ); assert_eq!( - Sat(50 * COIN_VALUE * SUBSIDY_HALVING_INTERVAL).rarity(), + Sat(50 * COIN_VALUE * u64::from(SUBSIDY_HALVING_INTERVAL)).rarity(), Rarity::Epic ); assert_eq!( - Sat(50 * COIN_VALUE * SUBSIDY_HALVING_INTERVAL + 1).rarity(), + Sat(50 * COIN_VALUE * u64::from(SUBSIDY_HALVING_INTERVAL) + 1).rarity(), Rarity::Common ); diff --git a/src/runes/etching.rs b/src/runes/etching.rs index ac350f82a7..e24cacd2e9 100644 --- a/src/runes/etching.rs +++ b/src/runes/etching.rs @@ -6,5 +6,5 @@ pub struct Etching { pub(crate) limit: Option, pub(crate) rune: Rune, pub(crate) symbol: Option, - pub(crate) term: Option, + pub(crate) term: Option, } diff --git a/src/runes/rune.rs b/src/runes/rune.rs index 99a0ec7801..4165070b8b 100644 --- a/src/runes/rune.rs +++ b/src/runes/rune.rs @@ -5,7 +5,7 @@ pub struct Rune(pub u128); impl Rune { pub(crate) fn minimum_at_height(height: Height) -> Self { - let length = 13u64 + let length = 13u32 .saturating_sub(height.0 / (DIFFCHANGE_INTERVAL * 2)) .max(1); @@ -146,7 +146,7 @@ mod tests { #[allow(clippy::zero_prefixed_literal)] fn minimum_at_height() { #[track_caller] - fn case(height: u64, minimum: &str) { + fn case(height: u32, minimum: &str) { assert_eq!(Rune::minimum_at_height(Height(height)).to_string(), minimum); } @@ -191,7 +191,7 @@ mod tests { case(2016 * 2 * 13 - 1, "A"); case(2016 * 2 * 13 + 0, "A"); case(2016 * 2 * 13 + 1, "A"); - case(u64::max_value(), "A"); + case(u32::max_value(), "A"); } #[test] diff --git a/src/runes/runestone.rs b/src/runes/runestone.rs index 949098e069..ad0275e453 100644 --- a/src/runes/runestone.rs +++ b/src/runes/runestone.rs @@ -91,7 +91,7 @@ impl Runestone { .and_then(char::from_u32), term: fields .remove(&TAG_TERM) - .and_then(|term| u64::try_from(term).ok()), + .and_then(|term| u32::try_from(term).ok()), }); Ok(Some(Self { diff --git a/src/sat.rs b/src/sat.rs index eab9fc48fc..a3e8fa4955 100644 --- a/src/sat.rs +++ b/src/sat.rs @@ -17,15 +17,16 @@ impl Sat { } pub(crate) fn height(self) -> Height { - self.epoch().starting_height() + self.epoch_position() / self.epoch().subsidy() + self.epoch().starting_height() + + u32::try_from(self.epoch_position() / self.epoch().subsidy()).unwrap() } - pub(crate) fn nineball(self) -> bool { - self.n() >= 50 * COIN_VALUE * 9 && self.n() < 50 * COIN_VALUE * 10 + pub(crate) fn cycle(self) -> u32 { + Epoch::from(self).0 / CYCLE_EPOCHS } - pub(crate) fn cycle(self) -> u64 { - Epoch::from(self).0 / CYCLE_EPOCHS + pub(crate) fn nineball(self) -> bool { + self.n() >= 50 * COIN_VALUE * 9 && self.n() < 50 * COIN_VALUE * 10 } pub(crate) fn percentile(self) -> String { @@ -36,7 +37,7 @@ impl Sat { self.into() } - pub(crate) fn period(self) -> u64 { + pub(crate) fn period(self) -> u32 { self.height().n() / DIFFCHANGE_INTERVAL } @@ -99,12 +100,12 @@ impl Sat { let (cycle_number, rest) = degree .split_once('°') .ok_or_else(|| anyhow!("missing degree symbol"))?; - let cycle_number = cycle_number.parse::()?; + let cycle_number = cycle_number.parse::()?; let (epoch_offset, rest) = rest .split_once('′') .ok_or_else(|| anyhow!("missing minute symbol"))?; - let epoch_offset = epoch_offset.parse::()?; + let epoch_offset = epoch_offset.parse::()?; if epoch_offset >= SUBSIDY_HALVING_INTERVAL { bail!("invalid epoch offset"); } @@ -112,14 +113,14 @@ impl Sat { let (period_offset, rest) = rest .split_once('″') .ok_or_else(|| anyhow!("missing second symbol"))?; - let period_offset = period_offset.parse::()?; + let period_offset = period_offset.parse::()?; if period_offset >= DIFFCHANGE_INTERVAL { bail!("invalid period offset"); } let cycle_start_epoch = cycle_number * CYCLE_EPOCHS; - const HALVING_INCREMENT: u64 = SUBSIDY_HALVING_INTERVAL % DIFFCHANGE_INTERVAL; + const HALVING_INCREMENT: u32 = SUBSIDY_HALVING_INTERVAL % DIFFCHANGE_INTERVAL; // For valid degrees the relationship between epoch_offset and period_offset // will increment by 336 every halving. @@ -291,37 +292,37 @@ mod tests { assert_eq!(Sat(50 * COIN_VALUE).degree().to_string(), "0°1′1″0‴"); assert_eq!(Sat(50 * COIN_VALUE + 1).degree().to_string(), "0°1′1″1‴"); assert_eq!( - Sat(50 * COIN_VALUE * DIFFCHANGE_INTERVAL - 1) + Sat(50 * COIN_VALUE * u64::from(DIFFCHANGE_INTERVAL) - 1) .degree() .to_string(), "0°2015′2015″4999999999‴" ); assert_eq!( - Sat(50 * COIN_VALUE * DIFFCHANGE_INTERVAL) + Sat(50 * COIN_VALUE * u64::from(DIFFCHANGE_INTERVAL)) .degree() .to_string(), "0°2016′0″0‴" ); assert_eq!( - Sat(50 * COIN_VALUE * DIFFCHANGE_INTERVAL + 1) + Sat(50 * COIN_VALUE * u64::from(DIFFCHANGE_INTERVAL) + 1) .degree() .to_string(), "0°2016′0″1‴" ); assert_eq!( - Sat(50 * COIN_VALUE * SUBSIDY_HALVING_INTERVAL - 1) + Sat(50 * COIN_VALUE * u64::from(SUBSIDY_HALVING_INTERVAL) - 1) .degree() .to_string(), "0°209999′335″4999999999‴" ); assert_eq!( - Sat(50 * COIN_VALUE * SUBSIDY_HALVING_INTERVAL) + Sat(50 * COIN_VALUE * u64::from(SUBSIDY_HALVING_INTERVAL)) .degree() .to_string(), "0°0′336″0‴" ); assert_eq!( - Sat(50 * COIN_VALUE * SUBSIDY_HALVING_INTERVAL + 1) + Sat(50 * COIN_VALUE * u64::from(SUBSIDY_HALVING_INTERVAL) + 1) .degree() .to_string(), "0°0′336″1‴" @@ -375,7 +376,10 @@ mod tests { fn epoch() { assert_eq!(Sat(0).epoch(), 0); assert_eq!(Sat(1).epoch(), 0); - assert_eq!(Sat(50 * COIN_VALUE * SUBSIDY_HALVING_INTERVAL).epoch(), 1); + assert_eq!( + Sat(50 * COIN_VALUE * u64::from(SUBSIDY_HALVING_INTERVAL)).epoch(), + 1 + ); assert_eq!(Sat(2099999997689999).epoch(), 32); } diff --git a/src/subcommand/info.rs b/src/subcommand/info.rs index 692c375b56..d8c25c07ff 100644 --- a/src/subcommand/info.rs +++ b/src/subcommand/info.rs @@ -8,9 +8,9 @@ pub(crate) struct Info { #[derive(Serialize, Deserialize)] pub struct TransactionsOutput { - pub start: u64, - pub end: u64, - pub count: u64, + pub start: u32, + pub end: u32, + pub count: u32, pub elapsed: f64, } diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 29d210712d..cedf65e860 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -55,7 +55,7 @@ pub struct ServerConfig { enum InscriptionQuery { Id(InscriptionId), - Number(i64), + Number(i32), } impl FromStr for InscriptionQuery { @@ -71,7 +71,7 @@ impl FromStr for InscriptionQuery { } enum BlockQuery { - Height(u64), + Height(u32), Hash(BlockHash), } @@ -666,7 +666,7 @@ impl Server { .get_block_by_hash(hash)? .ok_or_not_found(|| format!("block {hash}"))?; - (block, info.height as u64) + (block, u32::try_from(info.height).unwrap()) } }; @@ -918,7 +918,7 @@ impl Server { async fn block_hash_from_height( Extension(index): Extension>, - Path(height): Path, + Path(height): Path, ) -> ServerResult { Ok( index @@ -930,7 +930,7 @@ impl Server { async fn block_hash_from_height_json( Extension(index): Extension>, - Path(height): Path, + Path(height): Path, ) -> ServerResult> { Ok(Json( index @@ -952,7 +952,7 @@ impl Server { async fn input( Extension(page_config): Extension>, Extension(index): Extension>, - Path(path): Path<(u64, usize, usize)>, + Path(path): Path<(u32, usize, usize)>, ) -> Result, ServerError> { let not_found = || format!("input /{}/{}/{}", path.0, path.1, path.2); @@ -1189,9 +1189,14 @@ impl Server { let next = index.get_inscription_id_by_sequence_number(entry.sequence_number + 1)?; let (children, _more_children) = - index.get_children_by_inscription_id_paginated(inscription_id, 4, 0)?; + index.get_children_by_sequence_number_paginated(entry.sequence_number, 4, 0)?; - let rune = index.get_rune_by_inscription_id(inscription_id)?; + let rune = index.get_rune_by_sequence_number(entry.sequence_number)?; + + let parent = match entry.parent { + Some(parent) => index.get_inscription_id_by_sequence_number(parent)?, + None => None, + }; let mut charms = entry.charms; @@ -1205,7 +1210,7 @@ impl Server { children, inscription_number: entry.inscription_number, genesis_height: entry.height, - parent: entry.parent, + parent, genesis_fee: entry.fee, output_value: output.as_ref().map(|o| o.value), address: output @@ -1234,7 +1239,7 @@ impl Server { inscription_number: entry.inscription_number, next, output, - parent: entry.parent, + parent, previous, rune, sat: entry.sat, @@ -1293,13 +1298,14 @@ impl Server { Extension(index): Extension>, Path((parent, page)): Path<(InscriptionId, usize)>, ) -> ServerResult { - let parent_number = index + let entry = index .get_inscription_entry(parent)? - .ok_or_not_found(|| format!("inscription {parent}"))? - .inscription_number; + .ok_or_not_found(|| format!("inscription {parent}"))?; + + let parent_number = entry.inscription_number; let (children, more_children) = - index.get_children_by_inscription_id_paginated(parent, 100, page)?; + index.get_children_by_sequence_number_paginated(entry.sequence_number, 100, page)?; let prev_page = page.checked_sub(1); @@ -1329,7 +1335,7 @@ impl Server { async fn inscriptions_in_block( Extension(page_config): Extension>, Extension(index): Extension>, - Path(block_height): Path, + Path(block_height): Path, accept_json: AcceptJson, ) -> ServerResult { Self::inscriptions_in_block_from_page( @@ -1344,7 +1350,7 @@ impl Server { async fn inscriptions_in_block_from_page( Extension(page_config): Extension>, Extension(index): Extension>, - Path((block_height, page)): Path<(u64, usize)>, + Path((block_height, page)): Path<(u32, usize)>, accept_json: AcceptJson, ) -> ServerResult { let inscriptions = index.get_inscriptions_in_block(block_height)?; @@ -1366,7 +1372,7 @@ impl Server { async fn inscriptions_from( Extension(page_config): Extension>, Extension(index): Extension>, - Path(from): Path, + Path(from): Path, accept_json: AcceptJson, ) -> ServerResult { Self::inscriptions_inner(page_config, index, Some(from), 100, accept_json).await @@ -1375,7 +1381,7 @@ impl Server { async fn inscriptions_from_n( Extension(page_config): Extension>, Extension(index): Extension>, - Path((from, n)): Path<(u64, usize)>, + Path((from, n)): Path<(u32, usize)>, accept_json: AcceptJson, ) -> ServerResult { Self::inscriptions_inner(page_config, index, Some(from), n, accept_json).await @@ -1384,7 +1390,7 @@ impl Server { async fn inscriptions_inner( page_config: Arc, index: Arc, - from: Option, + from: Option, n: usize, accept_json: AcceptJson, ) -> ServerResult { diff --git a/src/subcommand/supply.rs b/src/subcommand/supply.rs index dcf86d3ed5..66622ef361 100644 --- a/src/subcommand/supply.rs +++ b/src/subcommand/supply.rs @@ -5,7 +5,7 @@ pub struct Output { pub supply: u64, pub first: u64, pub last: u64, - pub last_mined_in_block: u64, + pub last_mined_in_block: u32, } pub(crate) fn run() -> SubcommandResult { diff --git a/src/subcommand/traits.rs b/src/subcommand/traits.rs index 2b9a18de17..ce2bce499a 100644 --- a/src/subcommand/traits.rs +++ b/src/subcommand/traits.rs @@ -12,10 +12,10 @@ pub struct Output { pub decimal: String, pub degree: String, pub name: String, - pub height: u64, - pub cycle: u64, - pub epoch: u64, - pub period: u64, + pub height: u32, + pub cycle: u32, + pub epoch: u32, + pub period: u32, pub offset: u64, pub rarity: Rarity, } diff --git a/src/teleburn.rs b/src/teleburn.rs index 830918d366..c1fbd90dc1 100644 --- a/src/teleburn.rs +++ b/src/teleburn.rs @@ -1,11 +1,15 @@ -use {super::*, crate::index::entry::Entry, sha3::Digest, sha3::Keccak256}; +use {super::*, sha3::Digest, sha3::Keccak256}; #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Ethereum(String); impl From for Ethereum { fn from(inscription_id: InscriptionId) -> Self { - let digest = bitcoin::hashes::sha256::Hash::hash(&inscription_id.store()); + let mut array = [0; 36]; + let (txid, index) = array.split_at_mut(32); + txid.copy_from_slice(inscription_id.txid.as_ref()); + index.copy_from_slice(&inscription_id.index.to_be_bytes()); + let digest = bitcoin::hashes::sha256::Hash::hash(&array); Self(create_address_with_checksum(&hex::encode(&digest[0..20]))) } } diff --git a/src/templates/block.rs b/src/templates/block.rs index 5534aa71d5..52ae3d6c81 100644 --- a/src/templates/block.rs +++ b/src/templates/block.rs @@ -39,8 +39,8 @@ impl BlockHtml { pub struct BlockJson { pub hash: BlockHash, pub target: BlockHash, - pub best_height: u64, - pub height: u64, + pub best_height: u32, + pub height: u32, pub inscriptions: Vec, } diff --git a/src/templates/blocks.rs b/src/templates/blocks.rs index 5e790f4f01..52cc492e5a 100644 --- a/src/templates/blocks.rs +++ b/src/templates/blocks.rs @@ -2,14 +2,14 @@ use super::*; #[derive(Boilerplate)] pub(crate) struct BlocksHtml { - last: u64, + last: u32, blocks: Vec, featured_blocks: BTreeMap>, } impl BlocksHtml { pub(crate) fn new( - blocks: Vec<(u64, BlockHash)>, + blocks: Vec<(u32, BlockHash)>, featured_blocks: BTreeMap>, ) -> Self { Self { diff --git a/src/templates/children.rs b/src/templates/children.rs index ce744a489f..ac3621d57a 100644 --- a/src/templates/children.rs +++ b/src/templates/children.rs @@ -3,7 +3,7 @@ use super::*; #[derive(Boilerplate)] pub(crate) struct ChildrenHtml { pub(crate) parent: InscriptionId, - pub(crate) parent_number: i64, + pub(crate) parent_number: i32, pub(crate) children: Vec, pub(crate) prev_page: Option, pub(crate) next_page: Option, diff --git a/src/templates/clock.rs b/src/templates/clock.rs index 3fb9ba1079..aaeaecaae6 100644 --- a/src/templates/clock.rs +++ b/src/templates/clock.rs @@ -14,11 +14,12 @@ impl ClockSvg { Self { height, - hour: (min.n() % Epoch::FIRST_POST_SUBSIDY.starting_height().n()) as f64 - / Epoch::FIRST_POST_SUBSIDY.starting_height().n() as f64 + hour: f64::from(min.n() % Epoch::FIRST_POST_SUBSIDY.starting_height().n()) + / f64::from(Epoch::FIRST_POST_SUBSIDY.starting_height().n()) * 360.0, - minute: (min.n() % SUBSIDY_HALVING_INTERVAL) as f64 / SUBSIDY_HALVING_INTERVAL as f64 * 360.0, - second: height.period_offset() as f64 / DIFFCHANGE_INTERVAL as f64 * 360.0, + minute: f64::from(min.n() % SUBSIDY_HALVING_INTERVAL) / f64::from(SUBSIDY_HALVING_INTERVAL) + * 360.0, + second: f64::from(height.period_offset()) / f64::from(DIFFCHANGE_INTERVAL) * 360.0, } } } diff --git a/src/templates/input.rs b/src/templates/input.rs index aa070f605e..763758eac1 100644 --- a/src/templates/input.rs +++ b/src/templates/input.rs @@ -2,7 +2,7 @@ use super::*; #[derive(Boilerplate)] pub(crate) struct InputHtml { - pub(crate) path: (u64, usize, usize), + pub(crate) path: (u32, usize, usize), pub(crate) input: TxIn, } diff --git a/src/templates/inscription.rs b/src/templates/inscription.rs index ac458fcaec..f68da0c744 100644 --- a/src/templates/inscription.rs +++ b/src/templates/inscription.rs @@ -5,10 +5,10 @@ pub(crate) struct InscriptionHtml { pub(crate) chain: Chain, pub(crate) children: Vec, pub(crate) genesis_fee: u64, - pub(crate) genesis_height: u64, + pub(crate) genesis_height: u32, pub(crate) inscription: Inscription, pub(crate) inscription_id: InscriptionId, - pub(crate) inscription_number: i64, + pub(crate) inscription_number: i32, pub(crate) next: Option, pub(crate) output: Option, pub(crate) parent: Option, @@ -27,9 +27,9 @@ pub struct InscriptionJson { pub content_length: Option, pub content_type: Option, pub genesis_fee: u64, - pub genesis_height: u64, + pub genesis_height: u32, pub inscription_id: InscriptionId, - pub inscription_number: i64, + pub inscription_number: i32, pub next: Option, pub output_value: Option, pub parent: Option, diff --git a/src/templates/inscriptions.rs b/src/templates/inscriptions.rs index 19218c0d5b..258fad3f2a 100644 --- a/src/templates/inscriptions.rs +++ b/src/templates/inscriptions.rs @@ -3,26 +3,26 @@ use super::*; #[derive(Boilerplate)] pub(crate) struct InscriptionsHtml { pub(crate) inscriptions: Vec, - pub(crate) prev: Option, - pub(crate) next: Option, + pub(crate) prev: Option, + pub(crate) next: Option, } #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct InscriptionsJson { pub inscriptions: Vec, - pub prev: Option, - pub next: Option, - pub lowest: Option, - pub highest: Option, + pub prev: Option, + pub next: Option, + pub lowest: Option, + pub highest: Option, } impl InscriptionsJson { pub fn new( inscriptions: Vec, - prev: Option, - next: Option, - lowest: Option, - highest: Option, + prev: Option, + next: Option, + lowest: Option, + highest: Option, ) -> Self { Self { inscriptions, diff --git a/src/templates/inscriptions_block.rs b/src/templates/inscriptions_block.rs index e32d7592c6..3b95f82078 100644 --- a/src/templates/inscriptions_block.rs +++ b/src/templates/inscriptions_block.rs @@ -2,18 +2,18 @@ use super::*; #[derive(Boilerplate)] pub(crate) struct InscriptionsBlockHtml { - pub(crate) block: u64, + pub(crate) block: u32, pub(crate) inscriptions: Vec, - pub(crate) prev_block: Option, - pub(crate) next_block: Option, + pub(crate) prev_block: Option, + pub(crate) next_block: Option, pub(crate) prev_page: Option, pub(crate) next_page: Option, } impl InscriptionsBlockHtml { pub(crate) fn new( - block: u64, - current_blockheight: u64, + block: u32, + current_blockheight: u32, inscriptions: Vec, page_index: usize, ) -> Result { diff --git a/src/templates/sat.rs b/src/templates/sat.rs index c79c717749..78bb6ff3e6 100644 --- a/src/templates/sat.rs +++ b/src/templates/sat.rs @@ -14,10 +14,10 @@ pub struct SatJson { pub decimal: String, pub degree: String, pub name: String, - pub block: u64, - pub cycle: u64, - pub epoch: u64, - pub period: u64, + pub block: u32, + pub cycle: u32, + pub epoch: u32, + pub period: u32, pub offset: u64, pub rarity: Rarity, pub percentile: String, diff --git a/templates/blocks.html b/templates/blocks.html index 60631be4e9..b2cd37bb4b 100644 --- a/templates/blocks.html +++ b/templates/blocks.html @@ -2,7 +2,7 @@

    Blocks

    %% for (i, hash) in self.blocks.iter().enumerate() { %% if let Some(inscription_ids) = &self.featured_blocks.get(hash) {
    -

    Block {{ self.last - i as u64 }}

    +

    Block {{ self.last - i as u32 }}

    %% for id in *inscription_ids { {{ Iframe::thumbnail(*id) }} @@ -11,7 +11,7 @@

    Block {{ self.last - i as u64 }} %% } else { %% if i == self.featured_blocks.len() { -
      +
        %% }
      1. {{ hash }}
      2. %% } From 03de5b46cadfff3f7b6c1887b3f51b5f0f40998c Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 21 Nov 2023 17:17:12 -0800 Subject: [PATCH 21/41] Update redb to 1.4.0 (#2714) --- Cargo.lock | 17 +++++++++-------- Cargo.toml | 2 +- src/index.rs | 2 +- src/index/entry.rs | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ff7f69431..d0b901e123 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -880,9 +880,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "der-parser" @@ -2398,8 +2398,9 @@ dependencies = [ [[package]] name = "redb" -version = "1.3.0" -source = "git+https://github.com/cberner/redb.git?rev=c29eed6f866d50a2c79042fe55cf898a5aba1579#c29eed6f866d50a2c79042fe55cf898a5aba1579" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08837f9a129bde83c51953b8c96cbb3422b940166b730caa954836106eb1dfd2" dependencies = [ "libc", ] @@ -2787,18 +2788,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index bbaeed4494..5aaff046b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ mime_guess = "2.0.4" miniscript = "10.0.0" mp4 = "0.14.0" ord-bitcoincore-rpc = "0.17.1" -redb = { git = "https://github.com/cberner/redb.git", rev = "c29eed6f866d50a2c79042fe55cf898a5aba1579" } +redb = "1.4.0" regex = "1.6.0" rss = "2.0.1" rust-embed = "8.0.0" diff --git a/src/index.rs b/src/index.rs index eef4051eaa..36ef845c9d 100644 --- a/src/index.rs +++ b/src/index.rs @@ -35,7 +35,7 @@ mod updater; #[cfg(test)] pub(crate) mod testing; -const SCHEMA_VERSION: u64 = 12; +const SCHEMA_VERSION: u64 = 13; macro_rules! define_table { ($name:ident, $key:ty, $value:ty) => { diff --git a/src/index/entry.rs b/src/index/entry.rs index 5d835c8be8..d2f0dde17f 100644 --- a/src/index/entry.rs +++ b/src/index/entry.rs @@ -45,7 +45,7 @@ pub(super) type RuneEntryValue = ( u64, // number u128, // rune u128, // supply - Option, // symbol + Option, // symbol u32, // timestamp ); @@ -90,7 +90,7 @@ impl Entry for RuneEntry { number, rune: Rune(rune), supply, - symbol: symbol.map(|symbol| char::from_u32(symbol).unwrap()), + symbol, timestamp, } } @@ -117,7 +117,7 @@ impl Entry for RuneEntry { self.number, self.rune.0, self.supply, - self.symbol.map(u32::from), + self.symbol, self.timestamp, ) } @@ -417,7 +417,7 @@ mod tests { 5, 6, 7, - Some(u32::from('a')), + Some('a'), 6, ); From d666d90569af2bf27f7670355333405006c37074 Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 22 Nov 2023 02:47:10 +0100 Subject: [PATCH 22/41] Refactor inscriptions paginations (#2715) --- src/index.rs | 110 ++++++---------------------------- src/subcommand/server.rs | 108 +++++++++++++++++---------------- src/templates/inscriptions.rs | 28 ++------- tests/json_api.rs | 83 ++++--------------------- 4 files changed, 92 insertions(+), 237 deletions(-) diff --git a/src/index.rs b/src/index.rs index 36ef845c9d..300cfc04de 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1301,55 +1301,31 @@ impl Index { Ok(result) } - pub(crate) fn get_latest_inscriptions_with_prev_and_next( + pub(crate) fn get_inscriptions_paginated( &self, - n: usize, - from: Option, - ) -> Result<(Vec, Option, Option, u32, u32)> { + page_size: usize, + page_index: usize, + ) -> Result<(Vec, bool)> { let rtx = self.database.begin_read()?; let sequence_number_to_inscription_entry = rtx.open_table(SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY)?; - let highest = match sequence_number_to_inscription_entry.iter()?.next_back() { - Some(Ok((number, _entry))) => number.value(), - Some(Err(_)) | None => return Ok(Default::default()), - }; - - let lowest = match sequence_number_to_inscription_entry.iter()?.next() { - Some(Ok((number, _entry))) => number.value(), - Some(Err(_)) | None => return Ok(Default::default()), - }; - - let from = from.unwrap_or(highest); - - let prev = if let Some(prev) = from.checked_sub(n.try_into()?) { - sequence_number_to_inscription_entry - .get(&prev)? - .map(|_| prev) - } else { - None - }; - - let next = if from < highest { - Some( - from - .checked_add(n.try_into()?) - .unwrap_or(highest) - .min(highest), - ) - } else { - None - }; - - let inscriptions = sequence_number_to_inscription_entry - .range(..=from)? + let mut inscriptions = sequence_number_to_inscription_entry + .iter()? .rev() - .take(n) + .skip(page_size.saturating_mul(page_index)) + .take(page_size.saturating_add(1)) .flat_map(|result| result.map(|(_number, entry)| InscriptionEntry::load(entry.value()).id)) - .collect(); + .collect::>(); + + let more = inscriptions.len() > page_size; + + if more { + inscriptions.pop(); + } - Ok((inscriptions, prev, next, lowest, highest)) + Ok((inscriptions, more)) } pub(crate) fn get_inscriptions_in_block(&self, block_height: u32) -> Result> { @@ -2820,59 +2796,9 @@ mod tests { context.mine_blocks(1); - let (inscriptions, prev, next, _, _) = context - .index - .get_latest_inscriptions_with_prev_and_next(100, None) - .unwrap(); + let (inscriptions, more) = context.index.get_inscriptions_paginated(100, 0).unwrap(); assert_eq!(inscriptions, &[inscription_id]); - assert_eq!(prev, None); - assert_eq!(next, None); - } - } - - #[test] - fn get_latest_inscriptions_with_prev_and_next() { - for context in Context::configurations() { - context.mine_blocks(1); - - let mut ids = Vec::new(); - - for i in 0..103 { - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { - inputs: &[(i + 1, 0, 0, inscription("text/plain", "hello").to_witness())], - ..Default::default() - }); - ids.push(InscriptionId { txid, index: 0 }); - context.mine_blocks(1); - } - - ids.reverse(); - - let (inscriptions, prev, next, lowest, highest) = context - .index - .get_latest_inscriptions_with_prev_and_next(100, None) - .unwrap(); - assert_eq!(inscriptions, &ids[..100]); - assert_eq!(prev, Some(2)); - assert_eq!(next, None); - assert_eq!(highest, 102); - assert_eq!(lowest, 0); - - let (inscriptions, prev, next, _lowest, _highest) = context - .index - .get_latest_inscriptions_with_prev_and_next(100, Some(101)) - .unwrap(); - assert_eq!(inscriptions, &ids[1..101]); - assert_eq!(prev, Some(1)); - assert_eq!(next, Some(102)); - - let (inscriptions, prev, next, _lowest, _highest) = context - .index - .get_latest_inscriptions_with_prev_and_next(100, Some(0)) - .unwrap(); - assert_eq!(inscriptions, &ids[102..103]); - assert_eq!(prev, None); - assert_eq!(next, Some(100)); + assert!(!more); } } diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index cedf65e860..1f9c941fc3 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -211,15 +211,14 @@ impl Server { .route("/input/:block/:transaction/:input", get(Self::input)) .route("/inscription/:inscription_query", get(Self::inscription)) .route("/inscriptions", get(Self::inscriptions)) - .route("/inscriptions/:from", get(Self::inscriptions_from)) - .route("/inscriptions/:from/:n", get(Self::inscriptions_from_n)) + .route("/inscriptions/:page", get(Self::inscriptions_paginated)) .route( "/inscriptions/block/:height", get(Self::inscriptions_in_block), ) .route( "/inscriptions/block/:height/:page", - get(Self::inscriptions_in_block_from_page), + get(Self::inscriptions_in_block_paginated), ) .route("/install.sh", get(Self::install_script)) .route("/ordinal/:sat", get(Self::ordinal)) @@ -1329,88 +1328,95 @@ impl Server { Extension(index): Extension>, accept_json: AcceptJson, ) -> ServerResult { - Self::inscriptions_inner(page_config, index, None, 100, accept_json).await - } - - async fn inscriptions_in_block( - Extension(page_config): Extension>, - Extension(index): Extension>, - Path(block_height): Path, - accept_json: AcceptJson, - ) -> ServerResult { - Self::inscriptions_in_block_from_page( + Self::inscriptions_paginated( Extension(page_config), Extension(index), - Path((block_height, 0)), + Path(0), accept_json, ) .await } - async fn inscriptions_in_block_from_page( + async fn inscriptions_paginated( Extension(page_config): Extension>, Extension(index): Extension>, - Path((block_height, page)): Path<(u32, usize)>, + Path(page_index): Path, accept_json: AcceptJson, ) -> ServerResult { - let inscriptions = index.get_inscriptions_in_block(block_height)?; + let (inscriptions, more_inscriptions) = index.get_inscriptions_paginated(100, page_index)?; + + let prev = page_index.checked_sub(1); + + let next = more_inscriptions.then_some(page_index + 1); Ok(if accept_json.0 { - Json(InscriptionsJson::new(inscriptions, None, None, None, None)).into_response() + Json(InscriptionsJson { + inscriptions, + page_index, + more: more_inscriptions, + }) + .into_response() } else { - InscriptionsBlockHtml::new( - block_height, - index.block_height()?.unwrap_or(Height(0)).n(), + InscriptionsHtml { inscriptions, - page, - )? + next, + prev, + } .page(page_config) .into_response() }) } - async fn inscriptions_from( + async fn inscriptions_in_block( Extension(page_config): Extension>, Extension(index): Extension>, - Path(from): Path, + Path(block_height): Path, accept_json: AcceptJson, ) -> ServerResult { - Self::inscriptions_inner(page_config, index, Some(from), 100, accept_json).await + Self::inscriptions_in_block_paginated( + Extension(page_config), + Extension(index), + Path((block_height, 0)), + accept_json, + ) + .await } - async fn inscriptions_from_n( + async fn inscriptions_in_block_paginated( Extension(page_config): Extension>, Extension(index): Extension>, - Path((from, n)): Path<(u32, usize)>, + Path((block_height, page_index)): Path<(u32, usize)>, accept_json: AcceptJson, ) -> ServerResult { - Self::inscriptions_inner(page_config, index, Some(from), n, accept_json).await - } + let page_size = 100; + + let mut inscriptions = index + .get_inscriptions_in_block(block_height)? + .into_iter() + .skip(page_index.saturating_mul(page_size)) + .take(page_size.saturating_add(1)) + .collect::>(); + + let more = inscriptions.len() > page_size; + + if more { + inscriptions.pop(); + } - async fn inscriptions_inner( - page_config: Arc, - index: Arc, - from: Option, - n: usize, - accept_json: AcceptJson, - ) -> ServerResult { - let (inscriptions, prev, next, lowest, highest) = - index.get_latest_inscriptions_with_prev_and_next(n, from)?; Ok(if accept_json.0 { - Json(InscriptionsJson::new( + Json(InscriptionsJson { inscriptions, - prev, - next, - Some(lowest), - Some(highest), - )) + page_index, + more, + }) .into_response() } else { - InscriptionsHtml { + InscriptionsBlockHtml::new( + block_height, + index.block_height()?.unwrap_or(Height(0)).n(), inscriptions, - next, - prev, - } + page_index, + )? .page(page_config) .into_response() }) @@ -3592,7 +3598,7 @@ mod tests { server.mine_blocks(1); server.assert_response_regex( - "/inscriptions", + "/inscriptions/1", StatusCode::OK, ".*\nnext.*", ); @@ -3615,7 +3621,7 @@ mod tests { server.assert_response_regex( "/inscriptions/0", StatusCode::OK, - ".*prev\n.*", + ".*prev\n.*", ); } diff --git a/src/templates/inscriptions.rs b/src/templates/inscriptions.rs index 258fad3f2a..f7dc94b762 100644 --- a/src/templates/inscriptions.rs +++ b/src/templates/inscriptions.rs @@ -3,35 +3,15 @@ use super::*; #[derive(Boilerplate)] pub(crate) struct InscriptionsHtml { pub(crate) inscriptions: Vec, - pub(crate) prev: Option, - pub(crate) next: Option, + pub(crate) prev: Option, + pub(crate) next: Option, } #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct InscriptionsJson { pub inscriptions: Vec, - pub prev: Option, - pub next: Option, - pub lowest: Option, - pub highest: Option, -} - -impl InscriptionsJson { - pub fn new( - inscriptions: Vec, - prev: Option, - next: Option, - lowest: Option, - highest: Option, - ) -> Self { - Self { - inscriptions, - prev, - next, - lowest, - highest, - } - } + pub more: bool, + pub page_index: usize, } impl PageContent for InscriptionsHtml { diff --git a/tests/json_api.rs b/tests/json_api.rs index e40e75702d..ab3dfb8e8e 100644 --- a/tests/json_api.rs +++ b/tests/json_api.rs @@ -167,12 +167,17 @@ fn get_inscription() { ) } -fn create_210_inscriptions(rpc_server: &test_bitcoincore_rpc::Handle) -> Vec { +#[test] +fn get_inscriptions() { + let rpc_server = test_bitcoincore_rpc::spawn(); + + create_wallet(&rpc_server); + let witness = envelope(&[b"ord", &[1], b"text/plain;charset=utf-8", &[], b"bar"]); let mut inscriptions = Vec::new(); - // Create 150 inscriptions, 50 non-cursed and 100 cursed + // Create 150 inscriptions for i in 0..50 { rpc_server.mine_blocks(1); rpc_server.mine_blocks(1); @@ -194,32 +199,6 @@ fn create_210_inscriptions(rpc_server: &test_bitcoincore_rpc::Handle) -> Vec>() - ); - - let (lowest, highest) = ( - inscriptions_json.lowest.unwrap(), - inscriptions_json.highest.unwrap(), - ); - - for i in lowest..=highest { - let response = server.json_request(format!("/inscriptions/{}/1", i)); - assert_eq!(response.status(), StatusCode::OK); - - let inscriptions_json: InscriptionsJson = - serde_json::from_str(&response.text().unwrap()).unwrap(); - - assert_eq!(inscriptions_json.inscriptions.len(), 1); - assert_eq!( - inscriptions_json.inscriptions[0], - inscriptions[(i - lowest) as usize] - ); - - let response = server.json_request(format!( - "/inscription/{}", - inscriptions_json.inscriptions[0] - )); - assert_eq!(response.status(), StatusCode::OK); - - let inscription_json: InscriptionJson = - serde_json::from_str(&response.text().unwrap()).unwrap(); - - assert_eq!( - inscription_json.inscription_id, - inscriptions_json.inscriptions[0] - ); - } + assert_eq!(inscriptions_json.inscriptions.len(), 50); + assert!(!inscriptions_json.more); + assert_eq!(inscriptions_json.page_index, 1); } #[test] From 50e5b454bf203ca2b62acc1cc9bd1f54d1dfb96a Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 21 Nov 2023 18:11:05 -0800 Subject: [PATCH 23/41] Display table stats in `ord index info` (#2711) --- src/index.rs | 121 +++++++++++++++++++++++++---- src/subcommand.rs | 6 +- src/subcommand/index.rs | 4 + src/subcommand/{ => index}/info.rs | 2 + tests/info.rs | 14 ++-- 5 files changed, 121 insertions(+), 26 deletions(-) rename src/subcommand/{ => index}/info.rs (99%) diff --git a/src/index.rs b/src/index.rs index 300cfc04de..e759f59a99 100644 --- a/src/index.rs +++ b/src/index.rs @@ -17,8 +17,9 @@ use { indicatif::{ProgressBar, ProgressStyle}, log::log_enabled, redb::{ - Database, DatabaseError, MultimapTable, MultimapTableDefinition, ReadableMultimapTable, - ReadableTable, StorageError, Table, TableDefinition, WriteTransaction, + Database, DatabaseError, MultimapTable, MultimapTableDefinition, MultimapTableHandle, + ReadableMultimapTable, ReadableTable, RedbKey, RedbValue, StorageError, Table, TableDefinition, + TableHandle, WriteTransaction, }, std::collections::{BTreeSet, HashMap}, std::io::{BufWriter, Read, Write}, @@ -106,20 +107,31 @@ impl From for u64 { #[derive(Serialize)] pub(crate) struct Info { - pub(crate) blocks_indexed: u32, - pub(crate) branch_pages: u64, - pub(crate) fragmented_bytes: u64, - pub(crate) index_file_size: u64, - pub(crate) index_path: PathBuf, - pub(crate) leaf_pages: u64, - pub(crate) metadata_bytes: u64, - pub(crate) outputs_traversed: u64, - pub(crate) page_size: usize, - pub(crate) sat_ranges: u64, - pub(crate) stored_bytes: u64, + blocks_indexed: u32, + branch_pages: u64, + fragmented_bytes: u64, + index_file_size: u64, + index_path: PathBuf, + leaf_pages: u64, + metadata_bytes: u64, + outputs_traversed: u64, + page_size: usize, + sat_ranges: u64, + stored_bytes: u64, + tables: BTreeMap, pub(crate) transactions: Vec, - pub(crate) tree_height: u32, - pub(crate) utxos_indexed: u64, + tree_height: u32, + utxos_indexed: u64, +} + +#[derive(Serialize)] +pub(crate) struct TableInfo { + branch_pages: u64, + fragmented_bytes: u64, + leaf_pages: u64, + metadata_bytes: u64, + stored_bytes: u64, + tree_height: u32, } #[derive(Serialize)] @@ -419,10 +431,88 @@ impl Index { } pub(crate) fn info(&self) -> Result { + fn insert_table_info( + tables: &mut BTreeMap, + wtx: &WriteTransaction, + definition: TableDefinition, + ) { + let stats = wtx.open_table(definition).unwrap().stats().unwrap(); + tables.insert( + definition.name().into(), + TableInfo { + tree_height: stats.tree_height(), + leaf_pages: stats.leaf_pages(), + branch_pages: stats.branch_pages(), + stored_bytes: stats.stored_bytes(), + metadata_bytes: stats.metadata_bytes(), + fragmented_bytes: stats.fragmented_bytes(), + }, + ); + } + + fn insert_multimap_table_info( + tables: &mut BTreeMap, + wtx: &WriteTransaction, + definition: MultimapTableDefinition, + ) { + let stats = wtx + .open_multimap_table(definition) + .unwrap() + .stats() + .unwrap(); + tables.insert( + definition.name().into(), + TableInfo { + tree_height: stats.tree_height(), + leaf_pages: stats.leaf_pages(), + branch_pages: stats.branch_pages(), + stored_bytes: stats.stored_bytes(), + metadata_bytes: stats.metadata_bytes(), + fragmented_bytes: stats.fragmented_bytes(), + }, + ); + } + let wtx = self.begin_write()?; let stats = wtx.stats()?; + let mut tables: BTreeMap = BTreeMap::new(); + + insert_multimap_table_info(&mut tables, &wtx, SATPOINT_TO_SEQUENCE_NUMBER); + insert_multimap_table_info(&mut tables, &wtx, SAT_TO_SEQUENCE_NUMBER); + insert_multimap_table_info(&mut tables, &wtx, SEQUENCE_NUMBER_TO_CHILDREN); + insert_table_info(&mut tables, &wtx, HEIGHT_TO_BLOCK_HASH); + insert_table_info(&mut tables, &wtx, HEIGHT_TO_BLOCK_HASH); + insert_table_info(&mut tables, &wtx, HEIGHT_TO_LAST_SEQUENCE_NUMBER); + insert_table_info(&mut tables, &wtx, HOME_INSCRIPTIONS); + insert_table_info(&mut tables, &wtx, INSCRIPTION_ID_TO_SEQUENCE_NUMBER); + insert_table_info(&mut tables, &wtx, INSCRIPTION_NUMBER_TO_SEQUENCE_NUMBER); + insert_table_info(&mut tables, &wtx, OUTPOINT_TO_RUNE_BALANCES); + insert_table_info(&mut tables, &wtx, OUTPOINT_TO_SAT_RANGES); + insert_table_info(&mut tables, &wtx, OUTPOINT_TO_VALUE); + insert_table_info(&mut tables, &wtx, RUNE_ID_TO_RUNE_ENTRY); + insert_table_info(&mut tables, &wtx, RUNE_TO_RUNE_ID); + insert_table_info(&mut tables, &wtx, SAT_TO_SATPOINT); + insert_table_info(&mut tables, &wtx, SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY); + insert_table_info(&mut tables, &wtx, SEQUENCE_NUMBER_TO_RUNE); + insert_table_info(&mut tables, &wtx, SEQUENCE_NUMBER_TO_SATPOINT); + insert_table_info(&mut tables, &wtx, STATISTIC_TO_COUNT); + insert_table_info(&mut tables, &wtx, TRANSACTION_ID_TO_RUNE); + insert_table_info( + &mut tables, + &wtx, + WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP, + ); + + for table in wtx.list_tables()? { + assert!(tables.contains_key(table.name())); + } + + for table in wtx.list_multimap_tables()? { + assert!(tables.contains_key(table.name())); + } + let info = { let statistic_to_count = wtx.open_table(STATISTIC_TO_COUNT)?; let sat_ranges = statistic_to_count @@ -451,6 +541,7 @@ impl Index { outputs_traversed, page_size: stats.page_size(), stored_bytes: stats.stored_bytes(), + tables, transactions: wtx .open_table(WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP)? .range(0..)? diff --git a/src/subcommand.rs b/src/subcommand.rs index 93e393dcea..687fa187e8 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -3,8 +3,7 @@ use super::*; pub mod decode; pub mod epochs; pub mod find; -mod index; -pub mod info; +pub mod index; pub mod list; pub mod parse; mod preview; @@ -25,8 +24,6 @@ pub(crate) enum Subcommand { Find(find::Find), #[command(subcommand, about = "Index commands")] Index(index::IndexSubcommand), - #[command(about = "Display index statistics")] - Info(info::Info), #[command(about = "List the satoshis in an output")] List(list::List), #[command(about = "Parse a satoshi from ordinal notation")] @@ -54,7 +51,6 @@ impl Subcommand { Self::Epochs => epochs::run(), Self::Find(find) => find.run(options), Self::Index(index) => index.run(options), - Self::Info(info) => info.run(options), Self::List(list) => list.run(options), Self::Parse(parse) => parse.run(), Self::Preview(preview) => preview.run(), diff --git a/src/subcommand/index.rs b/src/subcommand/index.rs index 326c1a11b2..a76b9dca42 100644 --- a/src/subcommand/index.rs +++ b/src/subcommand/index.rs @@ -1,12 +1,15 @@ use super::*; mod export; +pub mod info; mod update; #[derive(Debug, Parser)] pub(crate) enum IndexSubcommand { #[command(about = "Write inscription numbers and ids to a tab-separated file")] Export(export::Export), + #[command(about = "Print index statistics")] + Info(info::Info), #[command(about = "Update the index", alias = "run")] Update, } @@ -15,6 +18,7 @@ impl IndexSubcommand { pub(crate) fn run(self, options: Options) -> SubcommandResult { match self { Self::Export(export) => export.run(options), + Self::Info(info) => info.run(options), Self::Update => update::run(options), } } diff --git a/src/subcommand/info.rs b/src/subcommand/index/info.rs similarity index 99% rename from src/subcommand/info.rs rename to src/subcommand/index/info.rs index d8c25c07ff..8b9a2deb07 100644 --- a/src/subcommand/info.rs +++ b/src/subcommand/index/info.rs @@ -17,7 +17,9 @@ pub struct TransactionsOutput { impl Info { pub(crate) fn run(self, options: Options) -> SubcommandResult { let index = Index::open(&options)?; + index.update()?; + let info = index.info()?; if self.transactions { diff --git a/tests/info.rs b/tests/info.rs index 414651b175..fb431f267c 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -1,9 +1,9 @@ -use {super::*, ord::subcommand::info::TransactionsOutput}; +use {super::*, ord::subcommand::index::info::TransactionsOutput}; #[test] fn json_with_satoshi_index() { let rpc_server = test_bitcoincore_rpc::spawn(); - CommandBuilder::new("--index-sats info") + CommandBuilder::new("--index-sats index info") .rpc_server(&rpc_server) .stdout_regex( r#"\{ @@ -18,6 +18,7 @@ fn json_with_satoshi_index() { "page_size": \d+, "sat_ranges": 1, "stored_bytes": \d+, + "tables": .*, "transactions": \[ \{ "starting_block_count": 0, @@ -35,7 +36,7 @@ fn json_with_satoshi_index() { #[test] fn json_without_satoshi_index() { let rpc_server = test_bitcoincore_rpc::spawn(); - CommandBuilder::new("info") + CommandBuilder::new("index info") .rpc_server(&rpc_server) .stdout_regex( r#"\{ @@ -50,6 +51,7 @@ fn json_without_satoshi_index() { "page_size": \d+, "sat_ranges": 0, "stored_bytes": \d+, + "tables": .*, "transactions": \[ \{ "starting_block_count": 0, @@ -73,7 +75,7 @@ fn transactions() { let index_path = tempdir.path().join("index.redb"); assert!(CommandBuilder::new(format!( - "--index {} info --transactions", + "--index {} index info --transactions", index_path.display() )) .rpc_server(&rpc_server) @@ -83,7 +85,7 @@ fn transactions() { rpc_server.mine_blocks(10); let output = CommandBuilder::new(format!( - "--index {} info --transactions", + "--index {} index info --transactions", index_path.display() )) .rpc_server(&rpc_server) @@ -96,7 +98,7 @@ fn transactions() { rpc_server.mine_blocks(10); let output = CommandBuilder::new(format!( - "--index {} info --transactions", + "--index {} index info --transactions", index_path.display() )) .rpc_server(&rpc_server) From a564dc97eb02e319eb181a10dbd9961bdd25996e Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Tue, 21 Nov 2023 23:20:45 -0800 Subject: [PATCH 24/41] Use redb's recovery callback API (#2584) --- src/index.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/index.rs b/src/index.rs index e759f59a99..fc4fea03e7 100644 --- a/src/index.rs +++ b/src/index.rs @@ -21,8 +21,11 @@ use { ReadableMultimapTable, ReadableTable, RedbKey, RedbValue, StorageError, Table, TableDefinition, TableHandle, WriteTransaction, }, - std::collections::{BTreeSet, HashMap}, - std::io::{BufWriter, Read, Write}, + std::{ + collections::{BTreeSet, HashMap}, + io::{BufWriter, Write}, + sync::Once, + }, }; pub(crate) use self::entry::RuneEntry; @@ -204,20 +207,6 @@ impl Index { } }; - if let Ok(mut file) = fs::OpenOptions::new().read(true).open(&path) { - // use cberner's quick hack to check the redb recovery bit - // https://github.com/cberner/redb/issues/639#issuecomment-1628037591 - const MAGICNUMBER: [u8; 9] = [b'r', b'e', b'd', b'b', 0x1A, 0x0A, 0xA9, 0x0D, 0x0A]; - const RECOVERY_REQUIRED: u8 = 2; - - let mut buffer = [0; MAGICNUMBER.len() + 1]; - file.read_exact(&mut buffer).unwrap(); - - if buffer[MAGICNUMBER.len()] & RECOVERY_REQUIRED != 0 { - println!("Index file {:?} needs recovery. This can take a long time, especially for the --index-sats index.", path); - } - } - log::info!("Setting DB cache size to {} bytes", db_cache_size); let durability = if cfg!(test) { @@ -229,8 +218,15 @@ impl Index { let index_runes; let index_sats; + let index_path = path.clone(); + let once = Once::new(); let database = match Database::builder() .set_cache_size(db_cache_size) + .set_repair_callback(move |_| { + once.call_once(|| { + println!("Index file `{}` needs recovery. This can take a long time, especially for the --index-sats index.", index_path.display()); + }) + }) .open(&path) { Ok(database) => { From bd6a1a7137c1f2dbc761cbbb9dd69fce07957a89 Mon Sep 17 00:00:00 2001 From: Rijndael <115941166+rot13maxi@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:31:37 -0500 Subject: [PATCH 25/41] Allow setting CSP origin (#2708) --- src/page_config.rs | 3 +- src/subcommand/server.rs | 79 ++++++++++++++++++++++++++++++++++------ src/templates.rs | 10 +++-- 3 files changed, 76 insertions(+), 16 deletions(-) diff --git a/src/page_config.rs b/src/page_config.rs index 0bc36cb5cc..07c408c02a 100644 --- a/src/page_config.rs +++ b/src/page_config.rs @@ -1,8 +1,9 @@ use super::*; -#[derive(Clone)] +#[derive(Clone, Default)] pub(crate) struct PageConfig { pub(crate) chain: Chain, + pub(crate) csp_origin: Option, pub(crate) domain: Option, pub(crate) index_sats: bool, } diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 1f9c941fc3..d458b0f8f7 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -132,6 +132,11 @@ pub(crate) struct Server { help = "Request ACME TLS certificate for . This ord instance must be reachable at :443 to respond to Let's Encrypt ACME challenges." )] acme_domain: Vec, + #[arg( + long, + help = "Use in Content-Security-Policy header. Set this to the public-facing URL of your ord instance." + )] + csp_origin: Option, #[arg( long, help = "Listen on for incoming HTTP requests. [default: 80]." @@ -182,6 +187,7 @@ impl Server { let page_config = Arc::new(PageConfig { chain: options.chain(), + csp_origin: self.csp_origin.clone(), domain: acme_domains.first().cloned(), index_sats: index.has_sat_index(), }); @@ -985,6 +991,7 @@ impl Server { async fn content( Extension(index): Extension>, Extension(config): Extension>, + Extension(page_config): Extension>, Path(inscription_id): Path, accept_encoding: AcceptEncoding, ) -> ServerResult { @@ -997,7 +1004,7 @@ impl Server { .ok_or_not_found(|| format!("inscription {inscription_id}"))?; Ok( - Self::content_response(inscription, accept_encoding)? + Self::content_response(inscription, accept_encoding, &page_config)? .ok_or_not_found(|| format!("inscription {inscription_id} content"))? .into_response(), ) @@ -1006,6 +1013,7 @@ impl Server { fn content_response( inscription: Inscription, accept_encoding: AcceptEncoding, + page_config: &PageConfig, ) -> ServerResult)>> { let mut headers = HeaderMap::new(); @@ -1027,15 +1035,25 @@ impl Server { } } - headers.insert( - header::CONTENT_SECURITY_POLICY, - HeaderValue::from_static("default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob:"), - ); - - headers.append( - header::CONTENT_SECURITY_POLICY, - HeaderValue::from_static("default-src *:*/content/ *:*/blockheight *:*/blockhash *:*/blockhash/ *:*/blocktime *:*/r/ 'unsafe-eval' 'unsafe-inline' data: blob:"), - ); + match &page_config.csp_origin { + None => { + headers.insert( + header::CONTENT_SECURITY_POLICY, + HeaderValue::from_static("default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob:"), + ); + headers.append( + header::CONTENT_SECURITY_POLICY, + HeaderValue::from_static("default-src *:*/content/ *:*/blockheight *:*/blockhash *:*/blockhash/ *:*/blocktime *:*/r/ 'unsafe-eval' 'unsafe-inline' data: blob:"), + ); + } + Some(origin) => { + let csp = format!("default-src {origin}/content/ {origin}/blockheight {origin}/blockhash {origin}/blockhash/ {origin}/blocktime {origin}/r/ 'unsafe-eval' 'unsafe-inline' data: blob:"); + headers.insert( + header::CONTENT_SECURITY_POLICY, + HeaderValue::from_str(&csp).map_err(|err| ServerError::Internal(Error::from(err)))?, + ); + } + } headers.insert( header::CACHE_CONTROL, @@ -1052,6 +1070,7 @@ impl Server { async fn preview( Extension(index): Extension>, Extension(config): Extension>, + Extension(page_config): Extension>, Path(inscription_id): Path, accept_encoding: AcceptEncoding, ) -> ServerResult { @@ -1089,7 +1108,7 @@ impl Server { .into_response(), ), Media::Iframe => Ok( - Self::content_response(inscription, accept_encoding)? + Self::content_response(inscription, accept_encoding, &page_config)? .ok_or_not_found(|| format!("inscription {inscription_id} content"))? .into_response(), ), @@ -3131,7 +3150,8 @@ mod tests { assert_eq!( Server::content_response( Inscription::new(Some("text/plain".as_bytes().to_vec()), None), - AcceptEncoding::default() + AcceptEncoding::default(), + &PageConfig::default(), ) .unwrap(), None @@ -3143,6 +3163,7 @@ mod tests { let (headers, body) = Server::content_response( Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])), AcceptEncoding::default(), + &PageConfig::default(), ) .unwrap() .unwrap(); @@ -3151,6 +3172,38 @@ mod tests { assert_eq!(body, vec![1, 2, 3]); } + #[test] + fn content_security_policy_no_origin() { + let (headers, _) = Server::content_response( + Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])), + AcceptEncoding::default(), + &PageConfig::default(), + ) + .unwrap() + .unwrap(); + + assert_eq!( + headers["content-security-policy"], + HeaderValue::from_static("default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob:") + ); + } + + #[test] + fn content_security_policy_with_origin() { + let (headers, _) = Server::content_response( + Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])), + AcceptEncoding::default(), + &PageConfig { + csp_origin: Some("https://ordinals.com".into()), + ..Default::default() + }, + ) + .unwrap() + .unwrap(); + + assert_eq!(headers["content-security-policy"], HeaderValue::from_static("default-src https://ordinals.com/content/ https://ordinals.com/blockheight https://ordinals.com/blockhash https://ordinals.com/blockhash/ https://ordinals.com/blocktime https://ordinals.com/r/ 'unsafe-eval' 'unsafe-inline' data: blob:")); + } + #[test] fn code_preview() { let server = TestServer::new_with_regtest(); @@ -3181,6 +3234,7 @@ mod tests { let (headers, body) = Server::content_response( Inscription::new(None, Some(Vec::new())), AcceptEncoding::default(), + &PageConfig::default(), ) .unwrap() .unwrap(); @@ -3194,6 +3248,7 @@ mod tests { let (headers, body) = Server::content_response( Inscription::new(Some("\n".as_bytes().to_vec()), Some(Vec::new())), AcceptEncoding::default(), + &PageConfig::default(), ) .unwrap() .unwrap(); diff --git a/src/templates.rs b/src/templates.rs index 32f6653776..7ad6b30c8a 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -117,6 +117,7 @@ mod tests { assert_regex_match!( Foo.page(Arc::new(PageConfig { chain: Chain::Mainnet, + csp_origin: Some("https://signet.ordinals.com".into()), domain: Some("signet.ordinals.com".into()), index_sats: true, }),), @@ -162,9 +163,10 @@ mod tests { assert_regex_match!( Foo.page(Arc::new(PageConfig { chain: Chain::Mainnet, + csp_origin: None, domain: None, index_sats: true, - }),), + })), r".*