commit a85202b8b86a97e3cdb75548b8afc1b70cc14a9e Author: bitcoinafterlife Date: Sun Mar 23 14:00:09 2025 -0400 init diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..8966cbf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1062 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "bal-pusher" +version = "0.1.0" +dependencies = [ + "bitcoincore-rpc", + "bitcoincore-rpc-json", + "byteorder", + "confy", + "env_logger", + "hex", + "log", + "serde", + "sqlite", + "zmq", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0032b0e8ead7074cda7fc4f034409607e3f03a6f71d66ade8a307f79b4d99e73" +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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" + +[[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 = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "confy" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45b1f4c00870f07dc34adcac82bb6a72cc5aabca8536ba1797e01df51d2ce9a0" +dependencies = [ + "directories", + "serde", + "thiserror", + "toml", +] + +[[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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +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.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "dircpy" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88521b0517f5f9d51d11925d8ab4523497dcf947073fa3231a311b63941131c" +dependencies = [ + "jwalk", + "log", + "walkdir", +] + +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[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 = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[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 = "jwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" +dependencies = [ + "crossbeam", + "rayon", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minreq" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763d142cdff44aaadd9268bebddb156ef6c65a0e13486bb81673cf2d8739f9b0" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +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_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[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 = "serde" +version = "1.0.198" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.198" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[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 = "sqlite" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf42adadeba1af33e2778aa22a6e9c487d8a0e3170fe65e6cb8775b3c59eb99" +dependencies = [ + "libc", + "sqlite3-sys", +] + +[[package]] +name = "sqlite3-src" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "174d4a6df77c27db281fb23de1a6d968f3aaaa4807c2a1afa8056b971f947b4a" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "sqlite3-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aed0b61828382e1103930d2d5df1972d493173319730b481192e63d929097321" +dependencies = [ + "libc", + "sqlite3-src", +] + +[[package]] +name = "syn" +version = "2.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "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]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c52ac009d615e79296318c1bcce2d422aaca15ad08515e344feeda07df67a587" +dependencies = [ + "memchr", +] + +[[package]] +name = "zeromq-src" +version = "0.2.6+4.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc120b771270365d5ed0dfb4baf1005f2243ae1ae83703265cb3504070f4160b" +dependencies = [ + "cc", + "dircpy", +] + +[[package]] +name = "zmq" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd3091dd571fb84a9b3e5e5c6a807d186c411c812c8618786c3c30e5349234e7" +dependencies = [ + "bitflags 1.3.2", + "libc", + "zmq-sys", +] + +[[package]] +name = "zmq-sys" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8351dc72494b4d7f5652a681c33634063bbad58046c1689e75270908fdc864" +dependencies = [ + "libc", + "system-deps", + "zeromq-src", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c9ed897 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "bal-pusher" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +log = "0.4.21" +env_logger = "0.11.5" +bitcoincore-rpc = "0.19.0" +bitcoincore-rpc-json = "0.19.0" +sqlite = "0.34.0" +confy = "0.6.1" +serde = { version = "1.0.152", features = ["derive"] } # <- Only one serde version needed (serde or serde_derive) +zmq = "0.10.0" +hex = "0.4.3" +byteorder = "1.5.0" + diff --git a/README.md b/README.md new file mode 100644 index 0000000..f091092 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# bal-pusher + +`bal-pusher` is a tool that retrieves Bitcoin transactions from a database and pushes them to the Bitcoin network when their **locktime** exceeds the **median time past** (MTP). It listens for Bitcoin block updates via ZMQ. + +## Installation + +To use `bal-pusher`, you need to compile and install Bitcoin with ZMQ (ZeroMQ) support enabled. Then, configure your Bitcoin node and `bal-pusher` to push the transactions. + +### Prerequisites + +1. **Bitcoin with ZMQ Support**: + Ensure that Bitcoin is compiled with ZMQ support. Add the following line to your `bitcoin.conf` file: + + ``` + zmqpubhashblock=tcp://127.0.0.1:28332 + ``` + +2. **Install Rust and Cargo**: + If you haven't already installed Rust and Cargo, you can follow the official instructions to do so: [Rust Installation](https://www.rust-lang.org/tools/install). + +### Installation Steps + +1. Clone the repository: + + ```bash + git clone + cd bal-pusher + ``` + +2. Build the project: + + ```bash + cargo build --release + ``` + +3. Install the binary: + + ```bash + sudo cp target/release/bal-pusher /usr/local/bin + ``` + +## Configuration + +`bal-pusher` can be configured using environment variables. If no configuration file is provided, a default configuration file will be created. + +### Available Configuration Variables + +| Variable | Description | Default | +|---------------------------------------|------------------------------------------|----------------------------------------------| +| `BAL_PUSHER_CONFIG_FILE` | Path to the configuration file. If the file does not exist, it will be created. | `$HOME/.config/bal-pusher/default-config.toml` | +| `BAL_PUSHER_DB_FILE` | Path to the SQLite3 database file. If the file does not exist, it will be created. | `bal.db` | +| `BAL_PUSHER_ZMQ_LISTENER` | ZMQ listener for Bitcoin updates. | `tcp://127.0.0.1:28332` | +| `BAL_PUSHER_BITCOIN_HOST` | Bitcoin server host for RPC connections. | `http://127.0.0.1` | +| `BAL_PUSHER_BITCOIN_PORT` | Bitcoin RPC server port. | `8332` | +| `BAL_PUSHER_BITCOIN_COOKIE_FILE` | Path to Bitcoin RPC cookie file. | `$HOME/.bitcoin/.cookie` | +| `BAL_PUSHER_BITCOIN_RPC_USER` | Bitcoin RPC username. | - | +| `BAL_PUSHER_BITCOIN_RPC_PASSWORD` | Bitcoin RPC password. | - | + + +## Running `bal-pusher` + +Once the application is installed and configured, you can start `bal-pusher` by running the following command: + +```bash +$ bal-pusher +``` + +This will start the service, which will listen for Bitcoin blocks via ZMQ and push transactions from the database when their locktime exceeds the median time past. diff --git a/bal-pusher.env b/bal-pusher.env new file mode 100644 index 0000000..c84322d --- /dev/null +++ b/bal-pusher.env @@ -0,0 +1,10 @@ +RUST_LOG=info + + +BAL_PUSHER_DB_FILE=/home/bal/bal.db +BAL_PUSHER_BITCOIN_COOKIE_FILE=/home/bitcoin/.bitcoin/.cookie +BAL_PUSHER_REGTEST_COOKIE_FILE=/home/bitcoin/.bitcoin/regtest/.cookie +BAL_PUSHER_TESTNET_COOKIE_FILE=/home/bitcoin/.bitcoin/testnet3/.cookie +BAL_PUSHER_SIGNET_COOKIE_FILE=/home/bitcoin/.bitcoin/signet/.cookie + + diff --git a/bal-pusher.service b/bal-pusher.service new file mode 100644 index 0000000..07ffcbf --- /dev/null +++ b/bal-pusher.service @@ -0,0 +1,42 @@ +[Unit] +Description=bal-pusher daemon +After=bitcoind.service + +[Service] + +EnvironmentFile=/etc/bal/bal-pusher.env + +ExecStart=/usr/local/bin/bal-pusher bitcoin + +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=bal-pusher + + +Type=simple +PIDFile=/run/bal-pusher/bal-pusher.pid +Restart=always +TimeoutSec=120 +RestartSec=300 +KillMode=process + +User=bal +Group=bitcoin +UMask=0027 + +RuntimeDirectory=bal-pusher +RuntimeDirectoryMode=0710 + +PrivateTmp=true + +ProtectSystem=full + +NoNewPrivileges=true + +PrivateDevices=true + +MemoryDenyWriteExecute=true + +[Install] +WantedBy=multi-user.target + diff --git a/bitcoind.service b/bitcoind.service new file mode 100644 index 0000000..efb41a4 --- /dev/null +++ b/bitcoind.service @@ -0,0 +1,57 @@ +# RaspiBolt: systemd unit for bitcoind +# /etc/systemd/system/bitcoind.service + +[Unit] +Description=Bitcoin daemon +After=network.target + +[Service] + +# Service execution +################### + +ExecStart=/usr/local/bin/bitcoind -daemon \ + -pid=/run/bitcoind/bitcoind.pid \ + -conf=/home/bitcoin/.bitcoin/bitcoin.conf \ + -datadir=/home/bitcoin/.bitcoin \ + -startupnotify="chmod g+r /home/bitcoin/.bitcoin/.cookie" + +# Process management +#################### +Type=forking +PIDFile=/run/bitcoind/bitcoind.pid +Restart=on-failure +TimeoutSec=300 +RestartSec=30 + +# Directory creation and permissions +#################################### +User=bitcoin +UMask=0027 + +# /run/bitcoind +RuntimeDirectory=bitcoind +RuntimeDirectoryMode=0710 + +# Hardening measures +#################### +# Provide a private /tmp and /var/tmp. +PrivateTmp=true + +# Mount /usr, /boot/ and /etc read-only for the process. +ProtectSystem=full + +# Disallow the process and all of its children to gain +# new privileges through execve(). +NoNewPrivileges=true + +# Use a new /dev namespace only populated with API pseudo devices +# such as /dev/null, /dev/zero and /dev/random. +PrivateDevices=true + +# Deny the creation of writable and executable memory mappings. +MemoryDenyWriteExecute=true + +[Install] +WantedBy=multi-user.target + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..082e392 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,416 @@ +extern crate bitcoincore_rpc; +extern crate zmq; +use bitcoin::Network; + +use bitcoincore_rpc::{bitcoin, Auth, Client, Error, RpcApi}; +use bitcoincore_rpc_json::GetBlockchainInfoResult; + +use sqlite::{Value}; +use serde::Serialize; +use serde::Deserialize; +use std::env; +use std::fs::OpenOptions; +use std::io::{ Write}; +use log::{info,debug,warn,error}; +use zmq::{Context, Socket}; +use std::str; +use std::{thread, time::Duration}; +//use byteorder::{LittleEndian, ReadBytesExt}; +//use std::io::Cursor; +use hex; +use std::error::Error as StdError; + +const LOCKTIME_THRESHOLD:i64 = 5000000; + +#[derive(Debug, Clone,Serialize, Deserialize)] +struct MyConfig { + zmq_listener: String, + requests_file: String, + db_file: String, + bitcoin_dir: String, + regtest: NetworkParams, + testnet: NetworkParams, + signet: NetworkParams, + mainnet: NetworkParams, + + +} + +impl Default for MyConfig { + fn default() -> Self { + MyConfig { + zmq_listener: "tcp://127.0.0.1:28332".to_string(), + requests_file: "rawrequests.log".to_string(), + db_file: "../bal.db".to_string(), + bitcoin_dir: "".to_string(), + regtest: get_network_params_default(Network::Regtest), + testnet: get_network_params_default(Network::Testnet), + signet: get_network_params_default(Network::Signet), + mainnet: get_network_params_default(Network::Bitcoin), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct NetworkParams { + host: String, + port: u16, + dir_path: String, + db_field: String, + cookie_file: String, + rpc_user: String, + rpc_pass: String, +} +fn get_network_params(cfg: &MyConfig,network:Network)-> &NetworkParams{ + match network{ + Network::Testnet => &cfg.testnet, + Network::Signet => &cfg.signet, + Network::Regtest => &cfg.regtest, + _ => &cfg.mainnet + } +} +fn get_network_params_default(network:Network) -> NetworkParams{ + match network { + Network::Testnet => NetworkParams{ + host: "http://localhost".to_string(), + port: 18332, + dir_path: "testnet3/".to_string(), + db_field: "testnet".to_string(), + cookie_file: "".to_string(), + rpc_user: "".to_string(), + rpc_pass: "".to_string(), + }, + Network::Signet => NetworkParams{ + host: "http://localhost".to_string(), + port: 18332, + dir_path: "signet/".to_string(), + db_field: "signet".to_string(), + cookie_file: "".to_string(), + rpc_user: "".to_string(), + rpc_pass: "".to_string(), + }, + Network::Regtest => NetworkParams{ + host: "http://localhost".to_string(), + port: 18443, + dir_path: "regtest/".to_string(), + db_field: "regtest".to_string(), + cookie_file: "".to_string(), + rpc_user: "".to_string(), + rpc_pass: "".to_string(), + }, + _ => NetworkParams{ + host: "http://localhost".to_string(), + port: 8332, + dir_path: "".to_string(), + db_field: "bitcoin".to_string(), + cookie_file: "".to_string(), + rpc_user: "".to_string(), + rpc_pass: "".to_string(), + }, + } +} + +fn get_cookie_filename(network: &NetworkParams) ->Result>{ + if network.cookie_file !=""{ + Ok(network.cookie_file.clone()) + }else{ + match env::var_os("HOME") { + Some(home) => { + info!("some home {}",home.to_str().unwrap()); + match home.to_str(){ + Some(home_str) => { + let cookie_file_path = format!("{}/.bitcoin/{}.cookie",home_str, network.dir_path); + + Ok(cookie_file_path) + }, + None => Err("wrong HOME value".into()) + } + }, + None => Err("Please Set HOME environment variable".into()) + } + } +} +fn get_client_from_username(url: &String, network: &NetworkParams) -> Result<(Client,GetBlockchainInfoResult),Box>{ + if network.rpc_user != "" { + match Client::new(&url[..],Auth::UserPass(network.rpc_user.to_string(),network.rpc_pass.to_string())){ + Ok(client) => match client.get_blockchain_info(){ + Ok(bcinfo) => Ok((client,bcinfo)), + Err(err) => Err(err.into()) + } + Err(err)=>Err(err.into()) + } + }else{ + Err("Failed".into()) + } +} +fn get_client_from_cookie(url: &String,network: &NetworkParams)->Result<(Client,GetBlockchainInfoResult),Box>{ + match get_cookie_filename(network){ + Ok(cookie) => { + match Client::new(&url[..], Auth::CookieFile(cookie.into())) { + Ok(client) => match client.get_blockchain_info(){ + Ok(bcinfo) => Ok((client,bcinfo)), + Err(err) => Err(err.into()) + }, + Err(err)=>Err(err.into()) + + } + }, + Err(err)=>Err(err.into()) + } +} +fn get_client(network: &NetworkParams) -> Result<(Client,GetBlockchainInfoResult),Box>{ + let url = format!("{}:{}",network.host,&network.port); + match get_client_from_username(&url,network){ + Ok(client) =>{Ok(client)}, + Err(_) =>{ + match get_client_from_cookie(&url,&network){ + Ok(client)=>{ + Ok(client) + }, + Err(err)=> Err(err.into()) + } + } + } +} +fn main_result(cfg: &MyConfig, network_params: &NetworkParams) -> Result<(), Error> { + + + /*let url = args.next().expect("Usage: "); + let user = args.next().expect("no user given"); + let pass = args.next().expect("no pass given"); + */ + //let network = Network::Regtest + match get_client(network_params){ + Ok((rpc,bcinfo)) => { + info!("connected"); + //let best_block_hash = rpc.get_best_block_hash()?; + //info!("best block hash: {}", best_block_hash); + //let bestblockcount = rpc.get_block_count()?; + //info!("best block height: {}", bestblockcount); + //let best_block_hash_by_height = rpc.get_block_hash(bestblockcount)?; + //info!("best block hash by height: {}", best_block_hash_by_height); + //assert_eq!(best_block_hash_by_height, best_block_hash); + //let from_block= std::cmp::max(0, bestblockcount - 11); + //let mut time_sum:u64=0; + //for i in from_block..bestblockcount{ + // let hash = rpc.get_block_hash(i).unwrap(); + // let block: bitcoin::Block = rpc.get_by_id(&hash).unwrap(); + // time_sum += >::into(block.header.time); + //} + //let average_time = time_sum/11; + info!("median time: {}",bcinfo.median_time); + let average_time = bcinfo.median_time; + let db = sqlite::open(&cfg.db_file).unwrap(); + + let query_tx = db.prepare("SELECT * FROM tbl_tx WHERE network = :network AND status = :status AND ( locktime < :bestblock_height OR locktime > :locktime_threshold AND locktime < :bestblock_time);").unwrap().into_iter(); + //let query_tx = db.prepare("SELECT * FROM tbl_tx where status = :status").unwrap().into_iter(); + let mut pushed_txs:Vec = Vec::new(); + let mut invalid_txs:Vec = Vec::new(); + for row in query_tx.bind::<&[(_, Value)]>(&[ + (":locktime_threshold", (LOCKTIME_THRESHOLD as i64).into()), + (":bestblock_time", (average_time as i64).into()), + (":bestblock_height", (bcinfo.blocks as i64).into()), + (":network", network_params.db_field.clone().into()), + (":status", 0.into()), + ][..]) + .unwrap() + .map(|row| row.unwrap()) + { + let tx = row.read::<&str, _>("tx"); + let txid = row.read::<&str, _>("txid"); + let locktime = row.read::("locktime"); + info!("to be pushed: {}: {}",txid, locktime); + match rpc.send_raw_transaction(tx){ + Ok(o) => { + let mut file = OpenOptions::new() + .append(true) // Set the append option + .create(true) // Create the file if it doesn't exist + .open("valid_txs")?; + let data = format!("{}\t:\t{}\t:\t{}\n",txid,average_time,locktime); + file.write_all(data.as_bytes())?; + drop(file); + + info!("tx: {} pusshata PUSHED\n{}",txid,o); + pushed_txs.push(txid.to_string()); + }, + Err(err) => { + let mut file = OpenOptions::new() + .append(true) // Set the append option + .create(true) // Create the file if it doesn't exist + .open("invalid_txs")?; + let data = format!("{}:\t{}\t:\t{}\t:\t{}\n",txid,err,average_time,locktime); + file.write_all(data.as_bytes())?; + drop(file); + warn!("Error: {}\n{}",err,txid); + invalid_txs.push(txid.to_string()); + }, + }; + } + + if pushed_txs.len() > 0 { + let _ = db.execute(format!("UPDATE tbl_tx SET status = 1 WHERE txid in ('{}');",pushed_txs.join("','"))); + } + if invalid_txs.len() > 0 { + let _ = db.execute(format!("UPDATE tbl_tx SET status = 2 WHERE txid in ('{}');",invalid_txs.join("','"))); + } + } + Err(_)=>{ + panic!("impossible to get client") + } + } + Ok(()) +} + +fn parse_env(cfg: &mut MyConfig){ + match env::var("BAL_PUSHER_ZMQ_LISTENER") { + Ok(value) => { + cfg.zmq_listener = value;}, + Err(_) => {}, + } + match env::var("BAL_PUSHER_REQUEST_FILE") { + Ok(value) => { + cfg.requests_file = value;}, + Err(_) => {}, + } + match env::var("BAL_PUSHER_DB_FILE") { + Ok(value) => { + cfg.db_file = value;}, + Err(_) => {}, + } + match env::var("BAL_PUSHER_BITCOIN_DIR") { + Ok(value) => { + cfg.bitcoin_dir = value;}, + Err(_) => {}, + } + cfg.regtest = parse_env_netconfig(cfg,"regtest"); + cfg.signet = parse_env_netconfig(cfg,"signet"); + cfg.testnet = parse_env_netconfig(cfg,"testnet"); + drop(parse_env_netconfig(cfg,"bitcoin")); + +} +fn parse_env_netconfig(cfg_lock: &mut MyConfig, chain: &str) -> NetworkParams{ +//fn parse_env_netconfig(cfg_lock: &MutexGuard, chain: &str) -> &NetworkParams{ + let cfg = match chain{ + "regtest" => &mut cfg_lock.regtest, + "signet" => &mut cfg_lock.signet, + "testnet" => &mut cfg_lock.testnet, + &_ => &mut cfg_lock.mainnet, + }; + match env::var(format!("BAL_PUSHER_{}_HOST",chain.to_uppercase())) { + Ok(value) => { cfg.host= value; }, + Err(_) => {}, + } + match env::var(format!("BAL_PUSHER_{}_PORT",chain.to_uppercase())) { + Ok(value) => { + match value.parse::(){ + Ok(value) =>{ cfg.port = value.try_into().unwrap(); }, + Err(_) => {}, + } + } + Err(_) => {}, + } + match env::var(format!("BAL_PUSHER_{}_DIR_PATH",chain.to_uppercase())) { + Ok(value) => { cfg.dir_path = value; }, + Err(_) => {}, + } + match env::var(format!("BAL_PUSHER_{}_DB_FIELD",chain.to_uppercase())) { + Ok(value) => { cfg.db_field = value; }, + Err(_) => {}, + } + match env::var(format!("BAL_PUSHER_{}_COOKIE_FILE",chain.to_uppercase())) { + Ok(value) => { + cfg.cookie_file = value; }, + Err(_) => {}, + } + match env::var(format!("BAL_PUSHER_{}_RPC_USER",chain.to_uppercase())) { + Ok(value) => { cfg.rpc_user = value; }, + Err(_) => {}, + } + match env::var(format!("BAL_PUSHER_{}_RPC_PASSWORD",chain.to_uppercase())) { + Ok(value) => { cfg.rpc_pass = value; }, + Err(_) => {}, + } + cfg.clone() +} + +fn get_default_config()-> MyConfig { + let file = confy::get_configuration_file_path("bal-pusher",None).expect("Error while getting path"); + info!("Default configuration file path is: {:#?}", file); + confy::load("bal-pusher",None).expect("cant_load") +} + +fn main(){ + env_logger::init(); + let mut cfg: MyConfig = match env::var("BAL_PUSHER_CONFIG_FILE") { + Ok(value) => { + match confy::load_path(value.to_string()){ + Ok(val) => { + info!("The configuration file path is: {:#?}", value); + val + }, + Err(err) => { + error!("{}",err); + get_default_config() + } + } + }, + Err(_) => { + get_default_config() + }, + }; + + parse_env(&mut cfg); + let mut args = std::env::args(); + let _exe_name = args.next().unwrap(); + let arg_network = match args.next(){ + Some(nargs) => nargs, + None => "bitcoin".to_string() + }; + let network = match arg_network.as_str(){ + + "testnet" => Network::Testnet, + "signet" => Network::Signet, + "regtest" => Network::Regtest, + _ => Network::Bitcoin, + }; + + + debug!("Network: {}",arg_network); + let network_params = get_network_params(&cfg,network); + + + let context = Context::new(); + let socket: Socket = context.socket(zmq::SUB).unwrap(); + + let zmq_address = cfg.zmq_listener.clone(); + socket.connect(&zmq_address).unwrap(); + + socket.set_subscribe(b"").unwrap(); + + let _ = main_result(&cfg,&network_params); + info!("waiting new blocks.."); + let mut last_seq:Vec=[0;4].to_vec(); + loop { + let message = socket.recv_multipart(0).unwrap(); + let topic = message[0].clone(); + let body = message[1].clone(); + let seq = message[2].clone(); + if last_seq >= seq { + continue + } + last_seq = seq; + //let mut sequence_str = "Unknown".to_string(); + /*if seq.len()==4{ + let mut rdr = Cursor::new(seq); + let sequence = rdr.read_u32::().expect("Failed to read integer"); + sequence_str = sequence.to_string(); + }*/ + if topic == b"hashblock" { + info!("NEW BLOCK{}", hex::encode(body)); + //let cfg = cfg.clone(); + let _ = main_result(&cfg,&network_params); + } + thread::sleep(Duration::from_millis(100)); // Sleep for 100ms + } +} +