Skip to content
This repository has been archived by the owner on Aug 9, 2023. It is now read-only.

Commit

Permalink
feat: status server
Browse files Browse the repository at this point in the history
  • Loading branch information
hopeyen committed Jul 31, 2023
1 parent d4559ac commit 9007d62
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 216 deletions.
90 changes: 47 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ Experimental rust impl for The Graph [indexer service](https://github.com/graphp
- [ ] operator wallet -> indexer address
- [ ] subgraph health check
- [ ] query timing logs
- [ ] Deployment health server / status server
- [ ] indexing status resolver - to query indexingStatuses
- [ ] Deployment health server
- [ ] query status endpoint and process result
- [ ] Status server
- [x] indexing status resolver - to query indexingStatuses
- [ ] Filter for unsupported queries
- [ ] Cost server
- [ ] Cost graphQL schema
- [ ] query indexer management client for Cost model
Expand Down Expand Up @@ -96,38 +99,32 @@ Configure required start-up args, check description by
```
cargo run -p service -- --help
```
Required

Set up configurations. To run with toml configurations
```
--ethereum
--ethereum-polling-interval
--mnemonic
--indexer-address
--port
--metrics-port
--graph-node-query-endpoint
--graph-node-status-endpoint
--log-level
--gcloud-profiling
--free-query-auth-token
--postgres-host
--postgres-port
--postgres-database
--postgres-username
--postgres-password
--network-subgraph-deployment
--network-subgraph-endpoint
--network-subgraph-auth-token
--serve-network-subgraph
--allocation-syncing-interval
--client-signer-address
cargo run -- config "template.toml"
```

Afterwards run
To run with CLI args
```
cargo run -p service
cargo run -- --ethereum <eth-node-provider> \
--mnemonic <operator-mnemonic> \
--indexer-address <indexer-address ></indexer-address> \
--port 7300 \
--metrics-port 7500 \
--graph-node-query-endpoint http://localhost:8000 \
--graph-node-status-endpoint http://localhost:8030 \
--free-query-auth-token "free-query-auth" \
--postgres-host "127.0.0.1" \
--postgres-port 5432 \
--postgres-database postgres \
--postgres-username <postgres-username> \
--postgres-password <postgres-password> \
--network-subgraph-endpoint "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network \
--network-subgraph-auth-token "network-subgraph-auth" \
--serve-network-subgraph true \
--client-signer-address "0xe1EC4339019eC9628438F8755f847e3023e4ff9c" \
```

Expand All @@ -136,39 +133,46 @@ After service start up, try with command
curl -X POST \
-H 'Content-Type: application/json' \
--data '{"query": "{_meta{block{number}}}"}' \
http://127.0.0.1:8080/subgraphs/id/QmVhiE4nax9i86UBnBmQCYDzvjWuwHShYh7aspGPQhU5Sj
http://127.0.0.1:7300/network
```


### Checks
### Supported requests


```
✗ curl http://localhost:7300/
✗ curl http://localhost:7300/
Ready to roll!
✗ curl http://localhost:7300/health
{"healthy":true}
✗ curl http://localhost:7300/version
{"version":"0.1.0","dependencies":{}}
✗ curl http://localhost:7300/operator/info
{"publicKey":"0xacb05407d78129b5717bb51712d3e23a78a10929"}
# Subgraph queries
# Checks for receipts and authorization
✗ curl -X POST -H 'Content-Type: application/json' -H 'Authorization: token-for-graph-node-query-endpoint' --data '{"query": "{_meta{block{number}}}"}' http://localhost:7300/subgraphs/id/QmVhiE4nax9i86UBnBmQCYDzvjWuwHShYh7aspGPQhU5Sj
"{\"data\":{\"_meta\":{\"block\":{\"number\":9425787}}}}"
// Checks for auth and configuration to serve-network-subgraph
# Network queries
# Checks for auth and configuration to serve-network-subgraph
✗ curl -X POST -H 'Content-Type: application/json' -H 'Authorization: token-for-network-subgraph' --data '{"query": "{_meta{block{number}}}"}' http://localhost:7300/network
"Not enabled or authorized query"
// Indexing status resolver
# Indexing status resolver - Route supported root field queries to graph node status endpoint
✗ curl -X POST -H 'Content-Type: application/json' --data '{"query": "{blockHashFromNumber(network:\"goerli\", blockNumber: 9069120)}"}' http://localhost:7300/status
{"data":{"blockHashFromNumber":"e1e5472636db73ba5496aee098dc21310683c95eb30fc46f9ba6c36d8b28d58e"}}%
// Indexing status resolver - filter unsupported root field queries
✗ curl -X POST -H 'Content-Type: application/json' --data '{"query": "{blockHashFromNumber(network:\"goerli\", blockNumber: 9069120)}"}' http://localhost:7300/status
{"data":{"blockHashFromNumber":"e1e5472636db73ba5496aee098dc21310683c95eb30fc46f9ba6c36d8b28d58e"}}%
# Indexing status resolver -
✗ curl -X POST -H 'Content-Type: application/json' --data '{"query": "{indexingStatuses {subgraph health} }"}' http://localhost:7300/status
{"data":{"indexingStatuses":[{"subgraph":"QmVhiE4nax9i86UBnBmQCYDzvjWuwHShYh7aspGPQhU5Sj","health":"healthy"},{"subgraph":"QmWVtsWk8Pqn3zY3czDjyoVreshRLmoz9jko3mQ4uvxQDj","health":"healthy"},{"subgraph":"QmacQnSgia4iDPWHpeY6aWxesRFdb8o5DKZUx96zZqEWrB","health":"healthy"}]}}
# Indexing status resolver - Filter out the unsupported queries
✗ curl -X POST -H 'Content-Type: application/json' --data '{"query": "{_meta{block{number}}}"}' http://localhost:7300/status
{"errors":[{"locations":[{"line":1,"column":2}],"message":"Type `Query` has no field `_meta`"}]}%
```
22 changes: 5 additions & 17 deletions service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,10 @@ pub struct IndexerInfrastructure {
long,
value_name = "log-level",
env = "LOG_LEVEL",
default_value_t = LogLevel::Debug,
value_enum,
help = "Log level"
help = "Log level in RUST_LOG format"
)]
pub log_level: LogLevel,
pub log_level: Option<String>,
#[clap(
long,
value_name = "gcloud-profiling",
Expand Down Expand Up @@ -234,7 +233,9 @@ impl Cli {
};

// Enables tracing under RUST_LOG variable
std::env::set_var("RUST_LOG", cli.indexer_infrastructure.log_level.to_str());
if let Some(log_setting) = &cli.indexer_infrastructure.log_level {
std::env::set_var("RUST_LOG", log_setting);
};
// add a LogFormat to config
init_tracing("pretty".to_string()).expect("Could not set up global default subscriber for logger, check environmental variable `RUST_LOG` or the CLI input `log-level`");
cli
Expand Down Expand Up @@ -281,16 +282,3 @@ pub enum LogLevel {
Error,
Fatal,
}

impl LogLevel {
fn to_str(&self) -> &'static str {
match self {
LogLevel::Trace => "Trace",
LogLevel::Debug => "Debug",
LogLevel::Info => "Info",
LogLevel::Warn => "Warn",
LogLevel::Error => "Error",
LogLevel::Fatal => "Fatal",
}
}
}
7 changes: 0 additions & 7 deletions service/src/graph_node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use reqwest::{header, Client, Url};
use tracing::info;

use crate::query_processor::UnattestedQueryResult;

Expand All @@ -26,18 +25,12 @@ impl GraphNodeInstance {
endpoint: &str,
data: String,
) -> Result<UnattestedQueryResult, reqwest::Error> {
info!("making subgraph query");
let request = self
.client
.post(format!("{}/subgraphs/id/{}", self.base_url, endpoint))
.body(data.clone())
.header(header::CONTENT_TYPE, "application/json");

info!(
"making subgraph query: {:#?}",
format!("{}/subgraphs/id/{}", self.base_url, endpoint)
);
info!("data: {:#?}", data);
let response = request.send().await?.text().await?;
Ok(UnattestedQueryResult {
graphql_response: response,
Expand Down
41 changes: 1 addition & 40 deletions service/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ use axum::{
use axum::{routing::post, Extension, Router, Server};
use dotenvy::dotenv;
use model::QueryRoot;
use reqwest::Client;
use serde_json::json;

use std::{net::SocketAddr, str::FromStr, time::Duration};
use tower::{BoxError, ServiceBuilder};
Expand Down Expand Up @@ -84,12 +82,12 @@ async fn main() -> Result<(), std::io::Error> {
.route("/", get(routes::basic::index))
.route("/health", get(routes::basic::health))
.route("/version", get(routes::basic::version))
// .route("/status", post(routes::status::status_middleware))
.route(
"/subgraphs/id/:id",
post(routes::subgraphs::subgraph_queries),
)
.route("/network", post(routes::network::network_queries))
.route("/status", post(routes::status::status_queries))
.nest(
"/operator",
routes::basic::create_operator_server(service_options.clone()),
Expand Down Expand Up @@ -126,42 +124,5 @@ async fn main() -> Result<(), std::io::Error> {
.await
.unwrap();

let test_res = test_graphql_query().await;
println!("{:#?}", test_res);

Ok(())
}

async fn test_graphql_query() -> serde_json::Value {
let addr = "http://localhost:7300/subgraphs/id/QmVhiE4nax9i86UBnBmQCYDzvjWuwHShYh7aspGPQhU5Sj";
let client = Client::new();

// Create the JSON data for the GraphQL query
let query_data = json!({
"query": "{_meta{block{number}}}"
});

// Make the POST request to the server
let response = client
.post(addr)
.json(&query_data)
.send()
.await
.expect("Failed to send request");

// Assert that the response status is 200 OK
assert!(response.status().is_success());

// Read the response body as a JSON value
let response_json: serde_json::Value = response
.json()
.await
.expect("Failed to parse response JSON");

// Add any additional assertions based on the expected response
// For example, you can check the values in the response JSON.

// For debugging purposes, you can print the response JSON
println!("Response JSON: {:?}", response_json);
response_json
}
1 change: 0 additions & 1 deletion service/src/server/routes/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@ async fn operator_info(Extension(options): Extension<ServerOptions>) -> Json<ser

// Create a function to build the operator server router
pub fn create_operator_server(_options: ServerOptions) -> Router {
println!("create_operator_server?");
Router::new().route("/info", get(operator_info))
}
37 changes: 32 additions & 5 deletions service/src/server/routes/network.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use axum::{
body::{Bytes, HttpBody},
body::Bytes,
extract::Extension,
http::{self, Request, StatusCode},
response::IntoResponse,
Expand All @@ -25,14 +25,27 @@ pub async fn network_queries(
&& auth_token.unwrap() == server.network_subgraph_auth_token.as_deref().unwrap())
{
let error_body = "Not enabled or authorized query".to_string();
return (StatusCode::BAD_REQUEST, Json(error_body));
return (
StatusCode::BAD_REQUEST,
axum::response::AppendHeaders([(axum::http::header::CONTENT_TYPE, "application/json")]),
Json(error_body),
);
}

// Serve query using query processor
let req_body = req.into_body();
let query: Bytes = hyper::body::to_bytes(req_body)
.await
.map_err(|e| (StatusCode::BAD_REQUEST, Json(e)))
.map_err(|e| {
(
StatusCode::BAD_REQUEST,
axum::response::AppendHeaders([(
axum::http::header::CONTENT_TYPE,
"application/json",
)]),
Json(e),
)
})
.unwrap();
let query_string = String::from_utf8_lossy(&query);

Expand All @@ -45,11 +58,25 @@ pub async fn network_queries(
match request.status {
200 => {
let response_body = request.result.graphql_response;
(StatusCode::OK, Json(response_body))
(
StatusCode::OK,
axum::response::AppendHeaders([(
axum::http::header::CONTENT_TYPE,
"application/json",
)]),
Json(response_body),
)
}
_ => {
let error_body = "Bad subgraph query".to_string();
(StatusCode::BAD_REQUEST, Json(error_body))
(
StatusCode::BAD_REQUEST,
axum::response::AppendHeaders([(
axum::http::header::CONTENT_TYPE,
"application/json",
)]),
Json(error_body),
)
}
}
}
Loading

0 comments on commit 9007d62

Please sign in to comment.