diff --git a/src/crates/barser/Cargo.lock b/src/crates/barser/Cargo.lock new file mode 100644 index 000000000..7d20da2a9 --- /dev/null +++ b/src/crates/barser/Cargo.lock @@ -0,0 +1,1094 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base58ck" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals", + "bitcoin_hashes", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + +[[package]] +name = "bitcoin" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026" +dependencies = [ + "base58ck", + "bech32", + "bitcoin-internals", + "bitcoin-io", + "bitcoin-units", + "bitcoin_hashes", + "hex-conservative", + "hex_lit", + "secp256k1", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals", + "serde", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", + "serde", +] + +[[package]] +name = "bitcoincore-rpc" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedd23ae0fd321affb4bbbc36126c6f49a32818dc6b979395d24da8c9d4e80ee" +dependencies = [ + "bitcoincore-rpc-json", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoincore-rpc-json" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8909583c5fab98508e80ef73e5592a651c954993dc6b7739963257d19f0e71a" +dependencies = [ + "bitcoin", + "serde", + "serde_json", +] + +[[package]] +name = "biter" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02527a2b7944d9edc90db0a73339c57cd521f9623f99416574d1943312c9d290" +dependencies = [ + "bitcoin", + "bitcoincore-rpc", + "crossbeam", + "derived-deref", + "rayon", + "serde", + "serde_json", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "color-eyre" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-skiplist" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "derive_deref" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcdbcee2d9941369faba772587a565f4f534e42cb8d17e5295871de730163b2b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derived-deref" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805ef2023ccd65425743a91ecd11fc020979a0b01921db3104fb606d18a7b43e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + +[[package]] +name = "double-ended-peekable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0d05e1c0dbad51b52c38bda7adceef61b9efc2baf04acfe8726a8c4630a6f57" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.92", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fjall" +version = "2.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd1bb382d52e527f10f5ed3f126bb4a87c77fbf878a1432010820a71aaa6322" +dependencies = [ + "byteorder", + "dashmap", + "log", + "lsm-tree", + "path-absolutize", + "std-semaphore", + "tempfile", + "xxhash-rust", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "guardian" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "493913a18c0d7bebb75127a26a432162c59edbe06f6cf712001e3e769345e8b5" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jsonrpc" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf" +dependencies = [ + "base64", + "minreq", + "serde", + "serde_json", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lsm-tree" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7952bc71e90c0b58ce441dcf6cf8624cac042125dec1183ec9c48144f74378d" +dependencies = [ + "byteorder", + "crossbeam-skiplist", + "double-ended-peekable", + "enum_dispatch", + "guardian", + "log", + "lz4_flex", + "path-absolutize", + "quick_cache", + "rustc-hash", + "self_cell", + "tempfile", + "value-log", + "varint-rs", + "xxhash-rust", +] + +[[package]] +name = "lz4_flex" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "min-max-heap" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2687e6cf9c00f48e9284cf9fd15f2ef341d03cc7743abf9df4c5f07fdee50b18" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "minreq" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36a8e50e917e18a37d500d27d40b7bc7d127e71c0c94fb2d83f43b4afd308390" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "path-absolutize" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4af381fe79fa195b4909485d99f73a80792331df0625188e707854f0b3383f5" +dependencies = [ + "path-dedot", +] + +[[package]] +name = "path-dedot" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ba0ad7e047712414213ff67533e6dd477af0a4e1d14fb52343e53d30ea9397" +dependencies = [ + "once_cell", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick_cache" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d7c94f8935a9df96bb6380e8592c70edf497a643f94bd23b2f76b399385dbf4" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rust-playground" +version = "0.1.0" +dependencies = [ + "biter", + "color-eyre", + "ctrlc", + "derive_deref", + "fjall", + "rayon", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + +[[package]] +name = "rustix" +version = "0.38.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "secp256k1" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes", + "rand", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "self_cell" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" + +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "std-semaphore" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ae9eec00137a8eed469fb4148acd9fc6ac8c3f9b110f52cd34698c8b5bfa0e" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "value-log" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc2af068c21c0b0531624fbdb5b2c950cf8e7dc72cedf77a9ec10bb677450f" +dependencies = [ + "byteorder", + "log", + "min-max-heap", + "path-absolutize", + "quick_cache", + "rustc-hash", + "tempfile", + "xxhash-rust", +] + +[[package]] +name = "varint-rs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "xxhash-rust" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d48f1b18be023c95e7b75f481cac649d74be7c507ff4a407c55cfb957f7934" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.92", +] diff --git a/src/crates/barser/Cargo.toml b/src/crates/barser/Cargo.toml new file mode 100644 index 000000000..9902da560 --- /dev/null +++ b/src/crates/barser/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "barser" +version = "0.1.0" +edition = "2021" + +[dependencies] +biter = "0.2.2" +color-eyre = "0.6.3" +ctrlc = "3.4.5" +derive_deref = "1.1.1" +fjall = "2.4.4" +rayon = "1.10.0" diff --git a/src/crates/barser/src/databases/blockhash_prefix_to_height.rs b/src/crates/barser/src/databases/blockhash_prefix_to_height.rs new file mode 100644 index 000000000..40c83118b --- /dev/null +++ b/src/crates/barser/src/databases/blockhash_prefix_to_height.rs @@ -0,0 +1,35 @@ +use biter::bitcoin::BlockHash; +use color_eyre::eyre::eyre; +use derive_deref::{Deref, DerefMut}; + +use crate::structs::{Database, DatabaseTrait, Height, Version}; + +#[derive(Deref, DerefMut)] +pub struct BlockhashPrefixToHeight(Database); + +impl BlockhashPrefixToHeight { + pub fn import() -> color_eyre::Result { + Ok(Self(Database::import( + "blockhash_suffix_to_height", + Self::version(), + )?)) + } + + pub fn insert(&mut self, blockhash: &BlockHash, height: Height) -> color_eyre::Result<()> { + if let Some(_height) = self.fetch_update(blockhash[..8].into(), height.into(), height)? { + // dbg!(height, Height::from(other), hash); + return Err(eyre!("BlockhashSuffixToHeight: key collision")); + } + Ok(()) + } + + pub fn remove(&mut self, blockhash: &BlockHash) { + self.0.remove((&blockhash[..]).into()) + } +} + +impl DatabaseTrait for BlockhashPrefixToHeight { + fn version() -> Version { + Version::from(1) + } +} diff --git a/src/crates/barser/src/databases/height_to_blockhash.rs b/src/crates/barser/src/databases/height_to_blockhash.rs new file mode 100644 index 000000000..bce5882da --- /dev/null +++ b/src/crates/barser/src/databases/height_to_blockhash.rs @@ -0,0 +1,37 @@ +use biter::bitcoin::{hashes::Hash, BlockHash}; +use derive_deref::{Deref, DerefMut}; +use fjall::Slice; + +use crate::structs::{Database, DatabaseTrait, Height, Version}; + +#[derive(Deref, DerefMut)] +pub struct HeightToBlockhash(Database); + +impl HeightToBlockhash { + pub fn import() -> color_eyre::Result { + Ok(Self(Database::import( + "height_to_blockhash", + Self::version(), + )?)) + } + + pub fn insert(&mut self, height: Height, blockhash: &BlockHash) { + self.0.insert(height.into(), blockhash[..].into(), height) + } + + pub fn get(&self, height: Height) -> fjall::Result> { + self.0 + .get(Slice::from(height)) + .map(|opt| opt.map(|slice| BlockHash::from_slice(&slice).unwrap())) + } + + pub fn remove(&mut self, height: Height) { + self.0.remove(Slice::from(height)) + } +} + +impl DatabaseTrait for HeightToBlockhash { + fn version() -> Version { + Version::from(1) + } +} diff --git a/src/crates/barser/src/databases/height_to_txindex.rs b/src/crates/barser/src/databases/height_to_txindex.rs new file mode 100644 index 000000000..0cdeb0781 --- /dev/null +++ b/src/crates/barser/src/databases/height_to_txindex.rs @@ -0,0 +1,45 @@ +use derive_deref::{Deref, DerefMut}; +use fjall::Slice; + +use crate::structs::{Database, DatabaseTrait, Height, Txindex, Version}; + +#[derive(Deref, DerefMut)] +pub struct HeightToTxindex(Database); + +#[derive(Debug, PartialEq, Eq)] +pub enum HeightToTxindexPosition { + First, + Last, +} + +impl HeightToTxindex { + pub fn import(position: HeightToTxindexPosition) -> color_eyre::Result { + Ok(Self(Database::import( + &format!( + "height_to_{}_txindex", + format!("{position:?}").to_lowercase() + ), + Self::version(), + )?)) + } + + pub fn insert(&mut self, height: Height, txindex: Txindex) { + self.0.insert(height.into(), txindex.into(), height) + } + + pub fn get(&self, height: Height) -> fjall::Result> { + self.0 + .get(Slice::from(height)) + .map(|opt| opt.map(|slice| slice.into())) + } + + pub fn remove(&mut self, height: Height) { + self.0.remove(Slice::from(height)) + } +} + +impl DatabaseTrait for HeightToTxindex { + fn version() -> Version { + Version::from(1) + } +} diff --git a/src/crates/barser/src/databases/mod.rs b/src/crates/barser/src/databases/mod.rs new file mode 100644 index 000000000..fd9066db9 --- /dev/null +++ b/src/crates/barser/src/databases/mod.rs @@ -0,0 +1,167 @@ +use std::{ops::Sub, thread}; + +use biter::{ + bitcoin::{hashes::Hash, BlockHash, Txid}, + bitcoincore_rpc::Client, +}; +pub use blockhash_prefix_to_height::*; +use color_eyre::eyre::ContextCompat; +use fjall::Slice; + +mod blockhash_prefix_to_height; +mod height_to_blockhash; +mod height_to_txindex; +mod txid_prefix_to_txindex; +mod txindex_to_txid; +mod txoutindex_to_amount; + +pub use height_to_blockhash::*; +pub use height_to_txindex::*; +pub use txid_prefix_to_txindex::*; +pub use txindex_to_txid::*; +pub use txoutindex_to_amount::*; + +use crate::structs::{Height, Txindex, Txoutindex}; + +pub struct Databases { + pub blockhash_prefix_to_height: BlockhashPrefixToHeight, + pub height_to_blockhash: HeightToBlockhash, + pub height_to_first_txindex: HeightToTxindex, + pub height_to_last_txindex: HeightToTxindex, + pub txid_prefix_to_txindex: TxidPrefixToTxindex, + pub txindex_to_txid: TxindexToTxid, + pub txoutindex_to_amount: TxoutindexToAmount, +} + +const UNSAFE_BLOCKS: usize = 100; + +impl Databases { + pub fn import() -> color_eyre::Result { + thread::scope(|scope| { + let blockhash_prefix_to_height_handle = scope.spawn(BlockhashPrefixToHeight::import); + let height_to_blockhash_handle = scope.spawn(HeightToBlockhash::import); + let height_to_first_txindex_handle = + scope.spawn(|| HeightToTxindex::import(HeightToTxindexPosition::First)); + let height_to_last_txindex_handle = + scope.spawn(|| HeightToTxindex::import(HeightToTxindexPosition::Last)); + let txid_prefix_to_txindex_handle = scope.spawn(TxidPrefixToTxindex::import); + let txindex_to_txid_handle = scope.spawn(TxindexToTxid::import); + let txoutindex_to_amount_handle = scope.spawn(TxoutindexToAmount::import); + + Ok(Self { + blockhash_prefix_to_height: blockhash_prefix_to_height_handle.join().unwrap()?, + height_to_blockhash: height_to_blockhash_handle.join().unwrap()?, + height_to_first_txindex: height_to_first_txindex_handle.join().unwrap()?, + height_to_last_txindex: height_to_last_txindex_handle.join().unwrap()?, + txid_prefix_to_txindex: txid_prefix_to_txindex_handle.join().unwrap()?, + txindex_to_txid: txindex_to_txid_handle.join().unwrap()?, + txoutindex_to_amount: txoutindex_to_amount_handle.join().unwrap()?, + }) + }) + } + + pub fn export(&mut self, height: Height) -> color_eyre::Result<()> { + thread::scope(|scope| { + scope.spawn(|| self.blockhash_prefix_to_height.export(height).unwrap()); + scope.spawn(|| self.height_to_blockhash.export(height).unwrap()); + scope.spawn(|| self.height_to_first_txindex.export(height).unwrap()); + scope.spawn(|| self.height_to_last_txindex.export(height).unwrap()); + scope.spawn(|| self.txid_prefix_to_txindex.export(height).unwrap()); + scope.spawn(|| self.txindex_to_txid.export(height).unwrap()); + scope.spawn(|| self.txoutindex_to_amount.export(height).unwrap()); + }); + Ok(()) + } + + pub fn start_height(&self, rpc: &Client) -> color_eyre::Result { + let safe_height = Height::try_from(rpc)?.sub(UNSAFE_BLOCKS); + Ok(self + .min_height() + .map(|h| h.sub(UNSAFE_BLOCKS)) + .unwrap_or_default() + .min(safe_height)) + } + + fn min_height(&self) -> Option { + [ + self.blockhash_prefix_to_height.height(), + self.height_to_blockhash.height(), + self.height_to_first_txindex.height(), + self.height_to_last_txindex.height(), + self.txid_prefix_to_txindex.height(), + self.txindex_to_txid.height(), + self.txoutindex_to_amount.height(), + ] + .into_iter() + .map(ToOwned::to_owned) + .min() + .flatten() + } + + pub fn has_different_blockhash( + &self, + height: Height, + blockhash: &BlockHash, + ) -> fjall::Result { + Ok(self + .height_to_blockhash + .get(height)? + .is_some_and(|saved_blockhash| blockhash != &saved_blockhash)) + } + + pub fn erase_from(&mut self, height: Height) -> color_eyre::Result<()> { + let mut txindex = None; + + self.height_to_blockhash + .range(Slice::from(height)..) + .try_for_each(|slice| -> color_eyre::Result<()> { + let (slice_height, slice_blockhash) = slice?; + let height = Height::from(slice_height); + let blockhash = BlockHash::from_slice(&slice_blockhash)?; + + self.height_to_blockhash.remove(height); + self.blockhash_prefix_to_height.remove(&blockhash); + if txindex.is_none() { + txindex.replace( + self.height_to_first_txindex + .get(height)? + .context("for height to have first txindex")?, + ); + } + self.height_to_first_txindex.remove(height); + self.height_to_last_txindex.remove(height); + + Ok(()) + })?; + + let txindex = txindex.context("txindex to not be none by now")?; + + self.txindex_to_txid + .range(Slice::from(txindex)..) + .try_for_each(|slice| -> color_eyre::Result<()> { + let (slice_txindex, slice_txid) = slice?; + let txindex = Txindex::from(slice_txindex); + let txid = Txid::from_slice(&slice_txid)?; + + self.txindex_to_txid.remove(txindex); + self.txid_prefix_to_txindex.remove(&txid); + + Ok(()) + })?; + + let txoutindex = Txoutindex::from(txindex); + + self.txoutindex_to_amount + .range(Slice::from(txoutindex)..) + .try_for_each(|slice| -> color_eyre::Result<()> { + let (slice_txoutindex, _) = slice?; + let txoutindex = Txoutindex::from(slice_txoutindex); + + self.txoutindex_to_amount.remove(txoutindex); + + Ok(()) + })?; + + Ok(()) + } +} diff --git a/src/crates/barser/src/databases/txid_prefix_to_txindex.rs b/src/crates/barser/src/databases/txid_prefix_to_txindex.rs new file mode 100644 index 000000000..dfc1b6fab --- /dev/null +++ b/src/crates/barser/src/databases/txid_prefix_to_txindex.rs @@ -0,0 +1,46 @@ +use biter::bitcoin::Txid; +use color_eyre::eyre::eyre; +use derive_deref::{Deref, DerefMut}; +use fjall::Slice; + +use crate::structs::{Database, DatabaseTrait, Height, Txindex, Version}; + +#[derive(Deref, DerefMut)] +pub struct TxidPrefixToTxindex(Database); + +impl TxidPrefixToTxindex { + pub fn import() -> color_eyre::Result { + Ok(Self(Database::import( + "txid_prefix_to_txindex", + Self::version(), + )?)) + } + + pub fn insert( + &mut self, + txid: &Txid, + txindex: Txindex, + height: Height, + ) -> color_eyre::Result<()> { + if let Some(_txindex) = + self.fetch_update(Self::txid_to_key(txid), txindex.into(), height)? + { + return Err(eyre!("TxidPrefixToTxindex: key collision")); + } + Ok(()) + } + + pub fn remove(&mut self, txid: &Txid) { + self.0.remove(Self::txid_to_key(txid)) + } + + fn txid_to_key(txid: &Txid) -> Slice { + txid[0..8].into() + } +} + +impl DatabaseTrait for TxidPrefixToTxindex { + fn version() -> Version { + Version::from(1) + } +} diff --git a/src/crates/barser/src/databases/txindex_to_txid.rs b/src/crates/barser/src/databases/txindex_to_txid.rs new file mode 100644 index 000000000..9c913f98b --- /dev/null +++ b/src/crates/barser/src/databases/txindex_to_txid.rs @@ -0,0 +1,28 @@ +use biter::bitcoin::Txid; +use derive_deref::{Deref, DerefMut}; +use fjall::Slice; + +use crate::structs::{Database, DatabaseTrait, Height, Txindex, Version}; + +#[derive(Deref, DerefMut)] +pub struct TxindexToTxid(Database); + +impl TxindexToTxid { + pub fn import() -> color_eyre::Result { + Ok(Self(Database::import("txindex_to_txid", Self::version())?)) + } + + pub fn insert(&mut self, txindex: Txindex, txid: &Txid, height: Height) { + self.0.insert(txindex.into(), txid[..].into(), height) + } + + pub fn remove(&mut self, txindex: Txindex) { + self.0.remove(Slice::from(txindex)) + } +} + +impl DatabaseTrait for TxindexToTxid { + fn version() -> Version { + Version::from(1) + } +} diff --git a/src/crates/barser/src/databases/txoutindex_to_amount.rs b/src/crates/barser/src/databases/txoutindex_to_amount.rs new file mode 100644 index 000000000..7ac6de829 --- /dev/null +++ b/src/crates/barser/src/databases/txoutindex_to_amount.rs @@ -0,0 +1,30 @@ +use derive_deref::{Deref, DerefMut}; +use fjall::Slice; + +use crate::structs::{Amount, Database, DatabaseTrait, Height, Txoutindex, Version}; + +#[derive(Deref, DerefMut)] +pub struct TxoutindexToAmount(Database); + +impl TxoutindexToAmount { + pub fn import() -> color_eyre::Result { + Ok(Self(Database::import( + "txoutindex_to_amount", + Self::version(), + )?)) + } + + pub fn insert(&mut self, txoutindex: Txoutindex, amount: Amount, height: Height) { + self.0.insert(txoutindex.into(), amount.into(), height) + } + + pub fn remove(&mut self, txoutindex: Txoutindex) { + self.0.remove(Slice::from(txoutindex)) + } +} + +impl DatabaseTrait for TxoutindexToAmount { + fn version() -> Version { + Version::from(1) + } +} diff --git a/src/crates/barser/src/main.rs b/src/crates/barser/src/main.rs new file mode 100644 index 000000000..e3ce5399e --- /dev/null +++ b/src/crates/barser/src/main.rs @@ -0,0 +1,100 @@ +use std::path::Path; + +use biter::bitcoincore_rpc::{Auth, Client}; + +mod databases; +mod structs; + +use databases::Databases; +use structs::{Exit, Height, Txindex, Txoutindex}; + +// https://github.com/fjall-rs/fjall/discussions/72 +// https://github.com/romanz/electrs/blob/master/doc/schema.md + +const DAILY_BLOCK_TARGET: usize = 144; +const MONTHLY_BLOCK_TARGET: usize = DAILY_BLOCK_TARGET * 30; + +fn main() -> color_eyre::Result<()> { + let i = std::time::Instant::now(); + + let data_dir = Path::new("../bitcoin"); + let cookie = Path::new(data_dir).join(".cookie"); + let rpc = Client::new("http://localhost:8332", Auth::CookieFile(cookie)).unwrap(); + + let exit = Exit::new(); + + let mut dbs = Databases::import()?; + + let mut height = dbs.start_height(&rpc)?; + + let mut txindex = dbs + .height_to_last_txindex + .get(height)? + .unwrap_or(Txindex::default()); + + let export = |dbs: &mut Databases, height: Height| -> color_eyre::Result<()> { + exit.block(); + println!("Exporting..."); + dbs.export(height)?; + println!("Export done"); + exit.unblock(); + Ok(()) + }; + + biter::new(data_dir, Some(height.into()), None, rpc) + .iter() + .try_for_each(|(_height, block, blockhash)| -> color_eyre::Result<()> { + println!("Processing block {_height}..."); + + height = Height::from(_height); + + if dbs.has_different_blockhash(height, &blockhash)? { + dbs.erase_from(height)?; + } + + dbs.blockhash_prefix_to_height.insert(&blockhash, height)?; + dbs.height_to_blockhash.insert(height, &blockhash); + + let txlen = block.txdata.len(); + + block.txdata.into_iter().enumerate().try_for_each( + |(i, tx)| -> color_eyre::Result<()> { + if i == txlen - 1 { + dbs.height_to_last_txindex.insert(height, txindex); + } + + if !dbs.txindex_to_txid.is_safe(height) + || !dbs.txid_prefix_to_txindex.is_safe(height) + { + let txid = tx.compute_txid(); + dbs.txindex_to_txid.insert(txindex, &txid, height); + dbs.txid_prefix_to_txindex.insert(&txid, txindex, height)?; + } + + txindex.increment(); + + tx.output.into_iter().enumerate().for_each(|(vout, txout)| { + let vout = vout as u16; + let txoutindex = Txoutindex::from((txindex, vout)); + let amount = txout.value.into(); + dbs.txoutindex_to_amount.insert(txoutindex, amount, height); + }); + + Ok(()) + }, + )?; + + let should_snapshot = _height % MONTHLY_BLOCK_TARGET == 0 && !exit.active(); + if should_snapshot { + export(&mut dbs, height)?; + } + + Ok(()) + })?; + + export(&mut dbs, height)?; + + dbg!(i.elapsed()); + + Ok(()) +} diff --git a/src/crates/barser/src/structs/amount.rs b/src/crates/barser/src/structs/amount.rs new file mode 100644 index 000000000..d25acf47a --- /dev/null +++ b/src/crates/barser/src/structs/amount.rs @@ -0,0 +1,90 @@ +use std::{ + iter::Sum, + ops::{Add, AddAssign, Mul, Sub, SubAssign}, +}; + +use biter::bitcoin; +use derive_deref::{Deref, DerefMut}; + +use super::Height; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Deref, DerefMut, Default)] +pub struct Amount(bitcoin::Amount); + +impl Amount { + pub const ZERO: Self = Self(bitcoin::Amount::ZERO); + pub const ONE_BTC_F32: f32 = 100_000_000.0; + pub const ONE_BTC_F64: f64 = 100_000_000.0; +} + +impl From for Amount { + fn from(value: u64) -> Self { + Self(bitcoin::Amount::from_sat(value)) + } +} + +impl From for Amount { + fn from(value: bitcoin::Amount) -> Self { + Self(value) + } +} + +impl From for fjall::Slice { + fn from(value: Amount) -> Self { + value.to_sat().to_be_bytes().into() + } +} + +impl Add for Amount { + type Output = Amount; + fn add(self, rhs: Amount) -> Self::Output { + Amount::from(self.to_sat() + rhs.to_sat()) + } +} + +impl AddAssign for Amount { + fn add_assign(&mut self, rhs: Self) { + *self = Amount::from(self.to_sat() + rhs.to_sat()); + } +} + +impl Sub for Amount { + type Output = Amount; + fn sub(self, rhs: Amount) -> Self::Output { + Amount::from(self.to_sat() - rhs.to_sat()) + } +} + +impl SubAssign for Amount { + fn sub_assign(&mut self, rhs: Self) { + *self = Amount::from(self.to_sat() - rhs.to_sat()); + } +} + +impl Mul for Amount { + type Output = Amount; + fn mul(self, rhs: Amount) -> Self::Output { + Amount::from(self.to_sat() * rhs.to_sat()) + } +} + +impl Mul for Amount { + type Output = Amount; + fn mul(self, rhs: u64) -> Self::Output { + Amount::from(self.to_sat() * rhs) + } +} + +impl Mul for Amount { + type Output = Amount; + fn mul(self, rhs: Height) -> Self::Output { + Amount::from(self.to_sat() * *rhs as u64) + } +} + +impl Sum for Amount { + fn sum>(iter: I) -> Self { + let sats: u64 = iter.map(|amt| amt.to_sat()).sum(); + Amount::from(sats) + } +} diff --git a/src/crates/barser/src/structs/database.rs b/src/crates/barser/src/structs/database.rs new file mode 100644 index 000000000..f33aa304f --- /dev/null +++ b/src/crates/barser/src/structs/database.rs @@ -0,0 +1,138 @@ +use std::{mem, ops::RangeBounds}; + +use fjall::{ + Batch, Keyspace, KvPair, PartitionCreateOptions, PartitionHandle, PersistMode, Result, Slice, +}; + +use super::{Height, Version}; + +pub struct Database { + keyspace: Keyspace, + data: PartitionHandle, + meta: PartitionHandle, + batch: Batch, + height: Option, +} + +const VERSION: &str = "version"; +const HEIGHT: &str = "height"; + +impl Database { + pub fn import(name: &str, version: Version) -> Result { + let keyspace = fjall::Config::new(format!("./databases/{name}")).open()?; + + let data = Self::open_data(&keyspace)?; + let meta = Self::open_meta(&keyspace)?; + + let batch = keyspace.batch(); + + let mut this = Self { + height: meta.get(HEIGHT)?.map(Height::from), + keyspace, + data, + meta, + batch, + }; + + if let Some(slice) = this.meta.get(VERSION)? { + if version != Version::from(slice) { + this = this.reset()?; + } + } + + this.batch + .insert(&this.meta, VERSION, version.to_be_bytes()); + + Ok(this) + } + + fn open_data(keyspace: &Keyspace) -> Result { + keyspace.open_partition("data", Self::create_options()) + } + + fn open_meta(keyspace: &Keyspace) -> Result { + keyspace.open_partition("meta", Self::create_options()) + } + + fn create_options() -> PartitionCreateOptions { + PartitionCreateOptions::default().manual_journal_persist(true) + } + + pub fn get(&self, key: Slice) -> Result> { + self.data.get(key) + } + + pub fn range<'a, K: AsRef<[u8]> + 'a, R: RangeBounds + 'a>( + &'a self, + range: R, + ) -> impl DoubleEndedIterator> + 'static { + self.data.range(range) + } + + pub fn insert(&mut self, key: Slice, value: Slice, height: Height) { + if self.is_safe(height) { + return; + } + self.batch.insert(&self.data, key, value); + } + + pub fn fetch_update( + &mut self, + key: Slice, + value: Slice, + height: Height, + ) -> Result> { + if self.is_safe(height) { + return Ok(None); + } + let prev = self.get(key.clone()); + self.batch.insert(&self.data, key, value); + prev + } + + pub fn remove(&mut self, key: Slice) { + self.batch.remove(&self.data, key); + } + + pub fn is_safe(&self, height: Height) -> bool { + self.height.is_some_and(|self_height| self_height >= height) + } + + fn persist(&self) -> Result<()> { + self.keyspace.persist(PersistMode::SyncAll) + } + + pub fn export(&mut self, height: Height) -> Result<()> { + let mut batch = self.keyspace.batch(); + mem::swap(&mut batch, &mut self.batch); + + batch.insert(&self.meta, HEIGHT, height.to_be_bytes()); + + batch.commit()?; + + self.persist() + } + + fn reset(mut self) -> Result { + self.keyspace.delete_partition(self.data)?; + self.keyspace.delete_partition(self.meta)?; + + self.keyspace.persist(PersistMode::SyncAll)?; + + self.data = Self::open_data(&self.keyspace)?; + self.meta = Self::open_meta(&self.keyspace)?; + + Ok(self) + } + + pub fn height(&self) -> &Option { + &self.height + } +} + +pub trait DatabaseTrait +where + Self: Sized, +{ + fn version() -> Version; +} diff --git a/src/crates/barser/src/structs/exit.rs b/src/crates/barser/src/structs/exit.rs new file mode 100644 index 000000000..d206f5b07 --- /dev/null +++ b/src/crates/barser/src/structs/exit.rs @@ -0,0 +1,60 @@ +use std::{ + process::exit, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread::sleep, + time::Duration, +}; + +#[derive(Default, Clone)] +pub struct Exit { + blocked: Arc, + active: Arc, +} + +impl Exit { + pub fn new() -> Self { + let s = Self { + active: Arc::new(AtomicBool::new(false)), + blocked: Arc::new(AtomicBool::new(false)), + }; + + let active = s.active.clone(); + + let _blocked = s.blocked.clone(); + let blocked = move || _blocked.load(Ordering::SeqCst); + + ctrlc::set_handler(move || { + println!("Exitting..."); + + active.store(true, Ordering::SeqCst); + + if blocked() { + println!("Waiting to exit safely"); + + while blocked() { + sleep(Duration::from_millis(50)); + } + } + + exit(0); + }) + .expect("Error setting Ctrl-C handler"); + + s + } + + pub fn block(&self) { + self.blocked.store(true, Ordering::SeqCst); + } + + pub fn unblock(&self) { + self.blocked.store(false, Ordering::SeqCst); + } + + pub fn active(&self) -> bool { + self.active.load(Ordering::SeqCst) + } +} diff --git a/src/crates/barser/src/structs/height.rs b/src/crates/barser/src/structs/height.rs new file mode 100644 index 000000000..d39992459 --- /dev/null +++ b/src/crates/barser/src/structs/height.rs @@ -0,0 +1,110 @@ +use std::{ + fmt, + ops::{Add, AddAssign, Sub}, +}; + +use biter::bitcoincore_rpc::{self, RpcApi}; +use derive_deref::{Deref, DerefMut}; + +use super::SliceExtended; + +#[derive(Debug, Clone, Copy, Deref, DerefMut, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct Height(u32); + +impl From for Height { + fn from(slice: fjall::Slice) -> Self { + Self(slice.read_u32()) + } +} +impl From for fjall::Slice { + fn from(value: Height) -> Self { + value.to_be_bytes().into() + } +} + +impl From for Height { + fn from(value: u32) -> Self { + Self(value) + } +} + +impl From for Height { + fn from(value: usize) -> Self { + Self(value as u32) + } +} +impl From for usize { + fn from(value: Height) -> Self { + value.0 as usize + } +} + +impl TryFrom<&bitcoincore_rpc::Client> for Height { + type Error = bitcoincore_rpc::Error; + fn try_from(value: &bitcoincore_rpc::Client) -> Result { + Ok((value.get_blockchain_info()?.blocks as usize - 1).into()) + } +} + +impl PartialEq for Height { + fn eq(&self, other: &u64) -> bool { + **self == *other as u32 + } +} + +impl Add for Height { + type Output = Height; + + fn add(self, rhs: u32) -> Self::Output { + Self::from(*self + rhs) + } +} + +impl Add for Height { + type Output = Height; + + fn add(self, rhs: usize) -> Self::Output { + Self::from(*self + rhs as u32) + } +} + +impl Sub for Height { + type Output = Height; + + fn sub(self, rhs: Height) -> Self::Output { + Self::from(*self - *rhs) + } +} + +impl Sub for Height { + type Output = Height; + fn sub(self, rhs: i32) -> Self::Output { + Self::from(*self - rhs as u32) + } +} + +impl Sub for Height { + type Output = Height; + fn sub(self, rhs: u32) -> Self::Output { + Self::from(*self - rhs) + } +} + +impl Sub for Height { + type Output = Height; + fn sub(self, rhs: usize) -> Self::Output { + Self::from(*self - rhs as u32) + } +} + +impl AddAssign for Height { + fn add_assign(&mut self, rhs: usize) { + *self = self.add(rhs); + } +} + +impl fmt::Display for Height { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", **self) + } +} diff --git a/src/crates/barser/src/structs/mod.rs b/src/crates/barser/src/structs/mod.rs new file mode 100644 index 000000000..574b6655a --- /dev/null +++ b/src/crates/barser/src/structs/mod.rs @@ -0,0 +1,17 @@ +mod amount; +mod database; +mod exit; +mod height; +mod slice; +mod txindex; +mod txoutindex; +mod version; + +pub use amount::*; +pub use database::*; +pub use exit::*; +pub use height::*; +pub use slice::*; +pub use txindex::*; +pub use txoutindex::*; +pub use version::*; diff --git a/src/crates/barser/src/structs/slice.rs b/src/crates/barser/src/structs/slice.rs new file mode 100644 index 000000000..2602f8bd5 --- /dev/null +++ b/src/crates/barser/src/structs/slice.rs @@ -0,0 +1,34 @@ +use std::io::Read; + +pub trait SliceExtended { + fn read_u8(&self) -> u8; + fn read_u32(&self) -> u32; + fn read_u64(&self) -> u64; + fn read_exact(&self, buf: &mut [u8]); +} + +impl SliceExtended for fjall::Slice { + fn read_u8(&self) -> u8 { + let mut buf: [u8; 1] = [0; 1]; + self.read_exact(&mut buf); + u8::from_be_bytes(buf) + } + + fn read_u32(&self) -> u32 { + let mut buf: [u8; 4] = [0; 4]; + self.read_exact(&mut buf); + u32::from_be_bytes(buf) + } + + fn read_u64(&self) -> u64 { + let mut buf: [u8; 8] = [0; 8]; + self.read_exact(&mut buf); + u64::from_be_bytes(buf) + } + + fn read_exact(&self, buf: &mut [u8]) { + self.bytes().take(buf.len()).enumerate().for_each(|(i, r)| { + buf[i] = r.unwrap(); + }); + } +} diff --git a/src/crates/barser/src/structs/txindex.rs b/src/crates/barser/src/structs/txindex.rs new file mode 100644 index 000000000..45d02e751 --- /dev/null +++ b/src/crates/barser/src/structs/txindex.rs @@ -0,0 +1,44 @@ +use derive_deref::{Deref, DerefMut}; + +use super::SliceExtended; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Deref, DerefMut, Default)] +pub struct Txindex(u32); + +impl Txindex { + pub fn increment(&mut self) { + self.0 += 1; + } + + pub fn incremented(self) -> Self { + Self(*self + 1) + } +} + +impl From for Txindex { + fn from(value: u32) -> Self { + Self(value) + } +} + +impl From for Txindex { + fn from(value: u64) -> Self { + Self(value as u32) + } +} +impl From for u64 { + fn from(value: Txindex) -> Self { + value.0 as u64 + } +} + +impl From for Txindex { + fn from(slice: fjall::Slice) -> Self { + Self(slice.read_u32()) + } +} +impl From for fjall::Slice { + fn from(value: Txindex) -> Self { + value.to_be_bytes().into() + } +} diff --git a/src/crates/barser/src/structs/txoutindex.rs b/src/crates/barser/src/structs/txoutindex.rs new file mode 100644 index 000000000..ab05801ad --- /dev/null +++ b/src/crates/barser/src/structs/txoutindex.rs @@ -0,0 +1,53 @@ +use super::{SliceExtended, Txindex}; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)] +pub struct Txoutindex { + pub txindex: Txindex, + pub vout: u16, +} + +const SHIFT: u64 = 16; +const AND: u64 = (1 << SHIFT) - 1; + +impl From for Txoutindex { + fn from(value: Txindex) -> Self { + Self { + txindex: value, + vout: 0, + } + } +} + +impl From<(Txindex, u16)> for Txoutindex { + fn from(value: (Txindex, u16)) -> Self { + Self { + txindex: value.0, + vout: value.1, + } + } +} + +impl From for Txoutindex { + fn from(value: u64) -> Self { + Self { + txindex: (value >> SHIFT).into(), + vout: (value & AND) as u16, + } + } +} +impl From for u64 { + fn from(value: Txoutindex) -> Self { + (u64::from(value.txindex) << SHIFT) + value.vout as u64 + } +} + +impl From for fjall::Slice { + fn from(value: Txoutindex) -> Self { + u64::from(value).to_be_bytes().into() + } +} +impl From for Txoutindex { + fn from(value: fjall::Slice) -> Self { + fjall::Slice::read_u64(&value).into() + } +} diff --git a/src/crates/barser/src/structs/version.rs b/src/crates/barser/src/structs/version.rs new file mode 100644 index 000000000..4c0dfe27e --- /dev/null +++ b/src/crates/barser/src/structs/version.rs @@ -0,0 +1,18 @@ +use derive_deref::{Deref, DerefMut}; + +use super::SliceExtended; + +#[derive(Debug, Clone, Copy, Deref, DerefMut, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version(u8); + +impl From for Version { + fn from(value: u8) -> Self { + Self(value) + } +} + +impl From for Version { + fn from(slice: fjall::Slice) -> Self { + Self(slice.read_u8()) + } +}