From 1e67b5bc652fb60b06ce07bf57c087f0e1068710 Mon Sep 17 00:00:00 2001 From: elsirion Date: Sun, 7 Apr 2024 15:06:44 +0200 Subject: [PATCH] feat: sync block times to DB --- Cargo.lock | 456 ++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + schema/v0.sql | 6 + src/federation/mod.rs | 76 ++++++- 4 files changed, 522 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d780ee1..564e182 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,9 +170,9 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.0", "http-body-util", - "hyper", + "hyper 1.2.0", "hyper-util", "itoa", "matchit", @@ -215,7 +215,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.0", "http-body-util", "mime", "pin-project-lite", @@ -241,6 +241,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.1" @@ -265,6 +271,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.10.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" + [[package]] name = "beef" version = "0.5.2" @@ -289,7 +301,7 @@ version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" dependencies = [ - "bech32", + "bech32 0.9.1", "bitcoin_hashes 0.11.0", "core2", "hashbrown 0.8.2", @@ -303,7 +315,7 @@ version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ - "bech32", + "bech32 0.9.1", "bitcoin-private", "bitcoin_hashes 0.12.0", "hex_lit", @@ -311,6 +323,30 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c85783c2fe40083ea54a33aa2f0ba58831d90fcd190f5bdc47e74e84d2a96ae" +dependencies = [ + "bech32 0.10.0-beta", + "bitcoin-internals", + "bitcoin_hashes 0.13.0", + "hex-conservative 0.1.1", + "hex_lit", + "secp256k1 0.28.2", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +dependencies = [ + "serde", +] + [[package]] name = "bitcoin-private" version = "0.1.0" @@ -337,6 +373,17 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative 0.1.1", + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -462,6 +509,22 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "core2" version = "0.3.3" @@ -614,6 +677,15 @@ dependencies = [ "serde", ] +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -639,6 +711,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "esplora-client" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a73e879128c5fcb38abaf0ec53e3310947c6e7b61ce0f1b4cd7a0b8ea1ab0389" +dependencies = [ + "bitcoin 0.31.2", + "hex-conservative 0.2.0", + "log", + "minreq", + "reqwest 0.11.27", + "serde", +] + [[package]] name = "etcetera" version = "0.8.0" @@ -748,7 +834,7 @@ dependencies = [ "async-recursion", "async-trait", "backtrace", - "bech32", + "bech32 0.9.1", "bincode", "bitcoin 0.29.2", "bitcoin 0.30.2", @@ -901,13 +987,14 @@ dependencies = [ "axum", "axum-auth", "dotenv", + "esplora-client", "fedimint-core", "fedimint-ln-common", "fedimint-mint-common", "fedimint-wallet-common", "futures", "hex", - "reqwest", + "reqwest 0.12.2", "serde", "serde_json", "sqlx", @@ -1014,6 +1101,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1237,6 +1339,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.8.2" @@ -1290,6 +1411,21 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + +[[package]] +name = "hex-conservative" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986" +dependencies = [ + "arrayvec", +] + [[package]] name = "hex_fmt" version = "0.3.0" @@ -1351,6 +1487,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.0" @@ -1370,7 +1517,7 @@ dependencies = [ "bytes", "futures-core", "http 1.1.0", - "http-body", + "http-body 1.0.0", "pin-project-lite", ] @@ -1386,6 +1533,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.2.0" @@ -1396,7 +1567,7 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.0", "httparse", "httpdate", "itoa", @@ -1406,6 +1577,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.28", + "rustls 0.21.10", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.26.0" @@ -1414,7 +1599,7 @@ checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", "http 1.1.0", - "hyper", + "hyper 1.2.0", "hyper-util", "rustls 0.22.3", "rustls-pki-types", @@ -1423,6 +1608,19 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.28", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-util" version = "0.1.3" @@ -1433,8 +1631,8 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body", - "hyper", + "http-body 1.0.0", + "hyper 1.2.0", "pin-project-lite", "socket2", "tokio", @@ -1726,7 +1924,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb24878b0f4ef75f020976c886d9ad1503867802329cc963e0ab4623ea3b25c" dependencies = [ - "bech32", + "bech32 0.9.1", "bitcoin 0.29.2", "bitcoin_hashes 0.11.0", "lightning", @@ -1854,6 +2052,18 @@ dependencies = [ "adler", ] +[[package]] +name = "minreq" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00a000cf8bbbfb123a9bdc66b61c2885a4bb038df4f2629884caafabeb76b0f9" +dependencies = [ + "base64 0.12.3", + "log", + "serde", + "serde_json", +] + [[package]] name = "mio" version = "0.8.11" @@ -1865,6 +2075,24 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nom" version = "7.1.3" @@ -1963,6 +2191,50 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "overload" version = "0.1.1" @@ -2280,6 +2552,51 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-rustls 0.24.2", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.10", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.24.1", + "tokio-socks", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + [[package]] name = "reqwest" version = "0.12.2" @@ -2291,10 +2608,10 @@ dependencies = [ "futures-core", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.0", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.2.0", + "hyper-rustls 0.26.0", "hyper-util", "ipnet", "js-sys", @@ -2414,6 +2731,7 @@ version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ + "log", "ring 0.17.8", "rustls-webpki 0.101.7", "sct", @@ -2481,6 +2799,15 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2520,6 +2847,17 @@ dependencies = [ "serde", ] +[[package]] +name = "secp256k1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "bitcoin_hashes 0.12.0", + "secp256k1-sys 0.9.2", + "serde", +] + [[package]] name = "secp256k1-sys" version = "0.6.1" @@ -2538,6 +2876,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + [[package]] name = "secp256k1-zkp" version = "0.7.0" @@ -2560,6 +2907,29 @@ dependencies = [ "secp256k1-sys 0.6.1", ] +[[package]] +name = "security-framework" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "send_wrapper" version = "0.4.0" @@ -3050,6 +3420,27 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384595c11a4e2969895cad5a8c4029115f5ab956a9e5ef4de79d11a426e5f20c" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -3153,6 +3544,16 @@ dependencies = [ "syn 2.0.55", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.23.4" @@ -3164,6 +3565,16 @@ dependencies = [ "webpki", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.10", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.25.0" @@ -3175,6 +3586,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +dependencies = [ + "either", + "futures-util", + "thiserror", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -3199,6 +3622,7 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", + "tracing", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b823157..57a5199 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ async-stream = "0.3.5" axum = { version = "0.7.5", features = ["json"] } axum-auth = "0.7.0" dotenv = "0.15.0" +esplora-client = { version = "0.7.0", features = ["async-https-rustls"] } futures = "0.3.30" hex = "0.4.3" reqwest = { version = "0.12.2", default-features = false, features = ["json", "rustls-tls"] } diff --git a/schema/v0.sql b/schema/v0.sql index 68f77ae..8dd1963 100644 --- a/schema/v0.sql +++ b/schema/v0.sql @@ -50,3 +50,9 @@ CREATE TABLE IF NOT EXISTS transaction_outputs ( CREATE INDEX IF NOT EXISTS federation_outputs ON transaction_outputs(federation_id); CREATE INDEX IF NOT EXISTS federation_transaction_outputs ON transaction_outputs(federation_id, txid); CREATE INDEX IF NOT EXISTS federation_output_kinds ON transaction_outputs(federation_id, kind); + +CREATE TABLE IF NOT EXISTS block_times ( + block_height INTEGER PRIMARY KEY, + timestamp INTEGER NOT NULL +); +CREATE INDEX IF NOT EXISTS block_times_time ON block_times(timestamp); diff --git a/src/federation/mod.rs b/src/federation/mod.rs index bdc4371..d95f91c 100644 --- a/src/federation/mod.rs +++ b/src/federation/mod.rs @@ -31,8 +31,9 @@ use sqlx::any::install_default_drivers; use sqlx::pool::PoolConnection; use sqlx::postgres::any::AnyTypeInfoKind; use sqlx::{query, query_as, Any, AnyPool, Column, Connection, Database, Row, Transaction}; +use tokio::time::sleep; use tracing::log::info; -use tracing::{debug, error}; +use tracing::{debug, error, warn}; use crate::config::get_decoders; use crate::federation::db::Federation; @@ -277,6 +278,9 @@ impl FederationObserver { slf.spawn_observer(federation).await; } + slf.task_group + .spawn_cancellable("fetch block times", Self::fetch_block_times(slf.clone())); + Ok(slf) } @@ -357,6 +361,76 @@ impl FederationObserver { Ok(()) } + async fn fetch_block_times(self) { + const SLEEP_SECS: u64 = 10; + loop { + if let Err(e) = self.fetch_block_times_inner().await { + warn!("Error while fetching block times: {e:?}"); + } + info!("Block sync finished, waiting {SLEEP_SECS} seconds"); + sleep(Duration::from_secs(SLEEP_SECS)).await; + } + } + + async fn fetch_block_times_inner(&self) -> anyhow::Result<()> { + let builder = esplora_client::Builder::new("https://blockstream.info/api"); + let esplora_client = builder.build_async()?; + + // TODO: find a better way to pre-seed the DB so we don't have to bother + // blockstream.info Block 820k was mined Dec 2023, afaik there are no + // compatible federations older than that + let next_block_height = + (self.last_fetched_block_height().await?.unwrap_or(820_000) + 1) as u32; + let current_block_height = esplora_client.get_height().await?; + + info!("Fetching block times for block {next_block_height} to {current_block_height}"); + + let mut block_stream = futures::stream::iter(next_block_height..=current_block_height) + .map(move |block_height| { + let esplora_client_inner = esplora_client.clone(); + async move { + let block_hash = esplora_client_inner.get_block_hash(block_height).await?; + let block = esplora_client_inner.get_header_by_hash(&block_hash).await?; + + Result::<_, anyhow::Error>::Ok((block_height, block)) + } + }) + .buffered(4); + + let mut timer = SystemTime::now(); + let mut last_log_height = next_block_height; + while let Some((block_height, block)) = block_stream.next().await.transpose()? { + query("INSERT INTO block_times VALUES ($1, $2)") + .bind(block_height as i64) + .bind(block.time as i64) + .execute(self.connection().await?.as_mut()) + .await?; + + // TODO: write abstraction + let elapsed = timer.elapsed().unwrap_or_default(); + if elapsed >= Duration::from_secs(5) { + let blocks_synced = block_height - last_log_height; + let rate = (blocks_synced as f64) / elapsed.as_secs_f64(); + info!("Synced up to block {block_height}, processed {blocks_synced} blocks at a rate of {rate:.2} blocks/s"); + timer = SystemTime::now(); + last_log_height = block_height; + } + } + + Ok(()) + } + + async fn last_fetched_block_height(&self) -> anyhow::Result> { + let row = query("SELECT MAX(block_height) AS max_height FROM block_times") + .fetch_one(self.connection().await?.as_mut()) + .await?; + + Ok(row + .try_get::("max_height") + .ok() + .map(|max_height| max_height as u64)) + } + async fn observe_federation( self, federation_id: FederationId,