From 84ff51397758177bc7a745d7350f83bc2c672740 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 7 Nov 2023 15:08:22 +0300 Subject: [PATCH 1/8] Add config and simple cache for blockscout client --- blockscout-ens/Cargo.lock | 80 ++++++++++++++++- blockscout-ens/bens-logic/Cargo.toml | 1 + .../bens-logic/examples/resolve_benchmark.rs | 4 +- .../src/subgraphs_reader/blockscout.rs | 90 ++++++++++++------- .../bens-logic/src/subgraphs_reader/reader.rs | 48 +++++----- .../src/subgraphs_reader/test_helpers.rs | 2 +- blockscout-ens/bens-server/src/server.rs | 21 ++++- blockscout-ens/bens-server/src/settings.rs | 47 +++++++--- 8 files changed, 215 insertions(+), 78 deletions(-) diff --git a/blockscout-ens/Cargo.lock b/blockscout-ens/Cargo.lock index 1c44673cf..6ba360551 100644 --- a/blockscout-ens/Cargo.lock +++ b/blockscout-ens/Cargo.lock @@ -599,6 +599,7 @@ name = "bens-logic" version = "0.1.0" dependencies = [ "anyhow", + "cached", "chrono", "ethers", "futures", @@ -925,6 +926,42 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "cached" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c8c50262271cdf5abc979a5f76515c234e764fa025d1ba4862c0f0bcda0e95" +dependencies = [ + "ahash 0.8.3", + "async-trait", + "cached_proc_macro", + "cached_proc_macro_types", + "futures", + "hashbrown 0.14.1", + "instant", + "once_cell", + "thiserror", + "tokio", +] + +[[package]] +name = "cached_proc_macro" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c878c71c2821aa2058722038a59a67583a4240524687c6028571c9b395ded61f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" + [[package]] name = "camino" version = "1.1.6" @@ -1326,14 +1363,38 @@ dependencies = [ "cipher", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -1350,13 +1411,24 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.38", ] @@ -4839,7 +4911,7 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.38", diff --git a/blockscout-ens/bens-logic/Cargo.toml b/blockscout-ens/bens-logic/Cargo.toml index c6706a724..dd3122359 100644 --- a/blockscout-ens/bens-logic/Cargo.toml +++ b/blockscout-ens/bens-logic/Cargo.toml @@ -22,6 +22,7 @@ reqwest-retry = "0.3" lazy_static = "1.4" tracing = "0.1" futures = "0.3" +cached = { version = "0.46.1", features = ["proc_macro", "tokio", "async", "async_tokio_rt_multi_thread"] } [dependencies.sqlx] version = "0.7" diff --git a/blockscout-ens/bens-logic/examples/resolve_benchmark.rs b/blockscout-ens/bens-logic/examples/resolve_benchmark.rs index 39c664d3b..d36dc39ec 100644 --- a/blockscout-ens/bens-logic/examples/resolve_benchmark.rs +++ b/blockscout-ens/bens-logic/examples/resolve_benchmark.rs @@ -26,9 +26,9 @@ async fn main() -> Result<(), anyhow::Error> { .connect(&url) .await?, ); - let eth_client = BlockscoutClient::new("https://eth.blockscout.com".parse().unwrap()); + let eth_client = BlockscoutClient::new("https://eth.blockscout.com".parse().unwrap(), 5, 30); let rootstock_client = - BlockscoutClient::new("https://rootstock.blockscout.com".parse().unwrap()); + BlockscoutClient::new("https://rootstock.blockscout.com".parse().unwrap(), 5, 30); let clients: HashMap = HashMap::from_iter([(1, eth_client), (30, rootstock_client)]); let reader = SubgraphReader::initialize(pool.clone(), clients).await?; diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs index 771eb9623..24bee7e91 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs @@ -1,27 +1,34 @@ +use cached::proc_macro::cached; use ethers::types::TxHash; use futures::StreamExt; -use reqwest::StatusCode; use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware}; -use serde::{de::DeserializeOwned, Deserialize}; -use std::sync::Arc; +use std::{collections::HashMap, fmt::Debug, sync::Arc}; use tracing::instrument; -const MAX_REQUESTS_BATCH: usize = 5; - #[derive(Debug, Clone)] pub struct BlockscoutClient { url: url::Url, inner: ClientWithMiddleware, + max_concurrent_requests: usize, } impl BlockscoutClient { - pub fn new(url: url::Url) -> Self { + pub fn new(url: url::Url, max_concurrent_requests: usize, timeout_seconds: u64) -> Self { let retry_policy = ExponentialBackoff::builder().build_with_max_retries(3); - let client = ClientBuilder::new(reqwest::Client::new()) - .with(RetryTransientMiddleware::new_with_policy(retry_policy)) - .build(); - Self { url, inner: client } + let client = ClientBuilder::new( + reqwest::Client::builder() + .timeout(std::time::Duration::from_secs(timeout_seconds)) + .build() + .expect("valid client"), + ) + .with(RetryTransientMiddleware::new_with_policy(retry_policy)) + .build(); + Self { + url, + inner: client, + max_concurrent_requests, + } } pub fn url(&self) -> &url::Url { @@ -29,12 +36,14 @@ impl BlockscoutClient { } } -#[derive(Debug, Deserialize)] +use reqwest::StatusCode; +use serde::{de::DeserializeOwned, Deserialize}; +#[derive(Debug, Clone, Deserialize)] pub struct TransactionFrom { pub hash: ethers::types::Address, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] pub struct Transaction { pub timestamp: String, pub method: Option, @@ -43,12 +52,12 @@ pub struct Transaction { pub block: i64, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] pub struct Message { pub message: String, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Response { Ok(T), NotFound(String), @@ -59,7 +68,7 @@ impl Response where T: DeserializeOwned, { - async fn try_from_reqwest_response( + pub async fn try_from_reqwest_response( response: reqwest::Response, ) -> reqwest_middleware::Result { let response = match response.status() { @@ -71,38 +80,57 @@ where } } +#[cached( + key = "String", + convert = r#"{ format!("{transaction_hash:#}") }"#, + result = true, + time = 86_400, // 24 * 60 * 60 seconds + size = 50_000, + sync_writes = true, +)] +pub async fn cached_transaction( + client: &BlockscoutClient, + transaction_hash: ðers::types::TxHash, +) -> reqwest_middleware::Result> { + let response = client + .inner + .get( + client + .url + .join(&format!("/api/v2/transactions/{transaction_hash:#x}")) + .unwrap(), + ) + .send() + .await?; + Response::try_from_reqwest_response(response).await +} + impl BlockscoutClient { - #[instrument(name = "blockscout_api:transaction", skip_all, err, level = "debug")] + #[instrument(name = "blockscout_api:transaction", skip(self), err, level = "debug")] pub async fn transaction( &self, transaction_hash: ðers::types::TxHash, ) -> reqwest_middleware::Result> { - let response = self - .inner - .get( - self.url - .join(&format!("/api/v2/transactions/{transaction_hash:#x}")) - .unwrap(), - ) - .send() - .await?; - Response::try_from_reqwest_response(response).await + cached_transaction(self, transaction_hash).await } pub async fn transactions_batch( self: Arc, - transaction_hashes: Vec<ðers::types::TxHash>, - ) -> reqwest_middleware::Result)>> { - let fetches = futures::stream::iter(transaction_hashes.into_iter().cloned().map(|hash| { + transaction_hashes: impl IntoIterator, + ) -> reqwest_middleware::Result>> { + let fetches = futures::stream::iter(transaction_hashes.into_iter().map(|hash| { let client = self.clone(); async move { let result = client.transaction(&hash).await; result.map(|r| (TxHash::clone(&hash), r)) } })) - .buffer_unordered(MAX_REQUESTS_BATCH) + .buffer_unordered(self.max_concurrent_requests) .collect::>(); - let result = fetches.await.into_iter().collect::, _>>()?; + let result = fetches + .await + .into_iter() + .collect::, _>>()?; Ok(result) } } diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs index 5d51bb474..14e0e7e36 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs @@ -154,38 +154,40 @@ async fn events_from_transactions( client: Arc, txns: Vec, ) -> Result, SubgraphReadError> { - let txns = txns - .into_iter() - .map(|t| (TxHash::from_slice(t.transaction_id.as_slice()), t)) - .collect::>(); - let transactions = client - .transactions_batch(txns.keys().collect()) + let txn_ids: Vec = txns + .iter() + .map(|t| TxHash::from_slice(t.transaction_id.as_slice())) + .collect(); + let mut blockscout_txns = client + .transactions_batch(txn_ids) .await - .map_err(|e| SubgraphReadError::Internal(e.to_string()))?; - - let mut events: Vec = transactions + .map_err(|e| SubgraphReadError::Internal(e.to_string()))? .into_iter() - .filter_map(|(tx_hash, t)| match t { - blockscout::Response::Ok(t) => Some(DomainEvent { - transaction_hash: t.hash, - block_number: t.block, - timestamp: t.timestamp, - from_address: t.from.hash, - method: t.method, - actions: txns - .get(&t.hash) - .map(|d| d.actions.clone()) - .unwrap_or_default(), - }), + .filter_map(|(hash, result)| match result { + blockscout::Response::Ok(t) => Some((hash, t)), e => { tracing::warn!( - "invalid response from blockscout transaction '{tx_hash:#x}' api: {e:?}" + "invalid response from blockscout transaction '{hash:#x}' api: {e:?}" ); None } }) + .collect::>(); + let events: Vec = txns + .into_iter() + .filter_map(|txn| { + blockscout_txns + .remove(&TxHash::from_slice(txn.transaction_id.as_slice())) + .map(|t| DomainEvent { + transaction_hash: t.hash, + block_number: t.block, + timestamp: t.timestamp, + from_address: t.from.hash, + method: t.method, + actions: txn.actions, + }) + }) .collect::>(); - events.sort_by_key(|event| event.block_number); Ok(events) } diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/test_helpers.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/test_helpers.rs index 14bc33d36..6ff65a617 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/test_helpers.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/test_helpers.rs @@ -84,6 +84,6 @@ pub async fn mocked_blockscout_clients() -> HashMap { } let url = mock_server.uri().parse().unwrap(); - let client = BlockscoutClient::new(url); + let client = BlockscoutClient::new(url, 1, 30); HashMap::from_iter([(1, client)]) } diff --git a/blockscout-ens/bens-server/src/server.rs b/blockscout-ens/bens-server/src/server.rs index 8a36aece8..5b8e8d60a 100644 --- a/blockscout-ens/bens-server/src/server.rs +++ b/blockscout-ens/bens-server/src/server.rs @@ -9,7 +9,7 @@ use bens_proto::blockscout::bens::v1::{ domains_extractor_server::DomainsExtractorServer, health_actix::route_health, health_server::HealthServer, }; -use blockscout_service_launcher::{launcher, launcher::LaunchSettings, tracing}; +use blockscout_service_launcher::{launcher, launcher::LaunchSettings}; use sqlx::postgres::PgPoolOptions; use std::sync::Arc; @@ -40,7 +40,11 @@ impl launcher::HttpRouter for Router { } pub async fn run(settings: Settings) -> Result<(), anyhow::Error> { - tracing::init_logs(SERVICE_NAME, &settings.tracing, &settings.jaeger)?; + blockscout_service_launcher::tracing::init_logs( + SERVICE_NAME, + &settings.tracing, + &settings.jaeger, + )?; let health = Arc::new(HealthService::default()); @@ -54,9 +58,20 @@ pub async fn run(settings: Settings) -> Result<(), anyhow::Error> { .blockscout .networks .into_iter() - .map(|(id, network)| (id, BlockscoutClient::new(network.url))) + .map(|(id, network)| { + ( + id, + BlockscoutClient::new( + network.url, + settings.blockscout.max_concurrent_requests, + settings.blockscout.timeout, + ), + ) + }) .collect(); + tracing::info!("found blockscout clients from config: {blockscout_clients:?}"); + let subgraph_reader = SubgraphReader::initialize(pool, blockscout_clients) .await .context("failed to initialize subgraph-reader")?; diff --git a/blockscout-ens/bens-server/src/settings.rs b/blockscout-ens/bens-server/src/settings.rs index 72a3bd020..f31815b13 100644 --- a/blockscout-ens/bens-server/src/settings.rs +++ b/blockscout-ens/bens-server/src/settings.rs @@ -42,26 +42,45 @@ pub struct NetworkConfig { #[derive(Debug, Clone, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields, default)] pub struct BlockscoutSettings { + #[serde(default = "default_networks")] pub networks: HashMap, + #[serde(default = "default_max_concurrent_requests")] + pub max_concurrent_requests: usize, + #[serde(default = "default_blockscout_timeout")] + pub timeout: u64, +} + +fn default_networks() -> HashMap { + HashMap::from_iter([ + ( + 1, + NetworkConfig { + url: "https://eth.blockscout.com".parse().unwrap(), + }, + ), + ( + 30, + NetworkConfig { + url: "https://rootstock.blockscout.com".parse().unwrap(), + }, + ), + ]) +} + +fn default_max_concurrent_requests() -> usize { + 5 +} + +fn default_blockscout_timeout() -> u64 { + 30 } impl Default for BlockscoutSettings { fn default() -> Self { Self { - networks: HashMap::from_iter([ - ( - 1, - NetworkConfig { - url: "https://eth.blockscout.com".parse().unwrap(), - }, - ), - ( - 30, - NetworkConfig { - url: "https://rootstock.blockscout.com".parse().unwrap(), - }, - ), - ]), + networks: default_networks(), + max_concurrent_requests: default_max_concurrent_requests(), + timeout: default_blockscout_timeout(), } } } From f0112a48e6dba28bb9c6cd5ac485dcab62300a0e Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 7 Nov 2023 17:29:03 +0300 Subject: [PATCH 2/8] Add test utils --- blockscout-ens/Cargo.toml | 1 + blockscout-ens/bens-logic/Cargo.toml | 6 +++++- blockscout-ens/bens-logic/src/lib.rs | 2 ++ blockscout-ens/bens-logic/src/subgraphs_reader/mod.rs | 2 -- blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs | 2 +- .../{subgraphs_reader/test_helpers.rs => test_utils.rs} | 2 +- blockscout-ens/bens-server/Cargo.toml | 4 ++++ blockscout-ens/bens-server/tests/domains.rs | 7 +++++++ 8 files changed, 21 insertions(+), 5 deletions(-) rename blockscout-ens/bens-logic/src/{subgraphs_reader/test_helpers.rs => test_utils.rs} (98%) create mode 100644 blockscout-ens/bens-server/tests/domains.rs diff --git a/blockscout-ens/Cargo.toml b/blockscout-ens/Cargo.toml index 8d3430d61..4966c2aff 100644 --- a/blockscout-ens/Cargo.toml +++ b/blockscout-ens/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "bens-logic", diff --git a/blockscout-ens/bens-logic/Cargo.toml b/blockscout-ens/bens-logic/Cargo.toml index dd3122359..712fa8588 100644 --- a/blockscout-ens/bens-logic/Cargo.toml +++ b/blockscout-ens/bens-logic/Cargo.toml @@ -23,6 +23,7 @@ lazy_static = "1.4" tracing = "0.1" futures = "0.3" cached = { version = "0.46.1", features = ["proc_macro", "tokio", "async", "async_tokio_rt_multi_thread"] } +wiremock = {version = "0.5", optional = true } [dependencies.sqlx] version = "0.7" @@ -37,8 +38,11 @@ features = [ [dev-dependencies] pretty_assertions = "1.4.0" -wiremock = "0.5" tracing-subscriber = {version = "0.3", features = ["env-filter"]} [[example]] name = "resolve_benchmark" + +[features] +default = [] +test-utils = ["dep:wiremock"] diff --git a/blockscout-ens/bens-logic/src/lib.rs b/blockscout-ens/bens-logic/src/lib.rs index 961a9e966..d2ac4d9df 100644 --- a/blockscout-ens/bens-logic/src/lib.rs +++ b/blockscout-ens/bens-logic/src/lib.rs @@ -1,3 +1,5 @@ pub mod entity; pub mod hash_name; pub mod subgraphs_reader; +#[cfg(feature = "test-utils")] +pub mod test_utils; diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/mod.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/mod.rs index c59ecb8bc..60a75aaa3 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/mod.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/mod.rs @@ -2,8 +2,6 @@ pub mod blockscout; mod reader; mod schema_selector; mod sql; -#[cfg(test)] -mod test_helpers; mod types; pub use reader::{SubgraphReadError, SubgraphReader}; diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs index 14e0e7e36..2f76caced 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs @@ -193,7 +193,7 @@ async fn events_from_transactions( #[cfg(test)] mod tests { - use crate::subgraphs_reader::test_helpers::mocked_blockscout_clients; + use crate::test_utils::mocked_blockscout_clients; use super::*; use ethers::types::Address; diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/test_helpers.rs b/blockscout-ens/bens-logic/src/test_utils.rs similarity index 98% rename from blockscout-ens/bens-logic/src/subgraphs_reader/test_helpers.rs rename to blockscout-ens/bens-logic/src/test_utils.rs index 6ff65a617..f5189f422 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/test_helpers.rs +++ b/blockscout-ens/bens-logic/src/test_utils.rs @@ -1,4 +1,4 @@ -use super::blockscout::BlockscoutClient; +use crate::subgraphs_reader::blockscout::BlockscoutClient; use ethers::types::TxHash; use std::collections::HashMap; use wiremock::{ diff --git a/blockscout-ens/bens-server/Cargo.toml b/blockscout-ens/bens-server/Cargo.toml index c01efe1cc..d32356f08 100644 --- a/blockscout-ens/bens-server/Cargo.toml +++ b/blockscout-ens/bens-server/Cargo.toml @@ -32,3 +32,7 @@ features = [ "runtime-tokio", "tls-rustls", ] + + +[dev-dependencies] +bens-logic = { path = "../bens-logic", features = ["test-utils"] } diff --git a/blockscout-ens/bens-server/tests/domains.rs b/blockscout-ens/bens-server/tests/domains.rs new file mode 100644 index 000000000..1f357b6c4 --- /dev/null +++ b/blockscout-ens/bens-server/tests/domains.rs @@ -0,0 +1,7 @@ +use sqlx::PgPool; +use bens_logic::test_helpers::*; + +#[sqlx::test(migrations = "../bens-logic/tests/migrations")] +async fn it_works(pool: PgPool) { + let clients = mocked_blockscout_clients().await; +} From 1afa68b8db09f64a226b780194c8a362ff7f8065 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 7 Nov 2023 20:20:08 +0300 Subject: [PATCH 3/8] Add tests --- blockscout-ens/Cargo.lock | 3 + .../bens-logic/src/subgraphs_reader/reader.rs | 2 +- .../20231019103631_push_mock_data.sql | 12 +- blockscout-ens/bens-proto/build.rs | 8 + blockscout-ens/bens-server/Cargo.toml | 3 + .../bens-server/tests/config.test.toml | 8 + blockscout-ens/bens-server/tests/domains.rs | 284 +++++++++++++++++- blockscout-ens/{bens-logic => }/justfile | 0 8 files changed, 311 insertions(+), 9 deletions(-) create mode 100644 blockscout-ens/bens-server/tests/config.test.toml rename blockscout-ens/{bens-logic => }/justfile (100%) diff --git a/blockscout-ens/Cargo.lock b/blockscout-ens/Cargo.lock index 6ba360551..b5b4743ab 100644 --- a/blockscout-ens/Cargo.lock +++ b/blockscout-ens/Cargo.lock @@ -651,6 +651,7 @@ dependencies = [ "config", "ethers", "hex", + "pretty_assertions", "serde", "serde_json", "sqlx", @@ -658,6 +659,7 @@ dependencies = [ "tokio", "tonic", "tracing", + "tracing-subscriber", "url", ] @@ -750,6 +752,7 @@ dependencies = [ "opentelemetry", "opentelemetry-jaeger", "prometheus", + "reqwest", "sea-orm", "sea-orm-migration", "serde", diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs index 2f76caced..9054e0d0d 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/reader.rs @@ -193,7 +193,7 @@ async fn events_from_transactions( #[cfg(test)] mod tests { - use crate::test_utils::mocked_blockscout_clients; + use crate::test_utils::mocked_blockscout_clients; use super::*; use ethers::types::Address; diff --git a/blockscout-ens/bens-logic/tests/migrations/20231019103631_push_mock_data.sql b/blockscout-ens/bens-logic/tests/migrations/20231019103631_push_mock_data.sql index 46ce0e999..3598d8ad4 100644 --- a/blockscout-ens/bens-logic/tests/migrations/20231019103631_push_mock_data.sql +++ b/blockscout-ens/bens-logic/tests/migrations/20231019103631_push_mock_data.sql @@ -33,12 +33,12 @@ VALUES (18, '[3937005,)', '0x0d086030cbd65bc7815cf758e586439ad1ea9d0b6fee3b3d757fde1f9a514b49', 'bloomberg.eth', 'bloomberg', '\xdeb000fbbe0f3de1f86bcaf4f433c09bacbaa44bdc4b26bc13244743fd277804', '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', 0, NULL, NULL, NULL, false, 1498554162, '0x00f2aaa26fa8a6aada2afa7f545b141c8aca983f', NULL, NULL, NULL), (19, '[3793505,)', '0x2f0af22f275fd8ad35453e8601964f8b9b492e52567a4ec93418381ae1e721f7', 'booking.eth', 'booking', '\x5c404fe0d68b7f2cbf78d2796785dfbc224cc281de624ac154aa97e8b83810e1', '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', 0, NULL, NULL, NULL, false, 1496160511, '0x2014e01eefe653901a7721fa908b0055f2eb84dc', NULL, NULL, NULL), (20, '[3870845,)', '0x7e1d0d7c24e1d7f82fb85f66a0c47b7c9dcaa290803b81e0f7bb7a76dcdbaf3f', 'brandbucket.eth', 'brandbucket', '\x942dd1cc8e267c4992feb18791fbfa374b39cd9843c5a915f8c27a49c527ee39', '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', 0, NULL, NULL, NULL, false, 1497433469, '0x4c759813ad1386bed27ffae9e4815e3630cca312', NULL, NULL, NULL), -(21,'[13294741,)','0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1','test.eth','test','0x9C22FF5F21F0B81B113E63F7DB6DA94FEDEF11B2119B4088B89664FB9A3CB658','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0xeefb13c7d42efcc655e528da6d6f7bbcf9a2251d','0x226159d592e2b063810a10ebf6dcbada94ed68b8-0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1',NULL,true,1571902007,'0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b','0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b',NULL,1737441815), -(22,'[10498481,13294741)','0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1','test.eth','test','0x9C22FF5F21F0B81B113E63F7DB6DA94FEDEF11B2119B4088B89664FB9A3CB658','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,NULL,'0x226159d592e2b063810a10ebf6dcbada94ed68b8-0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1',NULL,true,1571902007,'0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b','0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b',NULL,1737441815), -(23,'[13695732,)','0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835','vitalik.eth','vitalik','0xAF2CAA1C2CA1D027F1AC823B529D0A67CD144264B2789FA2EA4D63A67C7103CC','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0xd8da6bf26964af9d7eed9e03e53415d37aa96045','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835',NULL,true,1497775154,'0xd8da6bf26964af9d7eed9e03e53415d37aa96045','0xd8da6bf26964af9d7eed9e03e53415d37aa96045',NULL,1975009824), -(24,'[13942919,)','0x68b620f61c87062cf680144f898582a631c90e39dd1badb35c241be0a7284fff','sashaxyz.eth','sashaxyz','0x5F5E95F7A849C60A514EB073C6FAFE97E835C0EE7B6DC15FC9D7DAA9E86F1A25','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0xd8da6bf26964af9d7eed9e03e53415d37aa96045','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0x68b620f61c87062cf680144f898582a631c90e39dd1badb35c241be0a7284fff',NULL,true,1640341437,'0x66a6f7744ce4dea450910b81a7168588f992eafb','0x66a6f7744ce4dea450910b81a7168588f992eafb',NULL,1711231341), -(25,'[12439863,)','0x86f0774249ae1b7dcb5873ac0ada288d09ec4b3bf8bbf672b67726793797142e','expired.eth','expired','0x64CA1AE50619F7F4AB23F4C22C6B85B70CFC49C072D731BE4F91487F95764C93','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0x9f7f7ddbfb8e14d1756580ba8037530da0880b99','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0x86f0774249ae1b7dcb5873ac0ada288d09ec4b3bf8bbf672b67726793797142e',NULL,true,1496998132,'0x9f7f7ddbfb8e14d1756580ba8037530da0880b99','0x9f7f7ddbfb8e14d1756580ba8037530da0880b99',NULL,1688547600), -(26,'[13601083,)','0x5d438d292de31e08576d5bcd8a93aa41b401b9d9aeaba57da1a32c003e5fd5f5','wa🇬🇲i.eth','wa🇬🇲i','0x66F484A3530B784F2347DE3459625585DA2B38B429596364B98186B1C5E30180','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0x9c996076a85b46061d9a70ff81f013853a86b619','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0x5d438d292de31e08576d5bcd8a93aa41b401b9d9aeaba57da1a32c003e5fd5f5',NULL,true,1636717006,'0x9c996076a85b46061d9a70ff81f013853a86b619','0x9c996076a85b46061d9a70ff81f013853a86b619',NULL,1802277766) +(21,'[13294741,)','0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1','test.eth','test','\x9C22FF5F21F0B81B113E63F7DB6DA94FEDEF11B2119B4088B89664FB9A3CB658','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0xeefb13c7d42efcc655e528da6d6f7bbcf9a2251d','0x226159d592e2b063810a10ebf6dcbada94ed68b8-0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1',NULL,true,1571902007,'0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b','0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b',NULL,1737441815), +(22,'[10498481,13294741)','0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1','test.eth','test','\x9C22FF5F21F0B81B113E63F7DB6DA94FEDEF11B2119B4088B89664FB9A3CB658','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,NULL,'0x226159d592e2b063810a10ebf6dcbada94ed68b8-0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1',NULL,true,1571902007,'0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b','0xbd6bbe64bf841b81fc5a6e2b760029e316f2783b',NULL,1737441815), +(23,'[13695732,)','0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835','vitalik.eth','vitalik','\xAF2CAA1C2CA1D027F1AC823B529D0A67CD144264B2789FA2EA4D63A67C7103CC','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0xd8da6bf26964af9d7eed9e03e53415d37aa96045','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835',NULL,true,1497775154,'0xd8da6bf26964af9d7eed9e03e53415d37aa96045','0x220866b1a2219f40e72f5c628b65d54268ca3a9d',NULL,1975009824), +(24,'[13942919,)','0x68b620f61c87062cf680144f898582a631c90e39dd1badb35c241be0a7284fff','sashaxyz.eth','sashaxyz','\x5F5E95F7A849C60A514EB073C6FAFE97E835C0EE7B6DC15FC9D7DAA9E86F1A25','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0xd8da6bf26964af9d7eed9e03e53415d37aa96045','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0x68b620f61c87062cf680144f898582a631c90e39dd1badb35c241be0a7284fff',NULL,true,1640341437,'0x66a6f7744ce4dea450910b81a7168588f992eafb','0x66a6f7744ce4dea450910b81a7168588f992eafb',NULL,1711231341), +(25,'[12439863,)','0x86f0774249ae1b7dcb5873ac0ada288d09ec4b3bf8bbf672b67726793797142e','expired.eth','expired','\x64CA1AE50619F7F4AB23F4C22C6B85B70CFC49C072D731BE4F91487F95764C93','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0x9f7f7ddbfb8e14d1756580ba8037530da0880b99','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0x86f0774249ae1b7dcb5873ac0ada288d09ec4b3bf8bbf672b67726793797142e',NULL,true,1496998132,'0x9f7f7ddbfb8e14d1756580ba8037530da0880b99','0x9f7f7ddbfb8e14d1756580ba8037530da0880b99',NULL,1688547600), +(26,'[13601083,)','0x5d438d292de31e08576d5bcd8a93aa41b401b9d9aeaba57da1a32c003e5fd5f5','wa🇬🇲i.eth','wa🇬🇲i','\x66F484A3530B784F2347DE3459625585DA2B38B429596364B98186B1C5E30180','0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae',0,'0x9c996076a85b46061d9a70ff81f013853a86b619','0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41-0x5d438d292de31e08576d5bcd8a93aa41b401b9d9aeaba57da1a32c003e5fd5f5',NULL,true,1636717006,'0x9c996076a85b46061d9a70ff81f013853a86b619','0x9c996076a85b46061d9a70ff81f013853a86b619',NULL,1802277766) ; -- vitalik.eth events diff --git a/blockscout-ens/bens-proto/build.rs b/blockscout-ens/bens-proto/build.rs index 51b9c6259..95e722bb6 100644 --- a/blockscout-ens/bens-proto/build.rs +++ b/blockscout-ens/bens-proto/build.rs @@ -34,6 +34,10 @@ fn compile( ".blockscout.bens.v1.LookupDomainNameRequest.order", "#[serde(default)]" ) + .field_attribute( + ".blockscout.bens.v1.LookupDomainNameRequest.only_active", + "#[serde(default)]" + ) .field_attribute( ".blockscout.bens.v1.LookupAddressRequest.sort", "#[serde(default)]" @@ -42,6 +46,10 @@ fn compile( ".blockscout.bens.v1.LookupAddressRequest.order", "#[serde(default)]" ) + .field_attribute( + ".blockscout.bens.v1.LookupAddressRequest.only_active", + "#[serde(default)]" + ) ; config.compile_protos(protos, includes)?; Ok(()) diff --git a/blockscout-ens/bens-server/Cargo.toml b/blockscout-ens/bens-server/Cargo.toml index d32356f08..df0666d6d 100644 --- a/blockscout-ens/bens-server/Cargo.toml +++ b/blockscout-ens/bens-server/Cargo.toml @@ -36,3 +36,6 @@ features = [ [dev-dependencies] bens-logic = { path = "../bens-logic", features = ["test-utils"] } +blockscout-service-launcher = { version = "0.9.0", features = [ "database-0_12", "test-server" ] } +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +pretty_assertions = "1.4.0" diff --git a/blockscout-ens/bens-server/tests/config.test.toml b/blockscout-ens/bens-server/tests/config.test.toml new file mode 100644 index 000000000..3aaf15567 --- /dev/null +++ b/blockscout-ens/bens-server/tests/config.test.toml @@ -0,0 +1,8 @@ +[metrics] +enabled = false + +[jaeger] +enabled = false + +[tracing] +enabled = false \ No newline at end of file diff --git a/blockscout-ens/bens-server/tests/domains.rs b/blockscout-ens/bens-server/tests/domains.rs index 1f357b6c4..b295b9a3a 100644 --- a/blockscout-ens/bens-server/tests/domains.rs +++ b/blockscout-ens/bens-server/tests/domains.rs @@ -1,7 +1,287 @@ +use bens_logic::test_utils::*; +use bens_server::{NetworkConfig, Settings}; +use blockscout_service_launcher::{ + launcher::ConfigSettings, + test_server::{get_test_server_settings, init_server, send_get_request, send_post_request}, +}; +use pretty_assertions::assert_eq; +use serde_json::{json, Value}; use sqlx::PgPool; -use bens_logic::test_helpers::*; +use url::Url; #[sqlx::test(migrations = "../bens-logic/tests/migrations")] -async fn it_works(pool: PgPool) { +async fn basic_domain_extracting_works(pool: PgPool) { + let postgres_url = std::env::var("DATABASE_URL").expect("env should be here from sqlx::test"); + let db_url = format!( + "{postgres_url}{}", + pool.connect_options().get_database().unwrap() + ); let clients = mocked_blockscout_clients().await; + std::env::set_var("BENS__CONFIG", "./tests/config.test.toml"); + let mut settings = Settings::build().expect("Failed to build settings"); + let (server_settings, base) = get_test_server_settings(); + settings.server = server_settings; + settings.database.url = db_url.parse().unwrap(); + settings.blockscout.networks = clients + .into_iter() + .map(|(id, client)| { + ( + id, + NetworkConfig { + url: client.url().clone(), + }, + ) + }) + .collect(); + + init_server( + || async { + bens_server::run(settings).await.unwrap(); + Ok(()) + }, + &base, + ) + .await; + // Sleep until server will start and calculate all values + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + + // get detailed domain + let request: Value = send_get_request(&base, "/api/v1/1/domains/vitalik.eth").await; + assert_eq!( + request, + json!({ + "expiryDate": "1975009824", + "id": "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835", + "name": "vitalik.eth", + "otherAddresses": { + "137": "f0d485009714ce586358e3761754929904d76b9d", + "60": "d8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "owner": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "registrant": { + "hash": "0x220866b1a2219f40e72f5c628b65d54268ca3a9d", + }, + "registrationDate": "1497775154", + "resolvedAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "tokenId": "0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc", + }) + ); + + // get events + let expected_events = json!([ + { + "action": "finalizeAuction", + "fromAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "timestamp": ("2017-06-18T08:39:14.000000Z"), + "transactionHash": "0xdd16deb1ea750037c3ed1cae5ca20ff9db0e664a5146e5a030137d277a9247f3", + }, + { + "action": "transferRegistrars", + "fromAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "timestamp": ("2019-07-10T05:58:51.000000Z"), + "transactionHash": "0xea30bda97a7e9afcca208d5a648e8ec1e98b245a8884bf589dec8f4aa332fb14", + }, + { + "action": "setAddr", + "fromAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "timestamp": "2019-10-29T13:47:34.000000Z", + "transactionHash": "0x09922ac0caf1efcc8f68ce004f382b46732258870154d8805707a1d4b098dfd0", + }, + { + "action": "migrateAll", + "fromAddress": { + "hash": "0x0904dac3347ea47d208f3fd67402d039a3b99859", + }, + "timestamp": "2020-02-06T18:23:40.000000Z", + "transactionHash": "0xc3f86218c67bee8256b74b9b65d746a40bb5318a8b57948b804dbbbc3d0d7864", + }, + { + "action": "multicall", + "fromAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "timestamp": "2021-02-15T17:19:09.000000Z", + "transactionHash": "0x160ef4492c731ac6b59beebe1e234890cd55d4c556f8847624a0b47125fe4f84", + }, + { + "action": "setResolver", + "fromAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + }, + "timestamp": "2021-02-15T17:19:17.000000Z", + "transactionHash": "0xbb13efab7f1f798f63814a4d184e903e050b38c38aa407f9294079ee7b3110c9", + }, + ]); + let expected_events = expected_events.as_array().unwrap().clone(); + expect_list_results( + &base, + "/api/v1/1/domains/vitalik.eth/events", + "/api/v1/1/domains/vitalik.eth/events?order=DESC", + expected_events.clone(), + ) + .await; + expect_list_results( + &base, + "/api/v1/1/domains/vitalik.eth/events?sort=timestamp", + "/api/v1/1/domains/vitalik.eth/events?sort=timestamp&order=DESC", + expected_events.clone(), + ) + .await; + + // domain lookup + let expected_domains = vec![json!( + { + "id": "0x68b620f61c87062cf680144f898582a631c90e39dd1badb35c241be0a7284fff", + "name": "sashaxyz.eth", + "resolvedAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" + }, + "owner": { + "hash": "0x66a6f7744ce4dea450910b81a7168588f992eafb" + }, + "registrationDate": "1640341437", + "expiryDate": "1711231341" + } + )]; + expect_lookup_results( + &base, + "/api/v1/1/domains:lookup", + json!({ + "name": "sashaxyz.eth" + }), + expected_domains.clone(), + ) + .await; + + // address lookup + let expected_addresses: Vec = vec![json!( + { + "id": "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835", + "name": "vitalik.eth", + "resolvedAddress": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" + }, + "owner": { + "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" + }, + "registrationDate": "1497775154", + "expiryDate": "1975009824" + } + )] + .into_iter() + .chain(expected_domains) + .collect(); + expect_lookup_results( + &base, + "/api/v1/1/addresses:lookup", + json!({ + "address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + "resolvedTo": true, + "ownedBy": true, + }), + expected_addresses.clone(), + ) + .await; + expect_lookup_results( + &base, + "/api/v1/1/addresses:lookup?sort=registration_date", + json!({ + "address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + "resolvedTo": true, + "ownedBy": true, + }), + expected_addresses, + ) + .await; + + // batch address resolving + let response: Value = send_post_request( + &base, + "/api/v1/1/addresses:batch-resolve-names", + &json!({ + "addresses": [ + "0xeefb13c7d42efcc655e528da6d6f7bbcf9a2251d", + "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", + "0x9f7f7ddbfb8e14d1756580ba8037530da0880b99", + "0x9c996076a85b46061d9a70ff81f013853a86b619", + "0xee6c4522aab0003e8d14cd40a6af439055fd2577", + ], + }), + ) + .await; + assert_eq!( + response, + json!({ + "names": { + "0x9c996076a85b46061d9a70ff81f013853a86b619": "wa🇬🇲i.eth", + "0xd8da6bf26964af9d7eed9e03e53415d37aa96045": "vitalik.eth", + "0xeefb13c7d42efcc655e528da6d6f7bbcf9a2251d": "test.eth", + } + }) + ); +} + +async fn expect_list_results(base: &Url, route: &str, route_desc: &str, items: Vec) { + let request: Value = send_get_request(base, route).await; + assert_eq!( + request, + json!({ + "items": items, + "pagination": { + "totalRecords": items.len() + } + }) + ); + + let request: Value = send_get_request(base, route_desc).await; + let mut reversed_items = items.clone(); + reversed_items.reverse(); + assert_eq!( + request, + json!({ + "items": reversed_items, + "pagination": { + "totalRecords": reversed_items.len() + } + }) + ); +} + +async fn expect_lookup_results(base: &Url, route: &str, mut payload: Value, items: Vec) { + let request: Value = send_post_request(base, route, &payload).await; + assert_eq!( + request, + json!({ + "items": items, + "pagination": { + "totalRecords": items.len() + } + }) + ); + payload + .as_object_mut() + .unwrap() + .insert("order".to_string(), serde_json::json!("DESC")); + let request: Value = send_post_request(base, route, &payload).await; + let mut reversed_items = items.clone(); + reversed_items.reverse(); + assert_eq!( + request, + json!({ + "items": reversed_items, + "pagination": { + "totalRecords": reversed_items.len() + } + }) + ); } diff --git a/blockscout-ens/bens-logic/justfile b/blockscout-ens/justfile similarity index 100% rename from blockscout-ens/bens-logic/justfile rename to blockscout-ens/justfile From c4fbedc898f9260335e0956f26ccc4d4d786001a Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 7 Nov 2023 20:20:38 +0300 Subject: [PATCH 4/8] Uncomment cicd tests --- .github/workflows/bens.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/bens.yml b/.github/workflows/bens.yml index 75dc0fa33..4bb2ca37b 100644 --- a/.github/workflows/bens.yml +++ b/.github/workflows/bens.yml @@ -66,14 +66,14 @@ jobs: DATABASE_URL: postgres://graph-node:admin@localhost:5432/ SQLX_OFFLINE: true - # - name: Integration tests - # run: cargo test --locked --workspace --test '*' -- --nocapture --include-ignored - # if: success() || failure() - # env: - # RUST_BACKTRACE: 1 - # RUST_LOG: info - # DATABASE_URL: postgres://graph-node:admin@localhost:5432/ - # SQLX_OFFLINE: true + - name: Integration tests + run: cargo test --locked --workspace --test '*' -- --nocapture --include-ignored + if: success() || failure() + env: + RUST_BACKTRACE: 1 + RUST_LOG: info + DATABASE_URL: postgres://graph-node:admin@localhost:5432/ + SQLX_OFFLINE: true lint: name: Linting From 2bc2424ea9c786d4d4866f34d97df4914e916573 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 7 Nov 2023 20:24:52 +0300 Subject: [PATCH 5/8] Fix typo --- blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs index 24bee7e91..4bbc38721 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs @@ -68,7 +68,7 @@ impl Response where T: DeserializeOwned, { - pub async fn try_from_reqwest_response( + async fn try_from_reqwest_response( response: reqwest::Response, ) -> reqwest_middleware::Result { let response = match response.status() { From 2bf36c75ae20cb694842c013653c21b0ca9052b1 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 7 Nov 2023 22:00:49 +0300 Subject: [PATCH 6/8] Fix datetime --- blockscout-ens/Cargo.lock | 1 + blockscout-ens/bens-proto/proto/bens.proto | 16 ++++++++-------- .../bens-proto/swagger/bens.swagger.yaml | 16 ++++++---------- blockscout-ens/bens-server/Cargo.toml | 1 + .../bens-server/src/conversion/domain.rs | 12 ++++++++---- blockscout-ens/bens-server/tests/domains.rs | 16 ++++++++-------- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/blockscout-ens/Cargo.lock b/blockscout-ens/Cargo.lock index b5b4743ab..879334b02 100644 --- a/blockscout-ens/Cargo.lock +++ b/blockscout-ens/Cargo.lock @@ -648,6 +648,7 @@ dependencies = [ "bens-proto", "blockscout-display-bytes", "blockscout-service-launcher", + "chrono", "config", "ethers", "hex", diff --git a/blockscout-ens/bens-proto/proto/bens.proto b/blockscout-ens/bens-proto/proto/bens.proto index f05d29452..6a4abd4a6 100644 --- a/blockscout-ens/bens-proto/proto/bens.proto +++ b/blockscout-ens/bens-proto/proto/bens.proto @@ -26,10 +26,10 @@ message Domain { optional Address resolved_address = 3; // The account that owns the domain Address owner = 4; - // Optinal. Unix timestamp of expiry date. None means never expires - int64 registration_date = 5; - // Optinal. Unix timestamp of expiry date. None means never expires - optional int64 expiry_date = 6; + // Optinal. RFC 3339 datetime of expiry date. + string registration_date = 5; + // Optinal. RFC 3339 datetime of expiry date. None means never expires + optional string expiry_date = 6; } message DetailedDomain { @@ -45,10 +45,10 @@ message DetailedDomain { optional Address resolved_address = 5; // Optinal. The account that owns the ERC721 NFT for the domain optional Address registrant = 6; - // Optinal. Unix timestamp of expiry date. None means never expires - optional int64 expiry_date = 7; - // Unix timestamp of regisration date - int64 registration_date = 8; + // Optinal. RFC 3339 datetime of expiry date. + string registration_date = 7; + // Optinal. RFC 3339 datetime of expiry date. None means never expires + optional string expiry_date = 8; // Map chain -> resolved_address that contains other blockchain addresses. // This map will contain `current_chain_id` -> `resovled_address` if `resovled_address` is not None map other_addresses = 9; diff --git a/blockscout-ens/bens-proto/swagger/bens.swagger.yaml b/blockscout-ens/bens-proto/swagger/bens.swagger.yaml index 0b2093bcc..d2791880c 100644 --- a/blockscout-ens/bens-proto/swagger/bens.swagger.yaml +++ b/blockscout-ens/bens-proto/swagger/bens.swagger.yaml @@ -281,14 +281,12 @@ definitions: registrant: $ref: '#/definitions/v1Address' title: Optinal. The account that owns the ERC721 NFT for the domain - expiryDate: - type: string - format: int64 - title: Optinal. Unix timestamp of expiry date. None means never expires registrationDate: type: string - format: int64 - title: Unix timestamp of regisration date + description: Optinal. RFC 3339 datetime of expiry date. + expiryDate: + type: string + title: Optinal. RFC 3339 datetime of expiry date. None means never expires otherAddresses: type: object additionalProperties: @@ -313,12 +311,10 @@ definitions: title: The account that owns the domain registrationDate: type: string - format: int64 - title: Optinal. Unix timestamp of expiry date. None means never expires + description: Optinal. RFC 3339 datetime of expiry date. expiryDate: type: string - format: int64 - title: Optinal. Unix timestamp of expiry date. None means never expires + title: Optinal. RFC 3339 datetime of expiry date. None means never expires v1DomainEvent: type: object properties: diff --git a/blockscout-ens/bens-server/Cargo.toml b/blockscout-ens/bens-server/Cargo.toml index df0666d6d..7977a951d 100644 --- a/blockscout-ens/bens-server/Cargo.toml +++ b/blockscout-ens/bens-server/Cargo.toml @@ -24,6 +24,7 @@ async-trait = "0.1" url = { version = "2", features = ["serde"] } hex = "0.4" thiserror = "1" +chrono = "0.4" [dependencies.sqlx] version = "0.7" diff --git a/blockscout-ens/bens-server/src/conversion/domain.rs b/blockscout-ens/bens-server/src/conversion/domain.rs index a69906179..b5cad8aa6 100644 --- a/blockscout-ens/bens-server/src/conversion/domain.rs +++ b/blockscout-ens/bens-server/src/conversion/domain.rs @@ -94,8 +94,8 @@ pub fn detailed_domain_from_logic( owner, resolved_address, registrant, - expiry_date: d.expiry_date.map(|date| date.timestamp()), - registration_date: d.registration_date.timestamp(), + expiry_date: d.expiry_date.map(date_from_logic), + registration_date: date_from_logic(d.registration_date), other_addresses: d.other_addresses.0.into_iter().collect(), }) } @@ -110,8 +110,8 @@ pub fn domain_from_logic(d: Domain) -> Result { name: d.name.unwrap_or_default(), owner, resolved_address, - expiry_date: d.expiry_date.map(|date| date.timestamp()), - registration_date: d.registration_date.timestamp(), + expiry_date: d.expiry_date.map(date_from_logic), + registration_date: date_from_logic(d.registration_date), }) } @@ -120,3 +120,7 @@ fn address_from_str_inner(addr: &str) -> Result { .map_err(|_| ConversionError::UserRequest(format!("invalid address '{addr}'")))?; Ok(Address::from_slice(&address)) } + +fn date_from_logic(d: chrono::DateTime) -> String { + d.to_rfc3339_opts(chrono::SecondsFormat::Millis, true) +} diff --git a/blockscout-ens/bens-server/tests/domains.rs b/blockscout-ens/bens-server/tests/domains.rs index b295b9a3a..085aa4f21 100644 --- a/blockscout-ens/bens-server/tests/domains.rs +++ b/blockscout-ens/bens-server/tests/domains.rs @@ -50,7 +50,7 @@ async fn basic_domain_extracting_works(pool: PgPool) { assert_eq!( request, json!({ - "expiryDate": "1975009824", + "expiryDate": "2032-08-01T21:50:24.000Z", "id": "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835", "name": "vitalik.eth", "otherAddresses": { @@ -63,7 +63,7 @@ async fn basic_domain_extracting_works(pool: PgPool) { "registrant": { "hash": "0x220866b1a2219f40e72f5c628b65d54268ca3a9d", }, - "registrationDate": "1497775154", + "registrationDate": "2017-06-18T08:39:14.000Z", "resolvedAddress": { "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", }, @@ -78,7 +78,7 @@ async fn basic_domain_extracting_works(pool: PgPool) { "fromAddress": { "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", }, - "timestamp": ("2017-06-18T08:39:14.000000Z"), + "timestamp": "2017-06-18T08:39:14.000000Z", "transactionHash": "0xdd16deb1ea750037c3ed1cae5ca20ff9db0e664a5146e5a030137d277a9247f3", }, { @@ -86,7 +86,7 @@ async fn basic_domain_extracting_works(pool: PgPool) { "fromAddress": { "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", }, - "timestamp": ("2019-07-10T05:58:51.000000Z"), + "timestamp": "2019-07-10T05:58:51.000000Z", "transactionHash": "0xea30bda97a7e9afcca208d5a648e8ec1e98b245a8884bf589dec8f4aa332fb14", }, { @@ -149,8 +149,8 @@ async fn basic_domain_extracting_works(pool: PgPool) { "owner": { "hash": "0x66a6f7744ce4dea450910b81a7168588f992eafb" }, - "registrationDate": "1640341437", - "expiryDate": "1711231341" + "registrationDate": "2021-12-24T10:23:57.000Z", + "expiryDate": "2024-03-23T22:02:21.000Z" } )]; expect_lookup_results( @@ -174,8 +174,8 @@ async fn basic_domain_extracting_works(pool: PgPool) { "owner": { "hash": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" }, - "registrationDate": "1497775154", - "expiryDate": "1975009824" + "registrationDate": "2017-06-18T08:39:14.000Z", + "expiryDate": "2032-08-01T21:50:24.000Z" } )] .into_iter() From f2013ebcb07470c923e0a41ed345c2b70919c177 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Wed, 8 Nov 2023 11:05:08 +0300 Subject: [PATCH 7/8] Fix test config --- blockscout-ens/bens-server/tests/config.test.toml | 2 +- blockscout-ens/bens-server/tests/domains.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blockscout-ens/bens-server/tests/config.test.toml b/blockscout-ens/bens-server/tests/config.test.toml index 3aaf15567..845d2466f 100644 --- a/blockscout-ens/bens-server/tests/config.test.toml +++ b/blockscout-ens/bens-server/tests/config.test.toml @@ -5,4 +5,4 @@ enabled = false enabled = false [tracing] -enabled = false \ No newline at end of file +enabled = false diff --git a/blockscout-ens/bens-server/tests/domains.rs b/blockscout-ens/bens-server/tests/domains.rs index 085aa4f21..0ece10fab 100644 --- a/blockscout-ens/bens-server/tests/domains.rs +++ b/blockscout-ens/bens-server/tests/domains.rs @@ -16,12 +16,12 @@ async fn basic_domain_extracting_works(pool: PgPool) { "{postgres_url}{}", pool.connect_options().get_database().unwrap() ); + std::env::set_var("BENS__DATABASE__URL", db_url); let clients = mocked_blockscout_clients().await; std::env::set_var("BENS__CONFIG", "./tests/config.test.toml"); let mut settings = Settings::build().expect("Failed to build settings"); let (server_settings, base) = get_test_server_settings(); settings.server = server_settings; - settings.database.url = db_url.parse().unwrap(); settings.blockscout.networks = clients .into_iter() .map(|(id, client)| { From 1655da82e75d2bac016f7c4518f890d4dae18acd Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Wed, 8 Nov 2023 15:13:43 +0300 Subject: [PATCH 8/8] Add client url to cache key --- blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs b/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs index 4bbc38721..be73acd40 100644 --- a/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs +++ b/blockscout-ens/bens-logic/src/subgraphs_reader/blockscout.rs @@ -82,7 +82,10 @@ where #[cached( key = "String", - convert = r#"{ format!("{transaction_hash:#}") }"#, + convert = r#"{ + let url = client.url(); + format!("{url}/tx/{transaction_hash:#}") + }"#, result = true, time = 86_400, // 24 * 60 * 60 seconds size = 50_000,