Skip to content

Commit

Permalink
update chain ident when it was previously unset
Browse files Browse the repository at this point in the history
  • Loading branch information
mangas committed May 17, 2024
1 parent bb58953 commit f6f5b6d
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 12 deletions.
146 changes: 138 additions & 8 deletions graph/src/components/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ pub trait IdentValidator: Sync + Send {
chain_id: &ChainId,
ident: &ChainIdentifier,
) -> Result<(), IdentValidatorError>;

fn update_ident(
&self,
chain_id: &ChainId,
ident: &ChainIdentifier,
) -> Result<(), anyhow::Error>;
}

impl<T: ChainStoreTrait, B: BlockStoreTrait<ChainStore = T>> IdentValidator for B {
Expand Down Expand Up @@ -145,6 +151,20 @@ impl<T: ChainStoreTrait, B: BlockStoreTrait<ChainStore = T>> IdentValidator for

return Ok(());
}

fn update_ident(
&self,
chain_id: &ChainId,
ident: &ChainIdentifier,
) -> Result<(), anyhow::Error> {
let network_chain = self
.chain_store(&chain_id)
.ok_or_else(|| IdentValidatorError::UnavailableStore(chain_id.clone()))?;

network_chain.set_chain_identifier(ident)?;

Ok(())
}
}

pub struct MockIdentValidator;
Expand All @@ -157,6 +177,14 @@ impl IdentValidator for MockIdentValidator {
) -> Result<(), IdentValidatorError> {
Ok(())
}

fn update_ident(
&self,
_chain_id: &ChainId,
_ident: &ChainIdentifier,
) -> Result<(), anyhow::Error> {
Ok(())
}
}

/// ProviderCorrectness will maintain a list of providers which have had their
Expand Down Expand Up @@ -453,7 +481,9 @@ impl<T: NetIdentifiable + 'static> Inner<T> {
}
Err(err) => match err {
IdentValidatorError::UnsetIdent => {
// todo: update chain?
self.validator
.update_ident(&ident.chain_id, &chain_ident)
.map_err(ProviderManagerError::from)?;
*status = GenesisCheckStatus::Valid;
}
IdentValidatorError::ChangedNetVersion {
Expand Down Expand Up @@ -531,15 +561,24 @@ enum GenesisCheckStatus {

#[cfg(test)]
mod test {
use std::{ops::Sub, sync::Arc};
use std::{
ops::Sub,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};

use crate::{
bail,
blockchain::BlockHash,
components::adapter::{ChainId, GenesisCheckStatus, MockIdentValidator},
data::value::Word,
prelude::lazy_static,
};
use async_trait::async_trait;
use chrono::{Duration, Utc};
use ethabi::ethereum_types::H256;
use slog::{o, Discard, Logger};

use crate::{blockchain::ChainIdentifier, components::adapter::ProviderManagerError};
Expand All @@ -566,10 +605,12 @@ mod test {
};
static ref VALID_ADAPTER: MockAdapter = MockAdapter {provider: "valid".into(), status: GenesisCheckStatus::Valid,};
static ref FAILED_ADAPTER: MockAdapter = MockAdapter {provider: "FAILED".into(), status: GenesisCheckStatus::Failed,};
static ref NEW_CHAIN_IDENT: ChainIdentifier =ChainIdentifier { net_version: "123".to_string(), genesis_block_hash: BlockHash::from( H256::repeat_byte(1))};
}

struct TestValidator {
result: Result<(), IdentValidatorError>,
check_result: Result<(), IdentValidatorError>,
expected_new_ident: Option<ChainIdentifier>,
}

impl IdentValidator for TestValidator {
Expand All @@ -578,7 +619,19 @@ mod test {
_chain_id: &ChainId,
_ident: &ChainIdentifier,
) -> Result<(), IdentValidatorError> {
self.result.clone()
self.check_result.clone()
}

fn update_ident(
&self,
_chain_id: &ChainId,
ident: &ChainIdentifier,
) -> Result<(), anyhow::Error> {
match self.expected_new_ident.as_ref() {
None => unreachable!("unexpected call to update_ident"),
Some(ident_expected) if ident_expected.eq(ident) => Ok(()),
Some(_) => bail!("update_ident called with unexpected value"),
}
}
}

Expand All @@ -598,7 +651,7 @@ mod test {
{
unreachable!("should never check if ttl has not elapsed");
}
_ => Ok(ChainIdentifier::default()),
_ => Ok(NEW_CHAIN_IDENT.clone()),
}
}

Expand Down Expand Up @@ -626,7 +679,17 @@ mod test {
expected: Ok(vec![]),
},
Case {
name: "adapter temporary failure with Ident None",
name: "no adapters",
chain_id: TEST_CHAIN_ID,
adapters: vec![(TEST_CHAIN_ID.into(), vec![TESTABLE_ADAPTER.clone()])],
validator: Some(TestValidator {
check_result: Err(IdentValidatorError::UnsetIdent),
expected_new_ident: Some(NEW_CHAIN_IDENT.clone()),
}),
expected: Ok(vec![&TESTABLE_ADAPTER]),
},
Case {
name: "adapter temporary failure with Ident unset",
chain_id: TEST_CHAIN_ID,
// UNTESTABLE_ADAPTER has failed ident, will be valid cause idents has None value
adapters: vec![(TEST_CHAIN_ID.into(), vec![UNTESTABLE_ADAPTER.clone()])],
Expand All @@ -649,11 +712,12 @@ mod test {
chain_id: TEST_CHAIN_ID,
adapters: vec![(TEST_CHAIN_ID.into(), vec![FAILED_ADAPTER.clone()])],
validator: Some(TestValidator {
result: Err(IdentValidatorError::ChangedNetVersion {
check_result: Err(IdentValidatorError::ChangedNetVersion {
chain_id: TEST_CHAIN_ID.into(),
store_net_version: "".to_string(),
chain_net_version: "".to_string(),
}),
expected_new_ident: None,
}),
expected: Err(ProviderManagerError::AllProvidersFailed(
TEST_CHAIN_ID.into(),
Expand All @@ -668,11 +732,12 @@ mod test {
)],
// if a check is performed (which it shouldn't) the test will fail
validator: Some(TestValidator {
result: Err(IdentValidatorError::ChangedNetVersion {
check_result: Err(IdentValidatorError::ChangedNetVersion {
chain_id: TEST_CHAIN_ID.into(),
store_net_version: "".to_string(),
chain_net_version: "".to_string(),
}),
expected_new_ident: None,
}),
expected: Ok(vec![&VALID_ADAPTER]),
},
Expand Down Expand Up @@ -749,4 +814,69 @@ mod test {
}
}
}

#[tokio::test]
async fn test_provider_manager_updates_on_unset() {
#[derive(Clone, Debug, Eq, PartialEq)]
struct MockAdapter {}

#[async_trait]
impl NetIdentifiable for MockAdapter {
async fn net_identifiers(&self) -> Result<ChainIdentifier, anyhow::Error> {
Ok(NEW_CHAIN_IDENT.clone())
}
fn provider_name(&self) -> ProviderName {
TEST_CHAIN_ID.into()
}
}

struct TestValidator {
called: AtomicBool,
err: IdentValidatorError,
}

impl IdentValidator for TestValidator {
fn check_ident(
&self,
_chain_id: &ChainId,
_ident: &ChainIdentifier,
) -> Result<(), IdentValidatorError> {
Err(self.err.clone())
}

fn update_ident(
&self,
_chain_id: &ChainId,
ident: &ChainIdentifier,
) -> Result<(), anyhow::Error> {
if NEW_CHAIN_IDENT.eq(ident) {
self.called.store(true, Ordering::SeqCst);
return Ok(());
}

unreachable!("unexpected call to update_ident ot unexpected ident passed");
}
}

let logger = Logger::root(Discard, o!());
let chain_id = TEST_CHAIN_ID.into();

// Ensure the provider updates the chain ident when it wasn't set yet.
let validator = Arc::new(TestValidator {
called: AtomicBool::default(),
err: IdentValidatorError::UnsetIdent,
});
let adapter = MockAdapter {};

let manager = ProviderManager::new(
logger,
vec![(TEST_CHAIN_ID.into(), vec![adapter.clone()])].into_iter(),
validator.clone(),
);

let mut result = manager.get_all(&chain_id).await.unwrap();
assert_eq!(result.len(), 1);
assert_eq!(&adapter, result.pop().unwrap());
assert_eq!(validator.called.load(Ordering::SeqCst), true);
}
}
2 changes: 1 addition & 1 deletion graph/src/components/store/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ pub trait ChainStore: Send + Sync + 'static {
fn chain_identifier(&self) -> Result<ChainIdentifier, Error>;

/// Update the chain identifier for this store.
fn set_chain_identifier(&self, ident: ChainIdentifier) -> Result<(), Error>;
fn set_chain_identifier(&self, ident: &ChainIdentifier) -> Result<(), Error>;
}

pub trait EthereumCallCache: Send + Sync + 'static {
Expand Down
6 changes: 3 additions & 3 deletions store/postgres/src/chain_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1765,7 +1765,7 @@ impl ChainStore {
self.upsert_block(block).await.expect("can upsert block");
}

self.set_chain_identifier(ChainIdentifier {
self.set_chain_identifier(&ChainIdentifier {
net_version: "0".to_string(),
genesis_block_hash: BlockHash::try_from(genesis_hash).expect("valid block hash"),
})
Expand Down Expand Up @@ -2256,14 +2256,14 @@ impl ChainStoreTrait for ChainStore {
.await
}

fn set_chain_identifier(&self, ident: ChainIdentifier) -> Result<(), Error> {
fn set_chain_identifier(&self, ident: &ChainIdentifier) -> Result<(), Error> {
use public::ethereum_networks as n;

let mut conn = self.pool.get()?;
diesel::update(n::table.filter(n::name.eq(&self.chain)))
.set((
n::genesis_block_hash.eq(ident.genesis_block_hash.hash_hex()),
n::net_version.eq(ident.net_version),
n::net_version.eq(&ident.net_version),
))
.execute(&mut conn)?;

Expand Down

0 comments on commit f6f5b6d

Please sign in to comment.