From c598ed444c969da2b52241cb70d1cf5f7239d33b Mon Sep 17 00:00:00 2001 From: Jannis Pohlmann Date: Fri, 29 Sep 2023 21:45:48 +0200 Subject: [PATCH] refactor: use DeploymentId type from toolshed crate --- Cargo.lock | 1 + common/src/allocations/mod.rs | 64 ++++----- common/src/allocations/monitor.rs | 4 +- common/src/attestations/mod.rs | 61 ++++---- common/src/attestations/signer.rs | 13 +- common/src/attestations/signers.rs | 7 +- common/src/lib.rs | 2 - common/src/test_vectors.rs | 39 ++--- common/src/types.rs | 143 ------------------- service/Cargo.toml | 1 + service/src/common/indexer_management/mod.rs | 12 +- service/src/escrow_monitor.rs | 14 +- service/src/graph_node.rs | 43 ++++-- service/src/main.rs | 4 +- service/src/query_processor.rs | 87 ++--------- service/src/server/routes/subgraphs.rs | 8 +- 16 files changed, 145 insertions(+), 358 deletions(-) delete mode 100644 common/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 038b33d0d..beada77c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4744,6 +4744,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.7.4", + "toolshed", "tower", "tower-http 0.4.0", "tracing", diff --git a/common/src/allocations/mod.rs b/common/src/allocations/mod.rs index 4e050f2d3..730868619 100644 --- a/common/src/allocations/mod.rs +++ b/common/src/allocations/mod.rs @@ -9,8 +9,7 @@ use ethers_core::k256::ecdsa::SigningKey; use ethers_core::types::U256; use serde::Deserialize; use serde::Deserializer; - -use crate::types::SubgraphDeploymentID; +use toolshed::thegraph::DeploymentId; pub mod monitor; @@ -42,7 +41,7 @@ pub enum AllocationStatus { #[derive(Debug, Eq, PartialEq, Deserialize)] pub struct SubgraphDeployment { - pub id: SubgraphDeploymentID, + pub id: DeploymentId, #[serde(rename = "deniedAt")] pub denied_at: Option, #[serde(rename = "stakedTokens")] @@ -98,14 +97,13 @@ impl<'d> Deserialize<'d> for Allocation { pub fn derive_key_pair( indexer_mnemonic: &str, epoch: u64, - deployment: &SubgraphDeploymentID, + deployment: &DeploymentId, index: u64, ) -> Result> { let mut derivation_path = format!("m/{}/", epoch); derivation_path.push_str( &deployment - .ipfs_hash() - .as_bytes() + .0 .iter() .map(|char| char.to_string()) .collect::>() @@ -146,45 +144,37 @@ pub fn allocation_signer(indexer_mnemonic: &str, allocation: &Allocation) -> Res #[cfg(test)] mod test { + use lazy_static::lazy_static; use std::str::FromStr; - - use crate::prelude::SubgraphDeploymentID; + use toolshed::thegraph::DeploymentId; use super::*; const INDEXER_OPERATOR_MNEMONIC: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + lazy_static! { + static ref DEPLOYMENT_ID: DeploymentId = DeploymentId( + "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" + .parse() + .unwrap(), + ); + } + #[test] fn test_derive_key_pair() { assert_eq!( - derive_key_pair( - INDEXER_OPERATOR_MNEMONIC, - 953, - &SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" - ) - .unwrap(), - 0 - ) - .unwrap() - .address() - .as_fixed_bytes(), + derive_key_pair(INDEXER_OPERATOR_MNEMONIC, 953, &DEPLOYMENT_ID, 0) + .unwrap() + .address() + .as_fixed_bytes(), Address::from_str("0xfa44c72b753a66591f241c7dc04e8178c30e13af").unwrap() ); assert_eq!( - derive_key_pair( - INDEXER_OPERATOR_MNEMONIC, - 940, - &SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" - ) - .unwrap(), - 2 - ) - .unwrap() - .address() - .as_fixed_bytes(), + derive_key_pair(INDEXER_OPERATOR_MNEMONIC, 940, &DEPLOYMENT_ID, 2) + .unwrap() + .address() + .as_fixed_bytes(), Address::from_str("0xa171cd12c3dde7eb8fe7717a0bcd06f3ffa65658").unwrap() ); } @@ -197,10 +187,7 @@ mod test { id: Address::from_str("0xa171cd12c3dde7eb8fe7717a0bcd06f3ffa65658").unwrap(), status: AllocationStatus::Null, subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a", - ) - .unwrap(), + id: *DEPLOYMENT_ID, denied_at: None, staked_tokens: U256::zero(), signalled_tokens: U256::zero(), @@ -239,10 +226,7 @@ mod test { id: Address::from_str("0xdeadbeefcafebabedeadbeefcafebabedeadbeef").unwrap(), status: AllocationStatus::Null, subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a", - ) - .unwrap(), + id: *DEPLOYMENT_ID, denied_at: None, staked_tokens: U256::zero(), signalled_tokens: U256::zero(), diff --git a/common/src/allocations/monitor.rs b/common/src/allocations/monitor.rs index 7ddea7963..5c3426b97 100644 --- a/common/src/allocations/monitor.rs +++ b/common/src/allocations/monitor.rs @@ -246,9 +246,7 @@ impl AllocationMonitor { .map(|e| { format!( "{{allocation: {:?}, deployment: {}, closedAtEpoch: {:?})}}", - e.id, - e.subgraph_deployment.id.ipfs_hash(), - e.closed_at_epoch + e.id, e.subgraph_deployment.id, e.closed_at_epoch ) }) .collect::>() diff --git a/common/src/attestations/mod.rs b/common/src/attestations/mod.rs index 21ee4aa50..972b61290 100644 --- a/common/src/attestations/mod.rs +++ b/common/src/attestations/mod.rs @@ -7,8 +7,9 @@ use ethers::signers::MnemonicBuilder; use ethers::signers::Signer; use ethers::signers::Wallet; use ethers_core::k256::ecdsa::SigningKey; +use toolshed::thegraph::DeploymentId; -use crate::prelude::{Allocation, SubgraphDeploymentID}; +use crate::prelude::Allocation; pub mod signer; pub mod signers; @@ -16,14 +17,13 @@ pub mod signers; pub fn derive_key_pair( indexer_mnemonic: &str, epoch: u64, - deployment: &SubgraphDeploymentID, + deployment: &DeploymentId, index: u64, ) -> Result> { let mut derivation_path = format!("m/{}/", epoch); derivation_path.push_str( &deployment - .ipfs_hash() - .as_bytes() + .0 .iter() .map(|char| char.to_string()) .collect::>() @@ -69,46 +69,39 @@ pub fn attestation_signer_for_allocation( mod tests { use alloy_primitives::Address; use ethers_core::types::U256; + use lazy_static::lazy_static; use std::str::FromStr; use test_log::test; - use crate::prelude::{Allocation, AllocationStatus, SubgraphDeployment, SubgraphDeploymentID}; + use crate::prelude::{Allocation, AllocationStatus, SubgraphDeployment}; use super::*; const INDEXER_OPERATOR_MNEMONIC: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + lazy_static! { + static ref DEPLOYMENT_ID: DeploymentId = DeploymentId( + "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" + .parse() + .unwrap(), + ); + } + #[test] fn test_derive_key_pair() { assert_eq!( - derive_key_pair( - INDEXER_OPERATOR_MNEMONIC, - 953, - &SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" - ) - .unwrap(), - 0 - ) - .unwrap() - .address() - .as_fixed_bytes(), + derive_key_pair(INDEXER_OPERATOR_MNEMONIC, 953, &DEPLOYMENT_ID, 0) + .unwrap() + .address() + .as_fixed_bytes(), Address::from_str("0xfa44c72b753a66591f241c7dc04e8178c30e13af").unwrap() ); assert_eq!( - derive_key_pair( - INDEXER_OPERATOR_MNEMONIC, - 940, - &SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" - ) - .unwrap(), - 2 - ) - .unwrap() - .address() - .as_fixed_bytes(), + derive_key_pair(INDEXER_OPERATOR_MNEMONIC, 940, &DEPLOYMENT_ID, 2) + .unwrap() + .address() + .as_fixed_bytes(), Address::from_str("0xa171cd12c3dde7eb8fe7717a0bcd06f3ffa65658").unwrap() ); } @@ -121,10 +114,7 @@ mod tests { id: Address::from_str("0xa171cd12c3dde7eb8fe7717a0bcd06f3ffa65658").unwrap(), status: AllocationStatus::Null, subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a", - ) - .unwrap(), + id: *DEPLOYMENT_ID, denied_at: None, staked_tokens: U256::zero(), signalled_tokens: U256::zero(), @@ -163,10 +153,7 @@ mod tests { id: Address::from_str("0xdeadbeefcafebabedeadbeefcafebabedeadbeef").unwrap(), status: AllocationStatus::Null, subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a", - ) - .unwrap(), + id: *DEPLOYMENT_ID, denied_at: None, staked_tokens: U256::zero(), signalled_tokens: U256::zero(), diff --git a/common/src/attestations/signer.rs b/common/src/attestations/signer.rs index a01191882..393da94e8 100644 --- a/common/src/attestations/signer.rs +++ b/common/src/attestations/signer.rs @@ -11,11 +11,12 @@ use ethers_core::types::U256; use keccak_hash::keccak; use secp256k1::SecretKey; use std::convert::TryInto; +use toolshed::thegraph::DeploymentId; /// An attestation signer tied to a specific allocation via its signer key #[derive(Debug, Clone)] pub struct AttestationSigner { - subgraph_deployment_id: Bytes32, + subgraph_deployment_id: DeploymentId, domain_separator: DomainSeparator, signer: SecretKey, } @@ -25,7 +26,7 @@ impl AttestationSigner { chain_id: eip_712_derive::U256, dispute_manager: Address, signer: SecretKey, - subgraph_deployment_id: Bytes32, + deployment_id: DeploymentId, ) -> Self { let bytes = hex::decode("a070ffb1cd7409649bf77822cce74495468e06dbfaef09556838bf188679b9c2") .unwrap(); @@ -44,7 +45,7 @@ impl AttestationSigner { Self { domain_separator, signer, - subgraph_deployment_id, + subgraph_deployment_id: deployment_id, } } @@ -55,7 +56,7 @@ impl AttestationSigner { let receipt = Receipt { request_cid, response_cid, - subgraph_deployment_id: self.subgraph_deployment_id, + subgraph_deployment_id: *self.subgraph_deployment_id.0, }; // Unwrap: This can only fail if the SecretKey is invalid. @@ -69,7 +70,7 @@ impl AttestationSigner { v, r, s, - subgraph_deployment_id: self.subgraph_deployment_id, + subgraph_deployment_id: *self.subgraph_deployment_id.0, request_cid, response_cid, } @@ -106,7 +107,7 @@ pub fn create_attestation_signer( chain_id: U256, dispute_manager_address: Address, signer: SigningKey, - deployment_id: [u8; 32], + deployment_id: DeploymentId, ) -> anyhow::Result { // Tedious conversions to the "indexer_native" types let mut chain_id_bytes = [0u8; 32]; diff --git a/common/src/attestations/signers.rs b/common/src/attestations/signers.rs index d362826b6..62c1a336d 100644 --- a/common/src/attestations/signers.rs +++ b/common/src/attestations/signers.rs @@ -70,21 +70,20 @@ impl AttestationSigners { inner.chain_id, inner.dispute_manager, signer, - allocation.subgraph_deployment.id.bytes32(), + allocation.subgraph_deployment.id, ) }) { Ok(signer) => { e.insert(signer); info!( "Found attestation signer for {{allocation: {}, deployment: {}}}", - allocation.id, - allocation.subgraph_deployment.id.ipfs_hash() + allocation.id, allocation.subgraph_deployment.id, ); } Err(e) => { warn!( "Failed to find the attestation signer for {{allocation: {}, deployment: {}, createdAtEpoch: {}, err: {}}}", - allocation.id, allocation.subgraph_deployment.id.ipfs_hash(), allocation.created_at_epoch, e + allocation.id, allocation.subgraph_deployment.id, allocation.created_at_epoch, e ) } } diff --git a/common/src/lib.rs b/common/src/lib.rs index b8e06310c..b20ddcaad 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -6,7 +6,6 @@ pub mod attestations; pub mod graphql; pub mod network_subgraph; pub mod signature_verification; -pub mod types; #[cfg(test)] mod test_vectors; @@ -20,5 +19,4 @@ pub mod prelude { signers::AttestationSigners, }; pub use super::network_subgraph::NetworkSubgraph; - pub use super::types::*; } diff --git a/common/src/test_vectors.rs b/common/src/test_vectors.rs index d4f3e2f0c..16314c88b 100644 --- a/common/src/test_vectors.rs +++ b/common/src/test_vectors.rs @@ -5,8 +5,9 @@ use std::{collections::HashMap, str::FromStr}; use alloy_primitives::Address; use ethers_core::types::U256; +use toolshed::thegraph::DeploymentId; -use crate::prelude::{Allocation, AllocationStatus, SubgraphDeployment, SubgraphDeploymentID}; +use crate::prelude::{Allocation, AllocationStatus, SubgraphDeployment}; pub const INDEXER_OPERATOR_MNEMONIC: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; @@ -120,10 +121,11 @@ pub fn expected_eligible_allocations() -> HashMap { created_at_epoch: 953, closed_at_epoch: None, subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a", - ) - .unwrap(), + id: DeploymentId( + "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" + .parse() + .unwrap(), + ), denied_at: Some(0), staked_tokens: U256::from_str("96183284152000000014901161").unwrap(), signalled_tokens: U256::from_str("182832939554154667498047").unwrap(), @@ -148,10 +150,11 @@ pub fn expected_eligible_allocations() -> HashMap { created_at_epoch: 953, closed_at_epoch: None, subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xcda7fa0405d6fd10721ed13d18823d24b535060d8ff661f862b26c23334f13bf", - ) - .unwrap(), + id: DeploymentId( + "0xcda7fa0405d6fd10721ed13d18823d24b535060d8ff661f862b26c23334f13bf" + .parse() + .unwrap(), + ), denied_at: Some(0), staked_tokens: U256::from_str("53885041676589999979510903").unwrap(), signalled_tokens: U256::from_str("104257136417832003117925").unwrap(), @@ -176,10 +179,11 @@ pub fn expected_eligible_allocations() -> HashMap { created_at_epoch: 940, closed_at_epoch: Some(953), subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a", - ) - .unwrap(), + id: DeploymentId( + "0xbbde25a2c85f55b53b7698b9476610c3d1202d88870e66502ab0076b7218f98a" + .parse() + .unwrap(), + ), denied_at: Some(0), staked_tokens: U256::from_str("96183284152000000014901161").unwrap(), signalled_tokens: U256::from_str("182832939554154667498047").unwrap(), @@ -204,10 +208,11 @@ pub fn expected_eligible_allocations() -> HashMap { created_at_epoch: 940, closed_at_epoch: Some(953), subgraph_deployment: SubgraphDeployment { - id: SubgraphDeploymentID::new( - "0xc064c354bc21dd958b1d41b67b8ef161b75d2246b425f68ed4c74964ae705cbd", - ) - .unwrap(), + id: DeploymentId( + "0xc064c354bc21dd958b1d41b67b8ef161b75d2246b425f68ed4c74964ae705cbd" + .parse() + .unwrap(), + ), denied_at: Some(0), staked_tokens: U256::from_str("85450761241000000055879354").unwrap(), signalled_tokens: U256::from_str("154944508746646550301048").unwrap(), diff --git a/common/src/types.rs b/common/src/types.rs deleted file mode 100644 index cf30b419c..000000000 --- a/common/src/types.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2023-, GraphOps and Semiotic Labs. -// SPDX-License-Identifier: Apache-2.0 - -use ethers::utils::hex; -use serde::Deserialize; - -/// Subgraph identifier type: SubgraphDeploymentID with field 'value' -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SubgraphDeploymentID { - // bytes32 subgraph deployment Id - value: [u8; 32], -} - -/// Implement deserialization for SubgraphDeploymentID -/// Deserialize from hex string or IPFS multihash string -impl<'de> Deserialize<'de> for SubgraphDeploymentID { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - SubgraphDeploymentID::new(&s).map_err(serde::de::Error::custom) - } -} - -/// Implement SubgraphDeploymentID functions -impl SubgraphDeploymentID { - /// Construct SubgraphDeploymentID from a string - /// Validate IPFS hash or hex format before decoding - pub fn new(id: &str) -> anyhow::Result { - SubgraphDeploymentID::from_hex(id) - .or_else(|_| SubgraphDeploymentID::from_ipfs_hash(id)) - .map_err(|_| anyhow::anyhow!("Invalid subgraph deployment ID: {}", id)) - } - - /// Construct SubgraphDeploymentID from a 32 bytes hex string. - /// The '0x' prefix is optional. - /// - /// Returns an error if the input is not a valid hex string or if the input is not 32 bytes long. - pub fn from_hex(id: &str) -> anyhow::Result { - let mut buf = [0u8; 32]; - hex::decode_to_slice(id.trim_start_matches("0x"), &mut buf)?; - Ok(SubgraphDeploymentID { value: buf }) - } - - /// Construct SubgraphDeploymentID from a 34 bytes IPFS multihash string. - /// The 'Qm' prefix is mandatory. - /// - /// Returns an error if the input is not a valid IPFS multihash string or if the input is not 34 bytes long. - pub fn from_ipfs_hash(hash: &str) -> anyhow::Result { - let bytes = bs58::decode(hash).into_vec()?; - let value = bytes[2..].try_into()?; - Ok(SubgraphDeploymentID { value }) - } - - /// Returns the subgraph deployment ID as a 32 bytes array. - pub fn bytes32(&self) -> [u8; 32] { - self.value - } - - /// Returns the subgraph deployment ID as a 34 bytes IPFS multihash string. - pub fn ipfs_hash(&self) -> String { - let value = self.value; - let mut bytes: Vec = vec![0x12, 0x20]; - bytes.extend(value.to_vec()); - bs58::encode(bytes).into_string() - } - - /// Returns the subgraph deployment ID as a 32 bytes hex string. - /// The '0x' prefix is included. - pub fn hex(&self) -> String { - format!("0x{}", hex::encode(self.value)) - } -} - -impl ToString for SubgraphDeploymentID { - fn to_string(&self) -> String { - self.hex() - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn hex_to_ipfs_multihash() { - let deployment_id = "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884abf"; - let expected_ipfs_hash = "QmcPHxcC2ZN7m79XfYZ77YmF4t9UCErv87a9NFKrSLWKtJ"; - - assert_eq!( - SubgraphDeploymentID::from_hex(deployment_id) - .unwrap() - .ipfs_hash(), - expected_ipfs_hash - ); - } - - #[test] - fn ipfs_multihash_to_hex() { - let deployment_id = "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884abf"; - let ipfs_hash = "QmcPHxcC2ZN7m79XfYZ77YmF4t9UCErv87a9NFKrSLWKtJ"; - - assert_eq!( - SubgraphDeploymentID::from_ipfs_hash(ipfs_hash) - .unwrap() - .to_string(), - deployment_id - ); - } - - #[test] - fn subgraph_deployment_id_input_validation_success() { - let deployment_id = "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884abf"; - let ipfs_hash = "QmcPHxcC2ZN7m79XfYZ77YmF4t9UCErv87a9NFKrSLWKtJ"; - - assert_eq!( - SubgraphDeploymentID::new(ipfs_hash).unwrap().to_string(), - deployment_id - ); - - assert_eq!( - SubgraphDeploymentID::new(deployment_id) - .unwrap() - .ipfs_hash(), - ipfs_hash - ); - } - - #[test] - fn subgraph_deployment_id_input_validation_fail() { - let invalid_deployment_id = - "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884a"; - let invalid_ipfs_hash = "Qm1234"; - - let res = SubgraphDeploymentID::new(invalid_deployment_id); - assert!(res.is_err()); - - let res = SubgraphDeploymentID::new(invalid_ipfs_hash); - assert!(res.is_err()); - } -} diff --git a/service/Cargo.toml b/service/Cargo.toml index 8b9e2e17c..c0bb3a945 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -47,6 +47,7 @@ sqlx = { version = "0.7.1", features = ["postgres", "runtime-tokio", "bigdecimal alloy-primitives = { version = "0.3.3", features = ["serde"] } alloy-sol-types = "0.3.2" lazy_static = "1.4.0" +toolshed = { git = "https://github.com/edgeandnode/toolshed", tag = "v0.2.2", features = ["graphql"] } [dev-dependencies] faux = "0.1.10" diff --git a/service/src/common/indexer_management/mod.rs b/service/src/common/indexer_management/mod.rs index 62c860368..00a4334ad 100644 --- a/service/src/common/indexer_management/mod.rs +++ b/service/src/common/indexer_management/mod.rs @@ -6,8 +6,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use sqlx::{FromRow, PgPool}; -use indexer_common::prelude::SubgraphDeploymentID; - use super::indexer_error::{IndexerError, IndexerErrorCause, IndexerErrorCode}; #[derive(Debug, FromRow, Clone, Serialize, Deserialize, SimpleObject)] @@ -25,10 +23,7 @@ pub async fn cost_models( pool: &PgPool, deployments: &[String], ) -> Result, IndexerError> { - let deployment_ids = deployments - .iter() - .map(|d| SubgraphDeploymentID::new(d).unwrap().to_string()) - .collect::>(); + let deployment_ids = deployments.to_vec(); let models = if deployment_ids.is_empty() { sqlx::query_as!( CostModel, @@ -93,7 +88,6 @@ pub async fn cost_model( pool: &PgPool, deployment: &str, ) -> Result, IndexerError> { - let deployment_id = SubgraphDeploymentID::new(deployment).unwrap().to_string(); let model = sqlx::query_as!( CostModel, r#" @@ -101,7 +95,7 @@ pub async fn cost_model( FROM "CostModels" WHERE deployment = $1 "#, - deployment_id + deployment ) .fetch_optional(pool) .await @@ -113,7 +107,7 @@ pub async fn cost_model( || { Some(merge_global( CostModel { - deployment: deployment.to_string(), + deployment: deployment.into(), model: None, variables: None, }, diff --git a/service/src/escrow_monitor.rs b/service/src/escrow_monitor.rs index 44f032744..4c71965c2 100644 --- a/service/src/escrow_monitor.rs +++ b/service/src/escrow_monitor.rs @@ -10,13 +10,14 @@ use serde_json::json; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; +use toolshed::thegraph::DeploymentId; use crate::graph_node::GraphNodeInstance; #[derive(Debug)] struct EscrowMonitorInner { graph_node: GraphNodeInstance, - escrow_subgraph_deployment: String, + escrow_subgraph_deployment: DeploymentId, indexer_address: Address, interval_ms: u64, sender_accounts: Arc>>, @@ -33,7 +34,7 @@ pub struct EscrowMonitor { impl EscrowMonitor { pub async fn new( graph_node: GraphNodeInstance, - escrow_subgraph_deployment: String, + escrow_subgraph_deployment: DeploymentId, indexer_address: Address, interval_ms: u64, ) -> Result { @@ -61,7 +62,7 @@ impl EscrowMonitor { async fn current_accounts( graph_node: &GraphNodeInstance, - escrow_subgraph_deployment: &str, + escrow_subgraph_deployment: &DeploymentId, indexer_address: &Address, ) -> Result> { // These 2 structs are used to deserialize the response from the escrow subgraph. @@ -192,14 +193,15 @@ mod tests { #[tokio::test] async fn test_current_accounts() { let indexer_address = Address::from_str(test_vectors::INDEXER_ADDRESS).unwrap(); - let escrow_subgraph_deployment = "Qmabcdefghijklmnopqrstuvwxyz1234567890ABCDEFGH"; + let escrow_subgraph_deployment = + DeploymentId::from_str("Qmabcdefghijklmnopqrstuvwxyz1234567890ABCDEFGH").unwrap(); let mock_server = MockServer::start().await; let graph_node = graph_node::GraphNodeInstance::new(&mock_server.uri()); let mock = Mock::given(method("POST")) .and(path( - "/subgraphs/id/".to_string() + escrow_subgraph_deployment, + "/subgraphs/id/".to_string() + &escrow_subgraph_deployment.to_string(), )) .respond_with( ResponseTemplate::new(200) @@ -209,7 +211,7 @@ mod tests { let inner = EscrowMonitorInner { graph_node, - escrow_subgraph_deployment: escrow_subgraph_deployment.to_string(), + escrow_subgraph_deployment, indexer_address, interval_ms: 1000, sender_accounts: Arc::new(RwLock::new(HashMap::new())), diff --git a/service/src/graph_node.rs b/service/src/graph_node.rs index fe2b3de4c..7c875764f 100644 --- a/service/src/graph_node.rs +++ b/service/src/graph_node.rs @@ -1,10 +1,10 @@ // Copyright 2023-, GraphOps and Semiotic Labs. // SPDX-License-Identifier: Apache-2.0 -use std::sync::Arc; - use anyhow::anyhow; use reqwest::{header, Client, Url}; +use std::sync::Arc; +use toolshed::thegraph::DeploymentId; use crate::query_processor::{QueryError, UnattestedQueryResult}; @@ -34,17 +34,21 @@ impl GraphNodeInstance { pub async fn subgraph_query_raw( &self, - subgraph_id: &str, + subgraph_id: &DeploymentId, data: String, ) -> Result { let request = self .client - .post(self.subgraphs_base_url.join(subgraph_id).map_err(|e| { - QueryError::Other(anyhow!( - "Could not build subgraph query URL: {}", - e.to_string() - )) - })?) + .post( + self.subgraphs_base_url + .join(&subgraph_id.to_string()) + .map_err(|e| { + QueryError::Other(anyhow!( + "Could not build subgraph query URL: {}", + e.to_string() + )) + })?, + ) .body(data) .header(header::CONTENT_TYPE, "application/json"); @@ -63,18 +67,26 @@ impl GraphNodeInstance { #[cfg(test)] mod test { + use std::str::FromStr; + + use lazy_static::lazy_static; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, MockServer, ResponseTemplate}; use super::*; - const NETWORK_SUBGRAPH_ID: &str = "QmV614UpBCpuusv5MsismmPYu4KqLtdeNMKpiNrX56kw6u"; + lazy_static! { + static ref NETWORK_SUBGRAPH_ID: DeploymentId = + DeploymentId::from_str("QmV614UpBCpuusv5MsismmPYu4KqLtdeNMKpiNrX56kw6u").unwrap(); + } async fn mock_graph_node_server() -> MockServer { let mock_server = MockServer::start().await; let mock = Mock::given(method("POST")) - .and(path("/subgraphs/id/".to_string() + NETWORK_SUBGRAPH_ID)) + .and(path( + "/subgraphs/id/".to_string() + &NETWORK_SUBGRAPH_ID.to_string(), + )) .respond_with(ResponseTemplate::new(200).set_body_raw( r#" { @@ -103,8 +115,11 @@ mod test { #[tokio::test] #[ignore] // Run only if explicitly specified async fn test_subgraph_query_local() { - let network_subgraph_id = std::env::var("NETWORK_SUBGRAPH_ID") - .expect("NETWORK_SUBGRAPH_ID env variable is not set"); + let network_subgraph_id = DeploymentId::from_str( + &std::env::var("NETWORK_SUBGRAPH_ID") + .expect("NETWORK_SUBGRAPH_ID env variable is not set"), + ) + .unwrap(); let graph_node = local_graph_node().await; @@ -151,7 +166,7 @@ mod test { }); let response = graph_node - .subgraph_query_raw(NETWORK_SUBGRAPH_ID, query_json.to_string()) + .subgraph_query_raw(&NETWORK_SUBGRAPH_ID, query_json.to_string()) .await .unwrap(); diff --git a/service/src/main.rs b/service/src/main.rs index 5763a35e1..cdbcb980e 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -7,6 +7,7 @@ use axum::Server; use dotenvy::dotenv; use ethereum_types::U256; use std::{net::SocketAddr, str::FromStr}; +use toolshed::thegraph::DeploymentId; use tracing::info; use indexer_common::prelude::{AllocationMonitor, AttestationSigners, NetworkSubgraph}; @@ -99,7 +100,8 @@ async fn main() -> Result<(), std::io::Error> { let escrow_monitor = escrow_monitor::EscrowMonitor::new( graph_node.clone(), - config.escrow_subgraph.escrow_subgraph_deployment, + DeploymentId::from_str(&config.escrow_subgraph.escrow_subgraph_deployment) + .expect("escrow deployment ID is invalid"), config.ethereum.indexer_address, config.escrow_subgraph.escrow_syncing_interval, ) diff --git a/service/src/query_processor.rs b/service/src/query_processor.rs index ae0b683c5..17a1120f2 100644 --- a/service/src/query_processor.rs +++ b/service/src/query_processor.rs @@ -5,8 +5,9 @@ use ethers_core::types::{Signature, U256}; use log::error; use serde::{Deserialize, Serialize}; use tap_core::tap_manager::SignedReceipt; +use toolshed::thegraph::DeploymentId; -use indexer_common::prelude::{AttestationSigner, AttestationSigners, SubgraphDeploymentID}; +use indexer_common::prelude::{AttestationSigner, AttestationSigners}; use crate::graph_node::GraphNodeInstance; use crate::tap_manager::TapManager; @@ -36,13 +37,13 @@ pub struct Response { /// Later add along with PaidQuery #[derive(Debug)] pub struct FreeQuery { - pub subgraph_deployment_id: SubgraphDeploymentID, + pub subgraph_deployment_id: DeploymentId, pub query: String, } /// Paid query needs subgraph_deployment_id, query, receipt pub struct PaidQuery { - pub subgraph_deployment_id: SubgraphDeploymentID, + pub subgraph_deployment_id: DeploymentId, pub query: String, pub receipt: String, } @@ -55,15 +56,11 @@ pub enum QueryError { IndexingError, #[error("Bad or invalid entity data found in the subgraph: {}", .0.to_string())] BadData(anyhow::Error), - #[error("Invalid GraphQL query string: {0}")] - InvalidFormat(String), - #[error("Cannot query field: {:#?}", .0)] - UnsupportedFields(Vec), #[error("Unknown error: {0}")] Other(anyhow::Error), } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] pub struct QueryProcessor { graph_node: GraphNodeInstance, attestation_signers: AttestationSigners, @@ -89,7 +86,7 @@ impl QueryProcessor { ) -> Result, QueryError> { let response = self .graph_node - .subgraph_query_raw(&query.subgraph_deployment_id.ipfs_hash(), query.query) + .subgraph_query_raw(&query.subgraph_deployment_id, query.query) .await?; Ok(Response { @@ -128,7 +125,7 @@ impl QueryProcessor { let response = self .graph_node - .subgraph_query_raw(&subgraph_deployment_id.ipfs_hash(), query.clone()) + .subgraph_query_raw(&subgraph_deployment_id, query.clone()) .await?; let attestation_signature = response @@ -169,78 +166,25 @@ mod tests { attestation_signer_for_allocation, create_attestation_signer, Allocation, AllocationStatus, SubgraphDeployment, }; + use lazy_static::lazy_static; use super::*; const INDEXER_OPERATOR_MNEMONIC: &str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; const INDEXER_ADDRESS: &str = "0x1234567890123456789012345678901234567890"; - #[test] - fn hex_to_ipfs_multihash() { - let deployment_id = "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884abf"; - let expected_ipfs_hash = "QmcPHxcC2ZN7m79XfYZ77YmF4t9UCErv87a9NFKrSLWKtJ"; - - assert_eq!( - SubgraphDeploymentID::from_hex(deployment_id) - .unwrap() - .ipfs_hash(), - expected_ipfs_hash - ); - } - - #[test] - fn ipfs_multihash_to_hex() { - let deployment_id = "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884abf"; - let ipfs_hash = "QmcPHxcC2ZN7m79XfYZ77YmF4t9UCErv87a9NFKrSLWKtJ"; - - assert_eq!( - SubgraphDeploymentID::from_ipfs_hash(ipfs_hash) - .unwrap() - .to_string(), - deployment_id + lazy_static! { + static ref DEPLOYMENT_ID: DeploymentId = DeploymentId( + "0xc064c354bc21dd958b1d41b67b8ef161b75d2246b425f68ed4c74964ae705cbd" + .parse() + .unwrap(), ); } - #[test] - fn subgraph_deployment_id_input_validation_success() { - let deployment_id = "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884abf"; - let ipfs_hash = "QmcPHxcC2ZN7m79XfYZ77YmF4t9UCErv87a9NFKrSLWKtJ"; - - assert_eq!( - SubgraphDeploymentID::new(ipfs_hash).unwrap().to_string(), - deployment_id - ); - - assert_eq!( - SubgraphDeploymentID::new(deployment_id) - .unwrap() - .ipfs_hash(), - ipfs_hash - ); - } - - #[test] - fn subgraph_deployment_id_input_validation_fail() { - let invalid_deployment_id = - "0xd0b0e5b65df45a3fff1a653b4188881318e8459d3338f936aab16c4003884a"; - let invalid_ipfs_hash = "Qm1234"; - - let res = SubgraphDeploymentID::new(invalid_deployment_id); - assert!(res.is_err()); - - let res = SubgraphDeploymentID::new(invalid_ipfs_hash); - assert!(res.is_err()); - } - #[test] fn paid_query_attestation() { - let subgraph_deployment_id = SubgraphDeploymentID::new( - "0xc064c354bc21dd958b1d41b67b8ef161b75d2246b425f68ed4c74964ae705cbd", - ) - .unwrap(); - let subgraph_deployment = SubgraphDeployment { - id: subgraph_deployment_id.clone(), + id: *DEPLOYMENT_ID, denied_at: None, staked_tokens: U256::from(0), signalled_tokens: U256::from(0), @@ -265,12 +209,11 @@ mod tests { let allocation_key = attestation_signer_for_allocation(INDEXER_OPERATOR_MNEMONIC, allocation).unwrap(); - let attestation_signer = create_attestation_signer( U256::from(1), Address::from_str("0xdeadbeefcafebabedeadbeefcafebabedeadbeef").unwrap(), allocation_key, - subgraph_deployment_id.bytes32(), + *DEPLOYMENT_ID, ) .unwrap(); diff --git a/service/src/server/routes/subgraphs.rs b/service/src/server/routes/subgraphs.rs index b21eeac96..128ff9f9b 100644 --- a/service/src/server/routes/subgraphs.rs +++ b/service/src/server/routes/subgraphs.rs @@ -7,10 +7,10 @@ use axum::{ response::IntoResponse, Json, }; +use std::str::FromStr; +use toolshed::thegraph::DeploymentId; use tracing::trace; -use indexer_common::prelude::SubgraphDeploymentID; - use crate::{ metrics, query_processor::FreeQuery, @@ -31,11 +31,11 @@ pub async fn subgraph_queries( let (parts, body) = req.into_parts(); // Initialize id into a subgraph deployment ID - let subgraph_deployment_id = match SubgraphDeploymentID::new(id.as_str()) { + let subgraph_deployment_id = match DeploymentId::from_str(id.as_str()) { Ok(id) => id, Err(e) => return bad_request_response(&e.to_string()), }; - let deployment_label = subgraph_deployment_id.ipfs_hash(); + let deployment_label = subgraph_deployment_id.to_string(); let query_duration_timer = metrics::QUERY_DURATION .with_label_values(&[&deployment_label])