diff --git a/docs/environment-variables.md b/docs/environment-variables.md index 5e5bfb32d91..526bff01e70 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -294,3 +294,7 @@ those. `GRAPH_STORE_ACCOUNT_LIKE_MIN_VERSIONS_COUNT` and `GRAPH_STORE_ACCOUNT_LIKE_MAX_UNIQUE_RATIO`. - `GRAPH_STORE_ACCOUNT_LIKE_MIN_VERSIONS_COUNT`: Sets the minimum total number of versions a table must have to be considered for account-like flagging. Expects a positive integer value. No default value. - `GRAPH_STORE_ACCOUNT_LIKE_MAX_UNIQUE_RATIO`: Sets the maximum unique entities to version ratio (e.g., 0.01 ≈ 1:100 entity-to-version ratio). +- `GRAPH_STORE_DISABLE_CALL_CACHE`: Disables the store call cache entirely. Graph node will skip writing and reading from the + call cache. The buffered block call cache will still be enabled. This option may be useful + for indexers who are running their own RPC nodes. Disabling the store call cache may have + significant performance impact. (default: false) diff --git a/graph/src/env/mod.rs b/graph/src/env/mod.rs index 3fce087986e..905907e39b9 100644 --- a/graph/src/env/mod.rs +++ b/graph/src/env/mod.rs @@ -25,6 +25,7 @@ lazy_static! { lazy_static! { pub static ref TEST_WITH_NO_REORG: Mutex = Mutex::new(false); pub static ref TEST_SQL_QUERIES_ENABLED: Mutex = Mutex::new(false); + pub static ref TEST_STORE_CALL_CACHE_DISABLED: Mutex = Mutex::new(false); } /// Panics if: @@ -441,6 +442,25 @@ impl EnvVars { let mut lock = TEST_SQL_QUERIES_ENABLED.lock().unwrap(); *lock = enable; } + + #[cfg(debug_assertions)] + pub fn store_call_cache_disabled(&self) -> bool { + if *TEST_STORE_CALL_CACHE_DISABLED.lock().unwrap() { + true + } else { + self.store.disable_call_cache + } + } + + #[cfg(not(debug_assertions))] + pub fn store_call_cache_disabled(&self) -> bool { + self.store.disable_call_cache + } + + #[cfg(debug_assertions)] + pub fn set_store_call_cache_disabled_for_tests(&self, value: bool) { + *TEST_STORE_CALL_CACHE_DISABLED.lock().unwrap() = value; + } } impl Default for EnvVars { diff --git a/graph/src/env/store.rs b/graph/src/env/store.rs index 6d51b04ba34..a481a9890d0 100644 --- a/graph/src/env/store.rs +++ b/graph/src/env/store.rs @@ -149,7 +149,6 @@ pub struct EnvVarsStore { /// The number of rows to fetch from the foreign data wrapper in one go, /// this will be set as the option 'fetch_size' on all foreign servers pub fdw_fetch_size: usize, - /// Experimental feature to automatically set the account-like flag on eligible tables /// Set by the environment variable `GRAPH_STORE_ACCOUNT_LIKE_SCAN_INTERVAL_HOURS` /// If not set, the job is disabled. @@ -161,6 +160,10 @@ pub struct EnvVarsStore { /// Set by the environment variable `GRAPH_STORE_ACCOUNT_LIKE_MAX_UNIQUE_RATIO` /// Defines the maximum share of unique entities (e.g. 0.01 for a 1:100 entity-to-version ratio). pub account_like_max_unique_ratio: Option, + /// Disables the store call cache entirely. Graph node will skip writing and reading from the + /// call cache. The buffered block call cache will still be enabled. + /// Set by `GRAPH_STORE_DISABLE_CALL_CACHE`. Defaults to false. + pub disable_call_cache: bool, } // This does not print any values avoid accidentally leaking any sensitive env vars @@ -221,6 +224,7 @@ impl TryFrom for EnvVarsStore { account_like_scan_interval_hours: x.account_like_scan_interval_hours, account_like_min_versions_count: x.account_like_min_versions_count, account_like_max_unique_ratio: x.account_like_max_unique_ratio.map(|r| r.0), + disable_call_cache: x.disable_call_cache, }; if let Some(timeout) = vars.batch_timeout { if timeout < 2 * vars.batch_target_duration { @@ -326,6 +330,8 @@ pub struct InnerStore { account_like_min_versions_count: Option, #[envconfig(from = "GRAPH_STORE_ACCOUNT_LIKE_MAX_UNIQUE_RATIO")] account_like_max_unique_ratio: Option, + #[envconfig(from = "GRAPH_STORE_DISABLE_CALL_CACHE", default = "false")] + disable_call_cache: bool, } #[derive(Clone, Copy, Debug)] diff --git a/store/postgres/src/chain_store.rs b/store/postgres/src/chain_store.rs index eadde677f96..8f2cfe79925 100644 --- a/store/postgres/src/chain_store.rs +++ b/store/postgres/src/chain_store.rs @@ -3103,6 +3103,10 @@ impl EthereumCallCache for ChainStore { req: &call::Request, block: BlockPtr, ) -> Result, Error> { + if ENV_VARS.store_call_cache_disabled() { + return Ok(None); + } + let id = contract_call_id(req, &block); let conn = &mut self.pool.get_permitted().await?; let return_value = conn @@ -3193,6 +3197,10 @@ impl EthereumCallCache for ChainStore { block: BlockPtr, return_value: call::Retval, ) -> Result<(), Error> { + if ENV_VARS.store_call_cache_disabled() { + return Ok(()); + } + let return_value = match return_value { call::Retval::Value(return_value) if !return_value.is_empty() => return_value, _ => { diff --git a/store/test-store/tests/postgres/chain_head.rs b/store/test-store/tests/postgres/chain_head.rs index 98f1045de7a..06f4fb9e937 100644 --- a/store/test-store/tests/postgres/chain_head.rs +++ b/store/test-store/tests/postgres/chain_head.rs @@ -529,6 +529,41 @@ fn eth_call_cache() { }) } +#[test] +fn test_disable_call_cache() { + let chain = vec![&*GENESIS_BLOCK, &*BLOCK_ONE, &*BLOCK_TWO]; + + run_test_async(chain, |store, _, _| async move { + ENV_VARS.set_store_call_cache_disabled_for_tests(true); + + let logger = LOGGER.cheap_clone(); + let address = H160([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5]); + let call: [u8; 6] = [1, 2, 3, 4, 5, 6]; + let return_value: [u8; 3] = [7, 8, 9]; + + let call = call::Request::new(address, call.to_vec(), 0); + + store + .cheap_clone() + .set_call( + &logger, + call.cheap_clone(), + BLOCK_ONE.block_ptr(), + call::Retval::Value(Bytes::from(return_value)), + ) + .await + .unwrap(); + + let ret = store + .cheap_clone() + .get_call(&call, BLOCK_ONE.block_ptr()) + .await + .unwrap(); + + assert!(ret.is_none()); + }); +} + #[test] /// Tests mainly query correctness. Requires data in order not to hit early returns when no stale contracts are found. fn test_clear_stale_call_cache() {