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) {