mirror of
https://github.com/romanz/electrs.git
synced 2024-11-19 01:43:29 +01:00
merge upstream for supporting testnet4
This commit is contained in:
commit
3c40771e7f
316
Cargo.lock
generated
316
Cargo.lock
generated
@ -13,9 +13,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.76"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355"
|
||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
@ -29,6 +35,16 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[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"
|
||||
@ -37,9 +53,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.10.0-beta"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea"
|
||||
checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
@ -63,12 +79,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin"
|
||||
version = "0.31.1"
|
||||
version = "0.32.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd00f3c09b5f21fb357abe32d29946eb8bb7a0862bae62c0b5e4a692acbbe73c"
|
||||
checksum = "788902099d47c8682efe6a7afb01c8d58b9794ba66c06affd81c3d6b560743eb"
|
||||
dependencies = [
|
||||
"base58ck",
|
||||
"bech32",
|
||||
"bitcoin-internals",
|
||||
"bitcoin-io",
|
||||
"bitcoin-units",
|
||||
"bitcoin_hashes",
|
||||
"hex-conservative",
|
||||
"hex_lit",
|
||||
@ -78,13 +97,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-internals"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb"
|
||||
checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-io"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-test-data"
|
||||
version = "0.2.0"
|
||||
@ -92,21 +117,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c188654f9dce3bc6ce1bfa9c49777ad514bcad37e421b5f53e9d0ee10603f34"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.13.0"
|
||||
name = "bitcoin-units"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b"
|
||||
checksum = "cb54da0b28892f3c52203a7191534033e051b6f4b52bc15480681b57b7e036f5"
|
||||
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 = "bitcoin_slices"
|
||||
version = "0.7.0"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b221249ba4685e0f737f0df2c7bb656d527fdd8ede83ac066c4c8ce95898f42"
|
||||
checksum = "b0c2d2aa6c95757d94701123e5da8392fef1a4b8462564045d9309a8e11b0d22"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoin_hashes",
|
||||
@ -115,9 +150,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitcoincore-rpc"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eb70725a621848c83b3809913d5314c0d20ca84877d99dd909504b564edab00"
|
||||
checksum = "aedd23ae0fd321affb4bbbc36126c6f49a32818dc6b979395d24da8c9d4e80ee"
|
||||
dependencies = [
|
||||
"bitcoincore-rpc-json",
|
||||
"jsonrpc",
|
||||
@ -128,9 +163,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitcoincore-rpc-json"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "856ffbee2e492c23bca715d72ea34aae80d58400f2bda26a82015d6bc2ec3662"
|
||||
checksum = "d8909583c5fab98508e80ef73e5592a651c954993dc6b7739963257d19f0e71a"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"serde",
|
||||
@ -177,12 +212,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo_toml"
|
||||
version = "0.12.4"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a621d5d6d6c8d086dbaf1fe659981da41a1b63c6bdbba30b4dbb592c6d3bd49"
|
||||
checksum = "1521c5948ab432e084eabee0c9e4e965483f73156eaa0b04fc192e3f61205438"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"toml",
|
||||
"toml 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -236,20 +271,20 @@ dependencies = [
|
||||
"parse_arg",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"toml",
|
||||
"toml 0.5.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "configure_me_codegen"
|
||||
version = "0.4.4"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad4bfdee5b1410b1d3b4239172e6f4573d2d47a14a11cd397dac083233dbe3e3"
|
||||
checksum = "5e56840275667a19b0e8ab80219c81fb0bd924e567366d9f12aa385fb45511ea"
|
||||
dependencies = [
|
||||
"cargo_toml",
|
||||
"fmt2io",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"toml",
|
||||
"toml 0.5.11",
|
||||
"unicode-segmentation",
|
||||
"void",
|
||||
]
|
||||
@ -265,9 +300,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.11"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
|
||||
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@ -353,7 +388,7 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "electrs"
|
||||
version = "0.10.2"
|
||||
version = "0.10.7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitcoin",
|
||||
@ -429,15 +464,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||
|
||||
[[package]]
|
||||
name = "fmt2io"
|
||||
version = "0.1.0"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9db8691f0820ad11ce6eb94057d0dd9c456500da04da0c12a85c90d6f979cc9"
|
||||
checksum = "6b6129284da9f7e5296cc22183a63f24300e945e297705dcc0672f7df01d62c8"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
@ -472,6 +507,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.3"
|
||||
@ -486,9 +527,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-conservative"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2"
|
||||
checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex_lit"
|
||||
@ -508,6 +552,16 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.11"
|
||||
@ -526,7 +580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix 0.38.28",
|
||||
"rustix 0.38.37",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -547,11 +601,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc"
|
||||
version = "0.14.1"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8128f36b47411cd3f044be8c1f5cc0c9e24d1d1bfdc45f0a57897b32513053f2"
|
||||
checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"minreq",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@ -570,9 +625,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.151"
|
||||
version = "0.2.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -614,9 +669,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.12"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@ -630,9 +685,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
@ -655,6 +710,17 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "minreq"
|
||||
version = "2.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fdef521c74c2884a4f3570bcdb6d2a77b3c533feb6b27ac2ae72673cc221c64"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@ -665,6 +731,21 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom8"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@ -798,9 +879,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.8.1"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
@ -887,14 +968,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.28"
|
||||
version = "0.38.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
||||
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.12",
|
||||
"linux-raw-sys 0.4.14",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@ -912,9 +993,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5"
|
||||
checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3"
|
||||
dependencies = [
|
||||
"bitcoin_hashes",
|
||||
"rand",
|
||||
@ -924,9 +1005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1-sys"
|
||||
version = "0.9.1"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dd97a086ec737e30053fd5c46f097465d25bb81dd3608825f65298c4c98be83"
|
||||
checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
@ -962,6 +1043,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
@ -1000,9 +1090,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.2"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
@ -1028,40 +1118,40 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.9.0"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.52.0",
|
||||
"once_cell",
|
||||
"rustix 0.38.37",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.51"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
|
||||
checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.51"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
|
||||
checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1089,6 +1179,40 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "772c1426ab886e7362aedf4abc9c0d1348a979517efedfc25862944d10137af0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90a238ee2e6ede22fb95350acc78e21dc40da00bb66c0334bde83de4ed89424e"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nom8",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
@ -1186,7 +1310,16 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1221,17 +1354,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1248,9 +1382,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
@ -1266,9 +1400,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
@ -1284,9 +1418,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
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"
|
||||
@ -1302,9 +1442,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
@ -1320,9 +1460,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
@ -1338,9 +1478,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
@ -1356,9 +1496,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
|
17
Cargo.toml
17
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "electrs"
|
||||
version = "0.10.2"
|
||||
version = "0.10.7"
|
||||
authors = ["Roman Zeyde <me@romanzey.de>"]
|
||||
description = "An efficient re-implementation of Electrum Server in Rust"
|
||||
license = "MIT"
|
||||
@ -22,9 +22,9 @@ spec = "internal/config_specification.toml"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bitcoin = { version = "0.31.1", features = ["serde", "rand-std"] }
|
||||
bitcoin_slices = { version = "0.7", features = ["bitcoin", "sha2"] }
|
||||
bitcoincore-rpc = { version = "0.18" }
|
||||
bitcoin = { version = "0.32.4", features = ["serde", "rand-std"] }
|
||||
bitcoin_slices = { version = "0.9", features = ["bitcoin", "sha2"] }
|
||||
bitcoincore-rpc = { version = "0.19.0" }
|
||||
configure_me = "0.4"
|
||||
crossbeam-channel = "0.5"
|
||||
dirs-next = "2.0"
|
||||
@ -32,7 +32,7 @@ env_logger = "0.10"
|
||||
log = "0.4"
|
||||
parking_lot = "0.12"
|
||||
prometheus = { version = "0.13", optional = true }
|
||||
rayon = "1.8"
|
||||
rayon = "1.9"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0, <=1.0.171" # avoid precompiled binaries (https://github.com/serde-rs/serde/issues/2538)
|
||||
serde_json = "1.0"
|
||||
@ -48,9 +48,12 @@ default-features = false
|
||||
features = ["zstd", "snappy"]
|
||||
|
||||
[build-dependencies]
|
||||
configure_me_codegen = { version = "0.4.4", default-features = false }
|
||||
configure_me_codegen = { version = "0.4.8", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
bitcoin-test-data = "0.2.0"
|
||||
hex_lit = "0.1.1"
|
||||
tempfile = "3.9"
|
||||
tempfile = "3.13"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
@ -2,12 +2,12 @@
|
||||
# The maintainers of electrs are not deeply familiar with Docker, so you should DYOR.
|
||||
# If you are not familiar with Docker either it's probably be safer to NOT use it.
|
||||
|
||||
FROM debian:bookworm-slim as base
|
||||
FROM debian:bookworm-slim AS base
|
||||
RUN apt-get update -qqy
|
||||
RUN apt-get install -qqy librocksdb-dev curl
|
||||
|
||||
### Electrum Rust Server ###
|
||||
FROM base as electrs-build
|
||||
FROM base AS electrs-build
|
||||
RUN apt-get install -qqy cargo clang cmake
|
||||
|
||||
# Install electrs
|
||||
@ -17,7 +17,7 @@ ENV ROCKSDB_INCLUDE_DIR=/usr/include
|
||||
ENV ROCKSDB_LIB_DIR=/usr/lib
|
||||
RUN cargo install --locked --path .
|
||||
|
||||
FROM base as result
|
||||
FROM base AS result
|
||||
# Copy the binaries
|
||||
COPY --from=electrs-build /root/.cargo/bin/electrs /usr/bin/electrs
|
||||
|
||||
|
@ -22,7 +22,7 @@ FROM base as bitcoin-build
|
||||
# Download
|
||||
WORKDIR /build/bitcoin
|
||||
ARG ARCH=x86_64
|
||||
ARG BITCOIND_VERSION=26.0
|
||||
ARG BITCOIND_VERSION=28.0
|
||||
RUN wget -q https://bitcoincore.org/bin/bitcoin-core-$BITCOIND_VERSION/bitcoin-$BITCOIND_VERSION-$ARCH-linux-gnu.tar.gz
|
||||
RUN tar xvf bitcoin-$BITCOIND_VERSION-$ARCH-linux-gnu.tar.gz
|
||||
RUN mv -v bitcoin-$BITCOIND_VERSION/bin/bitcoind .
|
||||
@ -40,7 +40,7 @@ WORKDIR /build/
|
||||
RUN apt-get install -qqy git libsecp256k1-1 python3-cryptography python3-setuptools python3-venv python3-pip jq curl
|
||||
RUN git clone --recurse-submodules https://github.com/spesmilo/electrum/ && cd electrum/ && git log -1
|
||||
RUN python3 -m venv --system-site-packages venv && \
|
||||
venv/bin/pip install -e electrum/ && \
|
||||
ELECTRUM_ECC_DONT_COMPILE=1 venv/bin/pip install -e electrum/ && \
|
||||
ln /build/venv/bin/electrum /usr/bin/electrum
|
||||
|
||||
RUN electrum version --offline
|
||||
|
@ -16,6 +16,8 @@ allowing the user to keep real-time track of balances and transaction history us
|
||||
Since it runs on the user's own machine, there is no need for the wallet to communicate with external Electrum servers,
|
||||
thus preserving the privacy of the user's addresses and balances.
|
||||
|
||||
[BTC Prague 2024 dev/hack/day](https://btcprague.com/dev-hack-day/) slides are here: https://bit.ly/electrs
|
||||
|
||||
## Usage
|
||||
|
||||
**Please prefer to use OUR usage guide!**
|
||||
|
@ -1,3 +1,33 @@
|
||||
# 0.10.7 (Nov 05 2024)
|
||||
|
||||
* Support testnet4
|
||||
* Enable LTO in release build
|
||||
* Don't sync mempool when bitcoind mempool is not yet loaded
|
||||
* Update dependencies (`bitcoin`, `bitcoin_slices`)
|
||||
|
||||
# 0.10.6 (Sep 29 2024)
|
||||
|
||||
* Update dependencies (`bitcoin`, `configure_me_codegen`, `crossbeam-channel`, `log`)
|
||||
* Deprecate unused config option `timestamp`
|
||||
* Don't fail if bitcoind fee estimation is disabled
|
||||
* Save on allocations by using fixed size types for database rows
|
||||
* Add BTC Prague 2024 dev/hack/day slides
|
||||
|
||||
# 0.10.5 (May 18 2024)
|
||||
|
||||
* Update dependencies (`bitcoin`, `bitcoin_slices`, `bitcoincore-rpc`, `rayon`)
|
||||
* Support latest bitcoind (https://github.com/rust-bitcoin/rust-bitcoincore-rpc/pull/353 & https://github.com/rust-bitcoin/rust-bitcoincore-rpc/pull/356)
|
||||
|
||||
# 0.10.4 (Mar 15 2024)
|
||||
|
||||
* Don't fail mempool sync on missing transactions (#997)
|
||||
* Update dependencies (`anyhow`, `crossbeam-channel`, `log`, `secp256k1`, `secp256k1-sys`, `smallvec`, `tempfile`, `termcolor`, `thiserror`, `thiserror-impl`)
|
||||
|
||||
# 0.10.3 (Feb 10 2024)
|
||||
|
||||
* Update dependencies (`serde_json`, `tempfile`, `env_logger`, `rayon`, `bitcoin`, `crossbeam-channel`, `shlex`)
|
||||
* Fix build on Debian 12 (#1001)
|
||||
|
||||
# 0.10.2 (Dec 31 2023)
|
||||
|
||||
* Use batched RPC to fetch mempool entries & transactions (#979)
|
||||
|
@ -206,6 +206,11 @@ Relevant issues: [#134](https://github.com/romanz/electrs/issues/134) and [#391]
|
||||
|
||||
#### Dynamic linking
|
||||
|
||||
Note that if you have previously done a static linking build, it is recommended to clean the build artifacts to avoid build errors (e.g. https://github.com/romanz/electrs/issues/1001):
|
||||
```
|
||||
$ cargo clean
|
||||
```
|
||||
|
||||
```
|
||||
$ ROCKSDB_INCLUDE_DIR=/usr/include ROCKSDB_LIB_DIR=/usr/lib cargo build --locked --release
|
||||
```
|
||||
|
@ -2,7 +2,7 @@ use anyhow::{Context, Result};
|
||||
use electrs_rocksdb::{ColumnFamilyDescriptor, IteratorMode, Options, DB};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let path = std::env::args().skip(1).next().context("missing DB path")?;
|
||||
let path = std::env::args().nth(1).context("missing DB path")?;
|
||||
let cf_names = DB::list_cf(&Options::default(), &path)?;
|
||||
let cfs: Vec<_> = cf_names
|
||||
.iter()
|
||||
|
@ -58,7 +58,7 @@ doc = "JSONRPC authentication cookie file (default: ~/.bitcoin/.cookie)"
|
||||
name = "network"
|
||||
type = "crate::config::BitcoinNetwork"
|
||||
convert_into = "::bitcoin::Network"
|
||||
doc = "Select Bitcoin network type ('bitcoin', 'testnet', 'regtest' or 'signet')"
|
||||
doc = "Select Bitcoin network type ('bitcoin', 'testnet', 'testnet4', 'regtest' or 'signet')"
|
||||
default = "Default::default()"
|
||||
|
||||
[[param]]
|
||||
|
14
src/chain.rs
14
src/chain.rs
@ -57,11 +57,11 @@ impl Chain {
|
||||
}
|
||||
|
||||
/// Load the chain from a collection of headers, up to the given tip
|
||||
pub(crate) fn load(&mut self, headers: Vec<BlockHeader>, tip: BlockHash) {
|
||||
pub(crate) fn load(&mut self, headers: impl Iterator<Item = BlockHeader>, tip: BlockHash) {
|
||||
let genesis_hash = self.headers[0].0;
|
||||
|
||||
let header_map: HashMap<BlockHash, BlockHeader> =
|
||||
headers.into_iter().map(|h| (h.block_hash(), h)).collect();
|
||||
headers.map(|h| (h.block_hash(), h)).collect();
|
||||
let mut blockhash = tip;
|
||||
let mut new_headers: Vec<&BlockHeader> = Vec::with_capacity(header_map.len());
|
||||
while blockhash != genesis_hash {
|
||||
@ -202,7 +202,10 @@ hex!("000000200030d7f9c11ef35b89a0eefb9a5e449909339b5e7854d99804ea8d6a49bf900a03
|
||||
|
||||
// test loading from a list of headers and tip
|
||||
let mut regtest = Chain::new(Regtest);
|
||||
regtest.load(headers.clone(), headers.last().unwrap().block_hash());
|
||||
regtest.load(
|
||||
headers.iter().copied(),
|
||||
headers.last().unwrap().block_hash(),
|
||||
);
|
||||
assert_eq!(regtest.height(), headers.len());
|
||||
|
||||
// test getters
|
||||
@ -239,7 +242,10 @@ hex!("000000200030d7f9c11ef35b89a0eefb9a5e449909339b5e7854d99804ea8d6a49bf900a03
|
||||
|
||||
// test reorg
|
||||
let mut regtest = Chain::new(Regtest);
|
||||
regtest.load(headers.clone(), headers.last().unwrap().block_hash());
|
||||
regtest.load(
|
||||
headers.iter().copied(),
|
||||
headers.last().unwrap().block_hash(),
|
||||
);
|
||||
let height = regtest.height();
|
||||
|
||||
let new_header: BlockHeader = deserialize(&hex!("000000200030d7f9c11ef35b89a0eefb9a5e449909339b5e7854d99804ea8d6a49bf900a0304d2e55fe0b6415949cff9bca0f88c0717884a5e5797509f89f856af93624a7a6bcc60ffff7f2000000000")).unwrap();
|
||||
|
@ -111,7 +111,10 @@ impl FromStr for BitcoinNetwork {
|
||||
|
||||
impl ::configure_me::parse_arg::ParseArgFromStr for BitcoinNetwork {
|
||||
fn describe_type<W: fmt::Write>(mut writer: W) -> fmt::Result {
|
||||
write!(writer, "either 'bitcoin', 'testnet', 'regtest' or 'signet'")
|
||||
write!(
|
||||
writer,
|
||||
"either 'bitcoin', 'testnet', 'testnet4', 'regtest' or 'signet'"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +131,6 @@ pub struct Config {
|
||||
pub network: Network,
|
||||
pub db_path: PathBuf,
|
||||
pub db_log_dir: Option<PathBuf>,
|
||||
pub daemon_dir: PathBuf,
|
||||
pub daemon_auth: SensitiveAuth,
|
||||
pub daemon_rpc_addr: SocketAddr,
|
||||
pub daemon_p2p_addr: SocketAddr,
|
||||
@ -146,7 +148,6 @@ pub struct Config {
|
||||
pub disable_electrum_rpc: bool,
|
||||
pub server_banner: String,
|
||||
pub signet_magic: Magic,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct SensitiveAuth(pub Auth);
|
||||
@ -183,7 +184,7 @@ fn default_daemon_dir() -> PathBuf {
|
||||
fn default_config_files() -> Vec<OsString> {
|
||||
let mut files = vec![OsString::from("electrs.toml")]; // cwd
|
||||
if let Some(mut path) = home_dir() {
|
||||
path.extend(&[".electrs", "config.toml"]);
|
||||
path.extend([".electrs", "config.toml"]);
|
||||
files.push(OsString::from(path)) // home directory
|
||||
}
|
||||
files.push(OsString::from("/etc/electrs/config.toml")); // system-wide
|
||||
@ -195,7 +196,7 @@ impl Config {
|
||||
pub fn from_args() -> Config {
|
||||
use internal::ResultExt;
|
||||
|
||||
let (mut config, args) =
|
||||
let (mut config, _args) =
|
||||
internal::Config::including_optional_config_files(default_config_files())
|
||||
.unwrap_or_exit();
|
||||
|
||||
@ -207,6 +208,7 @@ impl Config {
|
||||
let db_subdir = match config.network {
|
||||
Network::Bitcoin => "bitcoin",
|
||||
Network::Testnet => "testnet",
|
||||
Network::Testnet4 => "testnet4",
|
||||
Network::Regtest => "regtest",
|
||||
Network::Signet => "signet",
|
||||
unsupported => unsupported_network(unsupported),
|
||||
@ -217,6 +219,7 @@ impl Config {
|
||||
let default_daemon_rpc_port = match config.network {
|
||||
Network::Bitcoin => 8332,
|
||||
Network::Testnet => 18332,
|
||||
Network::Testnet4 => 48332,
|
||||
Network::Regtest => 18443,
|
||||
Network::Signet => 38332,
|
||||
unsupported => unsupported_network(unsupported),
|
||||
@ -224,6 +227,7 @@ impl Config {
|
||||
let default_daemon_p2p_port = match config.network {
|
||||
Network::Bitcoin => 8333,
|
||||
Network::Testnet => 18333,
|
||||
Network::Testnet4 => 48333,
|
||||
Network::Regtest => 18444,
|
||||
Network::Signet => 38333,
|
||||
unsupported => unsupported_network(unsupported),
|
||||
@ -231,6 +235,7 @@ impl Config {
|
||||
let default_electrum_port = match config.network {
|
||||
Network::Bitcoin => 50001,
|
||||
Network::Testnet => 60001,
|
||||
Network::Testnet4 => 40001,
|
||||
Network::Regtest => 60401,
|
||||
Network::Signet => 60601,
|
||||
unsupported => unsupported_network(unsupported),
|
||||
@ -238,6 +243,7 @@ impl Config {
|
||||
let default_monitoring_port = match config.network {
|
||||
Network::Bitcoin => 4224,
|
||||
Network::Testnet => 14224,
|
||||
Network::Testnet4 => 44224,
|
||||
Network::Regtest => 24224,
|
||||
Network::Signet => 34224,
|
||||
unsupported => unsupported_network(unsupported),
|
||||
@ -285,11 +291,31 @@ impl Config {
|
||||
match config.network {
|
||||
Network::Bitcoin => (),
|
||||
Network::Testnet => config.daemon_dir.push("testnet3"),
|
||||
Network::Testnet4 => config.daemon_dir.push("testnet4"),
|
||||
Network::Regtest => config.daemon_dir.push("regtest"),
|
||||
Network::Signet => config.daemon_dir.push("signet"),
|
||||
unsupported => unsupported_network(unsupported),
|
||||
}
|
||||
|
||||
let mut deprecated_options_used = false;
|
||||
|
||||
if config.timestamp {
|
||||
eprintln!(
|
||||
"Error: `timestamp` is deprecated, timestamps on logs is (and was) always \
|
||||
enabled, please remove this option."
|
||||
);
|
||||
deprecated_options_used = true;
|
||||
}
|
||||
|
||||
if config.verbose > 0 {
|
||||
eprintln!("Error: please use `log_filters` to set logging verbosity",);
|
||||
deprecated_options_used = true;
|
||||
}
|
||||
|
||||
if deprecated_options_used {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let daemon_dir = &config.daemon_dir;
|
||||
let daemon_auth = SensitiveAuth(match (config.auth, config.cookie_file) {
|
||||
(None, None) => Auth::CookieFile(daemon_dir.join(".cookie")),
|
||||
@ -308,10 +334,6 @@ impl Config {
|
||||
}
|
||||
});
|
||||
|
||||
if config.verbose > 0 {
|
||||
eprintln!("Error: please use `log_filters` to set logging verbosity",);
|
||||
std::process::exit(1);
|
||||
}
|
||||
let log_filters = config.log_filters;
|
||||
|
||||
let index_lookup_limit = match config.index_lookup_limit {
|
||||
@ -336,7 +358,6 @@ impl Config {
|
||||
network: config.network,
|
||||
db_path: config.db_dir,
|
||||
db_log_dir: config.db_log_dir,
|
||||
daemon_dir: config.daemon_dir,
|
||||
daemon_auth,
|
||||
daemon_rpc_addr,
|
||||
daemon_p2p_addr,
|
||||
@ -354,7 +375,6 @@ impl Config {
|
||||
disable_electrum_rpc: config.disable_electrum_rpc,
|
||||
server_banner: config.server_banner,
|
||||
signet_magic: magic,
|
||||
args: args.map(|a| a.into_string().unwrap()).collect(),
|
||||
};
|
||||
eprintln!(
|
||||
"Starting electrs {} on {} {} with {:?}",
|
||||
|
122
src/daemon.rs
122
src/daemon.rs
@ -5,7 +5,8 @@ use bitcoin::{Amount, BlockHash, Transaction, Txid};
|
||||
use bitcoincore_rpc::{json, jsonrpc, Auth, Client, RpcApi};
|
||||
use crossbeam_channel::Receiver;
|
||||
use parking_lot::Mutex;
|
||||
use serde_json::{json, Value};
|
||||
use serde::Serialize;
|
||||
use serde_json::{json, value::RawValue, Value};
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
@ -147,11 +148,15 @@ impl Daemon {
|
||||
}
|
||||
|
||||
pub(crate) fn estimate_fee(&self, nblocks: u16) -> Result<Option<Amount>> {
|
||||
Ok(self
|
||||
.rpc
|
||||
.estimate_smart_fee(nblocks, None)
|
||||
.context("failed to estimate fee")?
|
||||
.fee_rate)
|
||||
let res = self.rpc.estimate_smart_fee(nblocks, None);
|
||||
if let Err(bitcoincore_rpc::Error::JsonRpc(jsonrpc::Error::Rpc(RpcError {
|
||||
code: -32603,
|
||||
..
|
||||
}))) = res
|
||||
{
|
||||
return Ok(None); // don't fail when fee estimation is disabled (e.g. with `-blocksonly=1`)
|
||||
}
|
||||
Ok(res.context("failed to estimate fee")?.fee_rate)
|
||||
}
|
||||
|
||||
pub(crate) fn get_relay_fee(&self) -> Result<Amount> {
|
||||
@ -214,6 +219,12 @@ impl Daemon {
|
||||
.tx)
|
||||
}
|
||||
|
||||
pub(crate) fn get_mempool_info(&self) -> Result<json::GetMempoolInfoResult> {
|
||||
self.rpc
|
||||
.get_mempool_info()
|
||||
.context("failed to get mempool info")
|
||||
}
|
||||
|
||||
pub(crate) fn get_mempool_txids(&self) -> Result<Vec<Txid>> {
|
||||
self.rpc
|
||||
.get_raw_mempool()
|
||||
@ -223,25 +234,16 @@ impl Daemon {
|
||||
pub(crate) fn get_mempool_entries(
|
||||
&self,
|
||||
txids: &[Txid],
|
||||
) -> Result<Vec<Result<json::GetMempoolEntryResult>>> {
|
||||
let client = self.rpc.get_jsonrpc_client();
|
||||
debug!("getting {} mempool entries", txids.len());
|
||||
let args: Vec<_> = txids
|
||||
.iter()
|
||||
.map(|txid| vec![serde_json::value::to_raw_value(txid).unwrap()])
|
||||
.collect();
|
||||
let reqs: Vec<_> = args
|
||||
.iter()
|
||||
.map(|a| client.build_request("getmempoolentry", a))
|
||||
.collect();
|
||||
let res = client.send_batch(&reqs).context("batch request failed")?;
|
||||
debug!("got {} mempool entries", res.len());
|
||||
Ok(res
|
||||
) -> Result<Vec<Option<json::GetMempoolEntryResult>>> {
|
||||
let results = batch_request(self.rpc.get_jsonrpc_client(), "getmempoolentry", txids)?;
|
||||
Ok(results
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
r.context("missing response")?
|
||||
.result::<json::GetMempoolEntryResult>()
|
||||
.context("invalid response")
|
||||
.map(|r| match r?.result::<json::GetMempoolEntryResult>() {
|
||||
Ok(entry) => Some(entry),
|
||||
Err(err) => {
|
||||
debug!("failed to get mempool entry: {}", err); // probably due to RBF
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
@ -249,28 +251,32 @@ impl Daemon {
|
||||
pub(crate) fn get_mempool_transactions(
|
||||
&self,
|
||||
txids: &[Txid],
|
||||
) -> Result<Vec<Result<Transaction>>> {
|
||||
let client = self.rpc.get_jsonrpc_client();
|
||||
debug!("getting {} transactions", txids.len());
|
||||
let args: Vec<_> = txids
|
||||
.iter()
|
||||
.map(|txid| vec![serde_json::value::to_raw_value(txid).unwrap()])
|
||||
.collect();
|
||||
let reqs: Vec<_> = args
|
||||
.iter()
|
||||
.map(|a| client.build_request("getrawtransaction", a))
|
||||
.collect();
|
||||
let res = client.send_batch(&reqs).context("batch request failed")?;
|
||||
debug!("got {} mempool transactions", res.len());
|
||||
Ok(res
|
||||
) -> Result<Vec<Option<Transaction>>> {
|
||||
let results = batch_request(self.rpc.get_jsonrpc_client(), "getrawtransaction", txids)?;
|
||||
Ok(results
|
||||
.into_iter()
|
||||
.map(|r| -> Result<Transaction> {
|
||||
let tx_hex = r
|
||||
.context("missing response")?
|
||||
.result::<String>()
|
||||
.context("invalid response")?;
|
||||
let tx_bytes = Vec::from_hex(&tx_hex).context("non-hex transaction")?;
|
||||
deserialize(&tx_bytes).context("invalid transaction")
|
||||
.map(|r| -> Option<Transaction> {
|
||||
let tx_hex = match r?.result::<String>() {
|
||||
Ok(tx_hex) => Some(tx_hex),
|
||||
Err(err) => {
|
||||
debug!("failed to get mempool tx: {}", err); // probably due to RBF
|
||||
None
|
||||
}
|
||||
}?;
|
||||
let tx_bytes = match Vec::from_hex(&tx_hex) {
|
||||
Ok(tx_bytes) => Some(tx_bytes),
|
||||
Err(err) => {
|
||||
warn!("got non-hex transaction {}: {}", tx_hex, err);
|
||||
None
|
||||
}
|
||||
}?;
|
||||
match deserialize(&tx_bytes) {
|
||||
Ok(tx) => Some(tx),
|
||||
Err(err) => {
|
||||
warn!("got invalid tx {}: {}", tx_hex, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
@ -303,3 +309,29 @@ pub(crate) fn extract_bitcoind_error(err: &bitcoincore_rpc::Error) -> Option<&Rp
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn batch_request<T>(
|
||||
client: &jsonrpc::Client,
|
||||
name: &str,
|
||||
items: &[T],
|
||||
) -> Result<Vec<Option<jsonrpc::Response>>>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
debug!("calling {} on {} items", name, items.len());
|
||||
let args: Vec<Box<RawValue>> = items
|
||||
.iter()
|
||||
.map(|item| jsonrpc::try_arg([item]).context("failed to serialize into JSON"))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let reqs: Vec<jsonrpc::Request> = args
|
||||
.iter()
|
||||
.map(|arg| client.build_request(name, Some(arg)))
|
||||
.collect();
|
||||
match client.send_batch(&reqs) {
|
||||
Ok(values) => {
|
||||
assert_eq!(items.len(), values.len());
|
||||
Ok(values)
|
||||
}
|
||||
Err(err) => bail!("batch {} request failed: {}", name, err),
|
||||
}
|
||||
}
|
||||
|
141
src/db.rs
141
src/db.rs
@ -4,15 +4,15 @@ use electrs_rocksdb as rocksdb;
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
pub(crate) type Row = Box<[u8]>;
|
||||
use crate::types::{HashPrefix, SerializedHashPrefixRow, SerializedHeaderRow};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct WriteBatch {
|
||||
pub(crate) tip_row: Row,
|
||||
pub(crate) header_rows: Vec<Row>,
|
||||
pub(crate) funding_rows: Vec<Row>,
|
||||
pub(crate) spending_rows: Vec<Row>,
|
||||
pub(crate) txid_rows: Vec<Row>,
|
||||
pub(crate) tip_row: [u8; 32],
|
||||
pub(crate) header_rows: Vec<SerializedHeaderRow>,
|
||||
pub(crate) funding_rows: Vec<SerializedHashPrefixRow>,
|
||||
pub(crate) spending_rows: Vec<SerializedHashPrefixRow>,
|
||||
pub(crate) txid_rows: Vec<SerializedHashPrefixRow>,
|
||||
}
|
||||
|
||||
impl WriteBatch {
|
||||
@ -42,7 +42,7 @@ const CONFIG_KEY: &str = "C";
|
||||
const TIP_KEY: &[u8] = b"T";
|
||||
|
||||
// Taken from https://github.com/facebook/rocksdb/blob/master/include/rocksdb/db.h#L654-L689
|
||||
const DB_PROPERIES: &[&str] = &[
|
||||
const DB_PROPERTIES: &[&str] = &[
|
||||
"rocksdb.num-immutable-mem-table",
|
||||
"rocksdb.mem-table-flush-pending",
|
||||
"rocksdb.compaction-pending",
|
||||
@ -218,39 +218,50 @@ impl DBStore {
|
||||
self.db.cf_handle(HEADERS_CF).expect("missing HEADERS_CF")
|
||||
}
|
||||
|
||||
pub(crate) fn iter_funding(&self, prefix: Row) -> impl Iterator<Item = Row> + '_ {
|
||||
pub(crate) fn iter_funding(
|
||||
&self,
|
||||
prefix: HashPrefix,
|
||||
) -> impl Iterator<Item = SerializedHashPrefixRow> + '_ {
|
||||
self.iter_prefix_cf(self.funding_cf(), prefix)
|
||||
}
|
||||
|
||||
pub(crate) fn iter_spending(&self, prefix: Row) -> impl Iterator<Item = Row> + '_ {
|
||||
pub(crate) fn iter_spending(
|
||||
&self,
|
||||
prefix: HashPrefix,
|
||||
) -> impl Iterator<Item = SerializedHashPrefixRow> + '_ {
|
||||
self.iter_prefix_cf(self.spending_cf(), prefix)
|
||||
}
|
||||
|
||||
pub(crate) fn iter_txid(&self, prefix: Row) -> impl Iterator<Item = Row> + '_ {
|
||||
pub(crate) fn iter_txid(
|
||||
&self,
|
||||
prefix: HashPrefix,
|
||||
) -> impl Iterator<Item = SerializedHashPrefixRow> + '_ {
|
||||
self.iter_prefix_cf(self.txid_cf(), prefix)
|
||||
}
|
||||
|
||||
fn iter_cf<const N: usize>(
|
||||
&self,
|
||||
cf: &rocksdb::ColumnFamily,
|
||||
readopts: rocksdb::ReadOptions,
|
||||
prefix: Option<HashPrefix>,
|
||||
) -> impl Iterator<Item = [u8; N]> + '_ {
|
||||
DBIterator::new(self.db.raw_iterator_cf_opt(cf, readopts), prefix)
|
||||
}
|
||||
|
||||
fn iter_prefix_cf(
|
||||
&self,
|
||||
cf: &rocksdb::ColumnFamily,
|
||||
prefix: Row,
|
||||
) -> impl Iterator<Item = Row> + '_ {
|
||||
let mode = rocksdb::IteratorMode::From(&prefix, rocksdb::Direction::Forward);
|
||||
prefix: HashPrefix,
|
||||
) -> impl Iterator<Item = SerializedHashPrefixRow> + '_ {
|
||||
let mut opts = rocksdb::ReadOptions::default();
|
||||
opts.set_prefix_same_as_start(true); // requires .set_prefix_extractor() above.
|
||||
self.db
|
||||
.iterator_cf_opt(cf, opts, mode)
|
||||
.map(|row| row.expect("prefix iterator failed").0) // values are empty in prefix-scanned CFs
|
||||
self.iter_cf(cf, opts, Some(prefix))
|
||||
}
|
||||
|
||||
pub(crate) fn read_headers(&self) -> Vec<Row> {
|
||||
pub(crate) fn iter_headers(&self) -> impl Iterator<Item = SerializedHeaderRow> + '_ {
|
||||
let mut opts = rocksdb::ReadOptions::default();
|
||||
opts.fill_cache(false);
|
||||
self.db
|
||||
.iterator_cf_opt(self.headers_cf(), opts, rocksdb::IteratorMode::Start)
|
||||
.map(|row| row.expect("header iterator failed").0) // extract key from row
|
||||
.filter(|key| &key[..] != TIP_KEY) // headers' rows are longer than TIP_KEY
|
||||
.collect()
|
||||
self.iter_cf(self.headers_cf(), opts, None)
|
||||
}
|
||||
|
||||
pub(crate) fn get_tip(&self) -> Option<Vec<u8>> {
|
||||
@ -273,7 +284,7 @@ impl DBStore {
|
||||
for key in &batch.header_rows {
|
||||
db_batch.put_cf(self.headers_cf(), key, b"");
|
||||
}
|
||||
db_batch.put_cf(self.headers_cf(), TIP_KEY, &batch.tip_row);
|
||||
db_batch.put_cf(self.headers_cf(), TIP_KEY, batch.tip_row);
|
||||
|
||||
let mut opts = rocksdb::WriteOptions::new();
|
||||
let bulk_import = self.bulk_import.load(Ordering::Relaxed);
|
||||
@ -315,7 +326,7 @@ impl DBStore {
|
||||
) -> impl Iterator<Item = (&'static str, &'static str, u64)> + '_ {
|
||||
COLUMN_FAMILIES.iter().flat_map(move |cf_name| {
|
||||
let cf = self.db.cf_handle(cf_name).expect("missing CF");
|
||||
DB_PROPERIES.iter().filter_map(move |property_name| {
|
||||
DB_PROPERTIES.iter().filter_map(move |property_name| {
|
||||
let value = self
|
||||
.db
|
||||
.property_int_value_cf(cf, *property_name)
|
||||
@ -354,6 +365,57 @@ impl DBStore {
|
||||
}
|
||||
}
|
||||
|
||||
struct DBIterator<'a, const N: usize> {
|
||||
raw: rocksdb::DBRawIterator<'a>,
|
||||
prefix: Option<HashPrefix>,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl<'a, const N: usize> DBIterator<'a, N> {
|
||||
fn new(mut raw: rocksdb::DBRawIterator<'a>, prefix: Option<HashPrefix>) -> Self {
|
||||
match prefix {
|
||||
Some(key) => raw.seek(key),
|
||||
None => raw.seek_to_first(),
|
||||
};
|
||||
Self {
|
||||
raw,
|
||||
prefix,
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Iterator for DBIterator<'_, N> {
|
||||
type Item = [u8; N];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while !self.done {
|
||||
let key = match self.raw.key() {
|
||||
Some(key) => key,
|
||||
None => {
|
||||
self.raw.status().expect("DB scan failed");
|
||||
break; // end of scan
|
||||
}
|
||||
};
|
||||
let prefix_match = match self.prefix {
|
||||
Some(key_prefix) => key.starts_with(&key_prefix),
|
||||
None => true,
|
||||
};
|
||||
if !prefix_match {
|
||||
break; // prefix mismatch
|
||||
}
|
||||
let result: Option<[u8; N]> = key.try_into().ok();
|
||||
self.raw.next();
|
||||
match result {
|
||||
Some(value) => return Some(value),
|
||||
None => continue, // skip keys with size != N
|
||||
}
|
||||
}
|
||||
self.done = true;
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DBStore {
|
||||
fn drop(&mut self) {
|
||||
info!("closing DB at {}", self.db.path().display());
|
||||
@ -424,31 +486,24 @@ mod tests {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let store = DBStore::open(dir.path(), None, true).unwrap();
|
||||
|
||||
let items: &[&[u8]] = &[
|
||||
b"ab",
|
||||
b"abcdefgh",
|
||||
b"abcdefghj",
|
||||
b"abcdefghjk",
|
||||
b"abcdefghxyz",
|
||||
b"abcdefgi",
|
||||
b"b",
|
||||
b"c",
|
||||
let items = [
|
||||
*b"ab ",
|
||||
*b"abcdefgh ",
|
||||
*b"abcdefghj ",
|
||||
*b"abcdefghjk ",
|
||||
*b"abcdefghxyz ",
|
||||
*b"abcdefgi ",
|
||||
*b"b ",
|
||||
*b"c ",
|
||||
];
|
||||
|
||||
store.write(&WriteBatch {
|
||||
txid_rows: to_rows(items),
|
||||
txid_rows: items.to_vec(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let rows = store.iter_txid(b"abcdefgh".to_vec().into_boxed_slice());
|
||||
assert_eq!(rows.collect::<Vec<_>>(), to_rows(&items[1..5]));
|
||||
}
|
||||
|
||||
fn to_rows(values: &[&[u8]]) -> Vec<Box<[u8]>> {
|
||||
values
|
||||
.iter()
|
||||
.map(|v| v.to_vec().into_boxed_slice())
|
||||
.collect()
|
||||
let rows = store.iter_txid(*b"abcdefgh");
|
||||
assert_eq!(rows.collect::<Vec<_>>(), items[1..5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
35
src/index.rs
35
src/index.rs
@ -1,5 +1,6 @@
|
||||
use anyhow::{Context, Result};
|
||||
use bitcoin::consensus::{deserialize, serialize, Decodable};
|
||||
use bitcoin::consensus::{deserialize, Decodable, Encodable};
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::{BlockHash, OutPoint, Txid};
|
||||
use bitcoin_slices::{bsl, Visit, Visitor};
|
||||
use std::ops::ControlFlow;
|
||||
@ -7,7 +8,7 @@ use std::ops::ControlFlow;
|
||||
use crate::{
|
||||
chain::{Chain, NewHeader},
|
||||
daemon::Daemon,
|
||||
db::{DBStore, Row, WriteBatch},
|
||||
db::{DBStore, WriteBatch},
|
||||
metrics::{self, Gauge, Histogram, Metrics},
|
||||
signals::ExitFlag,
|
||||
types::{
|
||||
@ -48,8 +49,8 @@ impl Stats {
|
||||
self.update_duration.observe_duration(label, f)
|
||||
}
|
||||
|
||||
fn observe_size(&self, label: &str, rows: &[Row]) {
|
||||
self.update_size.observe(label, db_rows_size(rows) as f64);
|
||||
fn observe_size<const N: usize>(&self, label: &str, rows: &[[u8; N]]) {
|
||||
self.update_size.observe(label, (rows.len() * N) as f64);
|
||||
}
|
||||
|
||||
fn observe_batch(&self, batch: &WriteBatch) {
|
||||
@ -101,10 +102,8 @@ impl Index {
|
||||
if let Some(row) = store.get_tip() {
|
||||
let tip = deserialize(&row).expect("invalid tip");
|
||||
let headers = store
|
||||
.read_headers()
|
||||
.into_iter()
|
||||
.map(|row| HeaderRow::from_db_row(&row).header)
|
||||
.collect();
|
||||
.iter_headers()
|
||||
.map(|row| HeaderRow::from_db_row(row).header);
|
||||
chain.load(headers, tip);
|
||||
chain.drop_last_headers(reindex_last_blocks);
|
||||
};
|
||||
@ -141,7 +140,7 @@ impl Index {
|
||||
pub(crate) fn filter_by_txid(&self, txid: Txid) -> impl Iterator<Item = BlockHash> + '_ {
|
||||
self.store
|
||||
.iter_txid(TxidRow::scan_prefix(txid))
|
||||
.map(|row| HashPrefixRow::from_db_row(&row).height())
|
||||
.map(|row| HashPrefixRow::from_db_row(row).height())
|
||||
.filter_map(move |height| self.chain.get_block_hash(height))
|
||||
}
|
||||
|
||||
@ -151,7 +150,7 @@ impl Index {
|
||||
) -> impl Iterator<Item = BlockHash> + '_ {
|
||||
self.store
|
||||
.iter_funding(ScriptHashRow::scan_prefix(scripthash))
|
||||
.map(|row| HashPrefixRow::from_db_row(&row).height())
|
||||
.map(|row| HashPrefixRow::from_db_row(row).height())
|
||||
.filter_map(move |height| self.chain.get_block_hash(height))
|
||||
}
|
||||
|
||||
@ -161,7 +160,7 @@ impl Index {
|
||||
) -> impl Iterator<Item = BlockHash> + '_ {
|
||||
self.store
|
||||
.iter_spending(SpendingPrefixRow::scan_prefix(outpoint))
|
||||
.map(|row| HashPrefixRow::from_db_row(&row).height())
|
||||
.map(|row| HashPrefixRow::from_db_row(row).height())
|
||||
.filter_map(move |height| self.chain.get_block_hash(height))
|
||||
}
|
||||
|
||||
@ -236,10 +235,6 @@ impl Index {
|
||||
}
|
||||
}
|
||||
|
||||
fn db_rows_size(rows: &[Row]) -> usize {
|
||||
rows.iter().map(|key| key.len()).sum()
|
||||
}
|
||||
|
||||
fn index_single_block(
|
||||
block_hash: BlockHash,
|
||||
block: SerBlock,
|
||||
@ -251,7 +246,7 @@ fn index_single_block(
|
||||
height: usize,
|
||||
}
|
||||
|
||||
impl<'a> Visitor for IndexBlockVisitor<'a> {
|
||||
impl Visitor for IndexBlockVisitor<'_> {
|
||||
fn visit_transaction(&mut self, tx: &bsl::Transaction) -> ControlFlow<()> {
|
||||
let txid = bsl_txid(tx);
|
||||
self.batch
|
||||
@ -263,7 +258,7 @@ fn index_single_block(
|
||||
fn visit_tx_out(&mut self, _vout: usize, tx_out: &bsl::TxOut) -> ControlFlow<()> {
|
||||
let script = bitcoin::Script::from_bytes(tx_out.script_pubkey());
|
||||
// skip indexing unspendable outputs
|
||||
if !script.is_provably_unspendable() {
|
||||
if !script.is_op_return() {
|
||||
let row = ScriptHashRow::row(ScriptHash::new(script), self.height);
|
||||
self.batch.funding_rows.push(row.to_db_row());
|
||||
}
|
||||
@ -292,5 +287,9 @@ fn index_single_block(
|
||||
|
||||
let mut index_block = IndexBlockVisitor { batch, height };
|
||||
bsl::Block::visit(&block, &mut index_block).expect("core returned invalid block");
|
||||
batch.tip_row = serialize(&block_hash).into_boxed_slice();
|
||||
|
||||
let len = block_hash
|
||||
.consensus_encode(&mut (&mut batch.tip_row as &mut [u8]))
|
||||
.expect("in-memory writers don't error");
|
||||
debug_assert_eq!(len, BlockHash::LEN);
|
||||
}
|
||||
|
@ -82,8 +82,20 @@ impl MempoolSyncUpdate {
|
||||
.iter()
|
||||
.zip(entries.into_iter().zip(txs.into_iter()))
|
||||
.filter_map(|(txid, (entry, tx))| {
|
||||
let tx = tx.ok()?;
|
||||
let entry = entry.ok()?;
|
||||
let entry = match entry {
|
||||
Some(entry) => entry,
|
||||
None => {
|
||||
debug!("missing mempool entry: {}", txid);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let tx = match tx {
|
||||
Some(tx) => tx,
|
||||
None => {
|
||||
debug!("missing mempool tx: {}", txid);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some(Entry {
|
||||
txid: *txid,
|
||||
tx,
|
||||
@ -199,6 +211,18 @@ impl Mempool {
|
||||
}
|
||||
|
||||
pub fn sync(&mut self, daemon: &Daemon, exit_flag: &ExitFlag) {
|
||||
let loaded = match daemon.get_mempool_info() {
|
||||
Ok(info) => info.loaded.unwrap_or(true),
|
||||
Err(e) => {
|
||||
warn!("mempool sync failed: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if !loaded {
|
||||
warn!("mempool not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
let old_txids = HashSet::<Txid>::from_iter(self.entries.keys().copied());
|
||||
|
||||
let poll_result = MempoolSyncUpdate::poll(daemon, old_txids, exit_flag);
|
||||
@ -332,7 +356,7 @@ impl Serialize for FeeHistogram {
|
||||
let mut seq = serializer.serialize_seq(Some(self.vsize.len()))?;
|
||||
// https://electrumx-spesmilo.readthedocs.io/en/latest/protocol-methods.html#mempool-get-fee-histogram
|
||||
let fee_rates =
|
||||
(0..FeeHistogram::BINS).map(|i| std::u64::MAX.checked_shr(i as u32).unwrap_or(0));
|
||||
(0..FeeHistogram::BINS).map(|i| u64::MAX.checked_shr(i as u32).unwrap_or(0));
|
||||
fee_rates
|
||||
.zip(self.vsize.iter().copied())
|
||||
.skip_while(|(_fee_rate, vsize)| *vsize == 0)
|
||||
|
@ -108,6 +108,6 @@ mod tests {
|
||||
.join(block_hash_hex);
|
||||
let data = std::fs::read(path).unwrap();
|
||||
let block: Block = deserialize(&data).unwrap();
|
||||
block.txdata.iter().map(|tx| tx.txid()).collect()
|
||||
block.txdata.iter().map(|tx| tx.compute_txid()).collect()
|
||||
}
|
||||
}
|
||||
|
26
src/p2p.rs
26
src/p2p.rs
@ -7,6 +7,7 @@ use bitcoin::{
|
||||
Decodable,
|
||||
},
|
||||
hashes::Hash,
|
||||
io,
|
||||
p2p::{
|
||||
self, address,
|
||||
message::{self, CommandString, NetworkMessage},
|
||||
@ -19,9 +20,8 @@ use bitcoin::{
|
||||
use bitcoin_slices::{bsl, Parse};
|
||||
use crossbeam_channel::{bounded, select, Receiver, Sender};
|
||||
|
||||
use std::io::{self, ErrorKind, Write};
|
||||
use std::io::Write;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use crate::types::SerBlock;
|
||||
@ -141,10 +141,11 @@ impl Connection {
|
||||
metrics: &Metrics,
|
||||
magic: Magic,
|
||||
) -> Result<Self> {
|
||||
let conn = Arc::new(
|
||||
TcpStream::connect(address)
|
||||
.with_context(|| format!("{} p2p failed to connect: {:?}", network, address))?,
|
||||
);
|
||||
let recv_conn = TcpStream::connect(address)
|
||||
.with_context(|| format!("{} p2p failed to connect: {:?}", network, address))?;
|
||||
let mut send_conn = recv_conn
|
||||
.try_clone()
|
||||
.context("failed to clone connection")?;
|
||||
|
||||
let (tx_send, tx_recv) = bounded::<NetworkMessage>(1);
|
||||
let (rx_send, rx_recv) = bounded::<RawNetworkMessage>(1);
|
||||
@ -180,7 +181,6 @@ impl Connection {
|
||||
default_duration_buckets(),
|
||||
);
|
||||
|
||||
let stream = Arc::clone(&conn);
|
||||
let mut buffer = vec![];
|
||||
crate::thread::spawn("p2p_send", move || loop {
|
||||
use std::net::Shutdown;
|
||||
@ -190,7 +190,7 @@ impl Connection {
|
||||
// p2p_loop is closed, so tx_send is disconnected
|
||||
debug!("closing p2p_send thread: no more messages to send");
|
||||
// close the stream reader (p2p_recv thread may block on it)
|
||||
if let Err(e) = stream.shutdown(Shutdown::Read) {
|
||||
if let Err(e) = send_conn.shutdown(Shutdown::Read) {
|
||||
warn!("failed to shutdown p2p connection: {}", e)
|
||||
}
|
||||
return Ok(());
|
||||
@ -203,16 +203,16 @@ impl Connection {
|
||||
raw_msg
|
||||
.consensus_encode(&mut buffer)
|
||||
.expect("in-memory writers don't error");
|
||||
(&*stream)
|
||||
send_conn
|
||||
.write_all(buffer.as_slice())
|
||||
.context("p2p failed to send")
|
||||
})?;
|
||||
});
|
||||
|
||||
let stream = Arc::clone(&conn);
|
||||
let mut stream_reader = std::io::BufReader::new(recv_conn);
|
||||
crate::thread::spawn("p2p_recv", move || loop {
|
||||
let start = Instant::now();
|
||||
let raw_msg = RawNetworkMessage::consensus_decode(&mut &*stream);
|
||||
let raw_msg = RawNetworkMessage::consensus_decode(&mut stream_reader);
|
||||
{
|
||||
let duration = duration_to_seconds(start.elapsed());
|
||||
let label = format!(
|
||||
@ -232,7 +232,7 @@ impl Connection {
|
||||
}
|
||||
raw_msg
|
||||
}
|
||||
Err(encode::Error::Io(e)) if e.kind() == ErrorKind::UnexpectedEof => {
|
||||
Err(encode::Error::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {
|
||||
debug!("closing p2p_recv thread: connection closed");
|
||||
return Ok(());
|
||||
}
|
||||
@ -390,7 +390,7 @@ enum ParsedNetworkMessage {
|
||||
}
|
||||
|
||||
impl Decodable for RawNetworkMessage {
|
||||
fn consensus_decode<D: io::Read + ?Sized>(d: &mut D) -> Result<Self, encode::Error> {
|
||||
fn consensus_decode<D: bitcoin::io::Read + ?Sized>(d: &mut D) -> Result<Self, encode::Error> {
|
||||
let magic = Decodable::consensus_decode(d)?;
|
||||
let cmd = Decodable::consensus_decode(d)?;
|
||||
|
||||
|
@ -240,7 +240,7 @@ impl ScriptHashStatus {
|
||||
fn confirmed_height_entries<'a>(
|
||||
&'a self,
|
||||
chain: &'a Chain,
|
||||
) -> impl Iterator<Item = (usize, &[TxEntry])> + 'a {
|
||||
) -> impl Iterator<Item = (usize, &'a [TxEntry])> + 'a {
|
||||
self.confirmed
|
||||
.iter()
|
||||
.filter_map(move |(blockhash, entries)| {
|
||||
@ -252,7 +252,7 @@ impl ScriptHashStatus {
|
||||
|
||||
/// Iterate through confirmed TxEntries.
|
||||
/// Skip entries from stale blocks.
|
||||
fn confirmed_entries<'a>(&'a self, chain: &'a Chain) -> impl Iterator<Item = &TxEntry> + 'a {
|
||||
fn confirmed_entries<'a>(&'a self, chain: &'a Chain) -> impl Iterator<Item = &'a TxEntry> + 'a {
|
||||
self.confirmed_height_entries(chain)
|
||||
.flat_map(|(_height, entries)| entries)
|
||||
}
|
||||
@ -565,7 +565,7 @@ fn filter_block_txs_inputs(
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a> Visitor for FindInputs<'a> {
|
||||
impl Visitor for FindInputs<'_> {
|
||||
fn visit_transaction(&mut self, tx: &bsl::Transaction) -> ControlFlow<()> {
|
||||
if !self.buffer.is_empty() {
|
||||
let result = std::mem::take(&mut self.buffer);
|
||||
|
73
src/types.rs
73
src/types.rs
@ -6,20 +6,18 @@ use bitcoin::blockdata::block::Header as BlockHeader;
|
||||
use bitcoin::{
|
||||
consensus::encode::{deserialize, Decodable, Encodable},
|
||||
hashes::{hash_newtype, sha256, Hash},
|
||||
OutPoint, Script, Txid,
|
||||
io, OutPoint, Script, Txid,
|
||||
};
|
||||
use bitcoin_slices::bsl;
|
||||
|
||||
use crate::db;
|
||||
|
||||
macro_rules! impl_consensus_encoding {
|
||||
($thing:ident, $($field:ident),+) => (
|
||||
impl Encodable for $thing {
|
||||
#[inline]
|
||||
fn consensus_encode<S: ::std::io::Write + ?Sized>(
|
||||
fn consensus_encode<S: io::Write + ?Sized>(
|
||||
&self,
|
||||
s: &mut S,
|
||||
) -> Result<usize, std::io::Error> {
|
||||
) -> Result<usize, io::Error> {
|
||||
let mut len = 0;
|
||||
$(len += self.$field.consensus_encode(s)?;)+
|
||||
Ok(len)
|
||||
@ -28,7 +26,7 @@ macro_rules! impl_consensus_encoding {
|
||||
|
||||
impl Decodable for $thing {
|
||||
#[inline]
|
||||
fn consensus_decode<D: ::std::io::Read + ?Sized>(
|
||||
fn consensus_decode<D: io::Read + ?Sized>(
|
||||
d: &mut D,
|
||||
) -> Result<$thing, bitcoin::consensus::encode::Error> {
|
||||
Ok($thing {
|
||||
@ -39,33 +37,34 @@ macro_rules! impl_consensus_encoding {
|
||||
);
|
||||
}
|
||||
|
||||
const HASH_PREFIX_LEN: usize = 8;
|
||||
pub const HASH_PREFIX_LEN: usize = 8;
|
||||
const HEIGHT_SIZE: usize = 4;
|
||||
|
||||
type HashPrefix = [u8; HASH_PREFIX_LEN];
|
||||
pub(crate) type HashPrefix = [u8; HASH_PREFIX_LEN];
|
||||
pub(crate) type SerializedHashPrefixRow = [u8; HASH_PREFIX_ROW_SIZE];
|
||||
type Height = u32;
|
||||
pub(crate) type SerBlock = Vec<u8>;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub(crate) struct HashPrefixRow {
|
||||
prefix: [u8; HASH_PREFIX_LEN],
|
||||
prefix: HashPrefix,
|
||||
height: Height, // transaction confirmed height
|
||||
}
|
||||
|
||||
const HASH_PREFIX_ROW_SIZE: usize = HASH_PREFIX_LEN + HEIGHT_SIZE;
|
||||
pub const HASH_PREFIX_ROW_SIZE: usize = HASH_PREFIX_LEN + HEIGHT_SIZE;
|
||||
|
||||
impl HashPrefixRow {
|
||||
pub(crate) fn to_db_row(&self) -> db::Row {
|
||||
let mut vec = Vec::with_capacity(HASH_PREFIX_ROW_SIZE);
|
||||
pub(crate) fn to_db_row(&self) -> SerializedHashPrefixRow {
|
||||
let mut row = [0; HASH_PREFIX_ROW_SIZE];
|
||||
let len = self
|
||||
.consensus_encode(&mut vec)
|
||||
.consensus_encode(&mut (&mut row as &mut [u8]))
|
||||
.expect("in-memory writers don't error");
|
||||
debug_assert_eq!(len, HASH_PREFIX_ROW_SIZE);
|
||||
vec.into_boxed_slice()
|
||||
row
|
||||
}
|
||||
|
||||
pub(crate) fn from_db_row(row: &[u8]) -> Self {
|
||||
deserialize(row).expect("bad HashPrefixRow")
|
||||
pub(crate) fn from_db_row(row: SerializedHashPrefixRow) -> Self {
|
||||
deserialize(&row).expect("bad HashPrefixRow")
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
@ -96,8 +95,8 @@ impl ScriptHash {
|
||||
pub(crate) struct ScriptHashRow;
|
||||
|
||||
impl ScriptHashRow {
|
||||
pub(crate) fn scan_prefix(scripthash: ScriptHash) -> Box<[u8]> {
|
||||
scripthash.0[..HASH_PREFIX_LEN].to_vec().into_boxed_slice()
|
||||
pub(crate) fn scan_prefix(scripthash: ScriptHash) -> HashPrefix {
|
||||
scripthash.0[..HASH_PREFIX_LEN].try_into().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn row(scripthash: ScriptHash, height: usize) -> HashPrefixRow {
|
||||
@ -118,7 +117,7 @@ hash_newtype! {
|
||||
// ***************************************************************************
|
||||
|
||||
fn spending_prefix(prev: OutPoint) -> HashPrefix {
|
||||
let txid_prefix = <[u8; HASH_PREFIX_LEN]>::try_from(&prev.txid[..HASH_PREFIX_LEN]).unwrap();
|
||||
let txid_prefix = HashPrefix::try_from(&prev.txid[..HASH_PREFIX_LEN]).unwrap();
|
||||
let value = u64::from_be_bytes(txid_prefix);
|
||||
let value = value.wrapping_add(prev.vout.into());
|
||||
value.to_be_bytes()
|
||||
@ -127,8 +126,8 @@ fn spending_prefix(prev: OutPoint) -> HashPrefix {
|
||||
pub(crate) struct SpendingPrefixRow;
|
||||
|
||||
impl SpendingPrefixRow {
|
||||
pub(crate) fn scan_prefix(outpoint: OutPoint) -> Box<[u8]> {
|
||||
Box::new(spending_prefix(outpoint))
|
||||
pub(crate) fn scan_prefix(outpoint: OutPoint) -> HashPrefix {
|
||||
spending_prefix(outpoint)
|
||||
}
|
||||
|
||||
pub(crate) fn row(outpoint: OutPoint, height: usize) -> HashPrefixRow {
|
||||
@ -150,8 +149,8 @@ fn txid_prefix(txid: &Txid) -> HashPrefix {
|
||||
pub(crate) struct TxidRow;
|
||||
|
||||
impl TxidRow {
|
||||
pub(crate) fn scan_prefix(txid: Txid) -> Box<[u8]> {
|
||||
Box::new(txid_prefix(&txid))
|
||||
pub(crate) fn scan_prefix(txid: Txid) -> HashPrefix {
|
||||
txid_prefix(&txid)
|
||||
}
|
||||
|
||||
pub(crate) fn row(txid: Txid, height: usize) -> HashPrefixRow {
|
||||
@ -164,12 +163,14 @@ impl TxidRow {
|
||||
|
||||
// ***************************************************************************
|
||||
|
||||
pub(crate) type SerializedHeaderRow = [u8; HEADER_ROW_SIZE];
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub(crate) struct HeaderRow {
|
||||
pub(crate) header: BlockHeader,
|
||||
}
|
||||
|
||||
const HEADER_ROW_SIZE: usize = 80;
|
||||
pub const HEADER_ROW_SIZE: usize = 80;
|
||||
|
||||
impl_consensus_encoding!(HeaderRow, header);
|
||||
|
||||
@ -178,17 +179,17 @@ impl HeaderRow {
|
||||
Self { header }
|
||||
}
|
||||
|
||||
pub(crate) fn to_db_row(&self) -> db::Row {
|
||||
let mut vec = Vec::with_capacity(HEADER_ROW_SIZE);
|
||||
pub(crate) fn to_db_row(&self) -> SerializedHeaderRow {
|
||||
let mut row = [0; HEADER_ROW_SIZE];
|
||||
let len = self
|
||||
.consensus_encode(&mut vec)
|
||||
.consensus_encode(&mut (&mut row as &mut [u8]))
|
||||
.expect("in-memory writers don't error");
|
||||
debug_assert_eq!(len, HEADER_ROW_SIZE);
|
||||
vec.into_boxed_slice()
|
||||
row
|
||||
}
|
||||
|
||||
pub(crate) fn from_db_row(row: &[u8]) -> Self {
|
||||
deserialize(row).expect("bad HeaderRow")
|
||||
pub(crate) fn from_db_row(row: SerializedHeaderRow) -> Self {
|
||||
deserialize(&row).expect("bad HeaderRow")
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,8 +220,8 @@ mod tests {
|
||||
let scripthash: ScriptHash = from_str(hex).unwrap();
|
||||
let row1 = ScriptHashRow::row(scripthash, 123456);
|
||||
let db_row = row1.to_db_row();
|
||||
assert_eq!(&*db_row, &hex!("a384491d38929fcc40e20100"));
|
||||
let row2 = HashPrefixRow::from_db_row(&db_row);
|
||||
assert_eq!(db_row, hex!("a384491d38929fcc40e20100"));
|
||||
let row2 = HashPrefixRow::from_db_row(db_row);
|
||||
assert_eq!(row1, row2);
|
||||
}
|
||||
|
||||
@ -247,8 +248,8 @@ mod tests {
|
||||
let row1 = TxidRow::row(txid, 91812);
|
||||
let row2 = TxidRow::row(txid, 91842);
|
||||
|
||||
assert_eq!(&*row1.to_db_row(), &hex!("9985d82954e10f22a4660100"));
|
||||
assert_eq!(&*row2.to_db_row(), &hex!("9985d82954e10f22c2660100"));
|
||||
assert_eq!(row1.to_db_row(), hex!("9985d82954e10f22a4660100"));
|
||||
assert_eq!(row2.to_db_row(), hex!("9985d82954e10f22c2660100"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -261,8 +262,8 @@ mod tests {
|
||||
let row2 = TxidRow::row(txid, 91880);
|
||||
|
||||
// low-endian encoding => rows should be sorted according to block height
|
||||
assert_eq!(&*row1.to_db_row(), &hex!("68b45f58b674e94e4a660100"));
|
||||
assert_eq!(&*row2.to_db_row(), &hex!("68b45f58b674e94ee8660100"));
|
||||
assert_eq!(row1.to_db_row(), hex!("68b45f58b674e94e4a660100"));
|
||||
assert_eq!(row2.to_db_row(), hex!("68b45f58b674e94ee8660100"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user