Skip to content

Commit e09833a

Browse files
committed
node, store: Do not fail startup when genesis block for a chain failed
Instead of crashing the node when the genesis block for a chain changed, log an error and do not start a block ingestor for that chain.
1 parent 91e6b22 commit e09833a

File tree

3 files changed

+88
-42
lines changed

3 files changed

+88
-42
lines changed

node/src/main.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -661,17 +661,25 @@ fn start_block_ingestor(
661661
eth_networks
662662
.networks
663663
.iter()
664-
.for_each(|(network_name, eth_adapters)| {
664+
.filter_map(|(network_name, eth_adapters)| {
665+
let chain_store = block_store
666+
.chain_store(network_name)
667+
.expect("network with name");
668+
if chain_store.is_ingestible() {
669+
Some((network_name, eth_adapters, chain_store))
670+
} else {
671+
None
672+
}
673+
})
674+
.for_each(|(network_name, eth_adapters, chain_store)| {
665675
info!(
666676
logger,
667677
"Starting block ingestor for network";
668678
"network_name" => &network_name
669679
);
670680
let eth_adapter = eth_adapters.cheapest().unwrap(); //Safe to unwrap since it cannot be empty
671681
let block_ingestor = BlockIngestor::new(
672-
block_store
673-
.chain_store(network_name)
674-
.expect("network with name"),
682+
chain_store,
675683
eth_adapter.clone(),
676684
*ANCESTOR_COUNT,
677685
network_name.to_string(),

store/postgres/src/block_store.rs

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ use crate::{subgraph_store::PRIMARY_SHARD, Shard};
2323
#[cfg(debug_assertions)]
2424
pub const FAKE_NETWORK_SHARED: &str = "fake_network_shared";
2525

26+
/// The status of a chain: whether we can only read from the chain, or
27+
/// whether it is ok to ingest from it, too
28+
#[derive(Copy, Clone)]
29+
pub enum ChainStatus {
30+
ReadOnly,
31+
Ingestible,
32+
}
33+
2634
mod primary {
2735
use std::str::FromStr;
2836

@@ -214,57 +222,77 @@ impl BlockStore {
214222
}
215223
}
216224

225+
/// Check that the configuration for `chain` hasn't changed so that
226+
/// it is ok to ingest from it
227+
fn chain_ingestible(
228+
logger: &Logger,
229+
chain: &primary::Chain,
230+
shard: &Shard,
231+
ident: &Option<EthereumNetworkIdentifier>,
232+
) -> bool {
233+
if &chain.shard != shard {
234+
error!(
235+
logger,
236+
"the chain {} is stored in shard {} but is configured for shard {}",
237+
chain.name,
238+
chain.shard,
239+
shard
240+
);
241+
return false;
242+
}
243+
if let Some(ident) = ident {
244+
if chain.net_version != ident.net_version {
245+
error!(logger,
246+
"the net version for chain {} has changed from {} to {} since the last time we ran",
247+
chain.name,
248+
chain.net_version,
249+
ident.net_version
250+
);
251+
return false;
252+
}
253+
if &chain.genesis_block != &format!("{:x}", ident.genesis_block_hash) {
254+
error!(logger,
255+
"the genesis block hash for chain {} has changed from {} to {:x} since the last time we ran",
256+
chain.name,
257+
chain.genesis_block,
258+
ident.genesis_block_hash
259+
);
260+
return false;
261+
}
262+
}
263+
return true;
264+
}
265+
217266
// For each configured chain, add a chain store
218267
for (chain_name, idents, shard) in chains {
219268
let ident = reduce_idents(&chain_name, idents)?;
220-
let (chain, create) = match (
269+
match (
221270
existing_chains
222271
.iter()
223272
.find(|chain| chain.name == chain_name),
224273
ident,
225274
) {
226275
(Some(chain), ident) => {
227-
if chain.shard != shard {
228-
return Err(StoreError::Unknown(anyhow!(
229-
"the chain {} is stored in shard {} but is configured for shard {}",
230-
chain.name,
231-
chain.shard,
232-
shard
233-
)));
234-
}
235-
if let Some(ident) = ident {
236-
if chain.net_version != ident.net_version {
237-
return Err(StoreError::Unknown(anyhow!(
238-
"the net version for chain {} has changed from {} to {} since the last time we ran",
239-
chain.name,
240-
chain.net_version,
241-
ident.net_version
242-
)));
243-
}
244-
if &chain.genesis_block != &format!("{:x}", ident.genesis_block_hash) {
245-
return Err(StoreError::Unknown(anyhow!(
246-
"the genesis block hash for chain {} has changed from {} to {:x} since the last time we ran",
247-
chain.name,
248-
chain.genesis_block,
249-
ident.genesis_block_hash
250-
)));
251-
}
252-
}
253-
(chain.clone(), false)
276+
let status = if chain_ingestible(&block_store.logger, chain, &shard, &ident) {
277+
ChainStatus::Ingestible
278+
} else {
279+
ChainStatus::ReadOnly
280+
};
281+
block_store.add_chain_store(&chain, status, false)?;
282+
}
283+
(None, Some(ident)) => {
284+
let chain =
285+
primary::add_chain(&block_store.primary, &chain_name, &ident, &shard)?;
286+
block_store.add_chain_store(&chain, ChainStatus::Ingestible, true)?;
254287
}
255-
(None, Some(ident)) => (
256-
primary::add_chain(&block_store.primary, &chain_name, &ident, &shard)?,
257-
true,
258-
),
259288
(None, None) => {
260-
return Err(StoreError::Unknown(anyhow!(
289+
error!(
290+
&block_store.logger,
261291
" the chain {} is new but we could not get a network identifier for it",
262292
chain_name
263-
)));
293+
);
264294
}
265295
};
266-
267-
block_store.add_chain_store(&chain, create)?;
268296
}
269297

270298
// There might be chains we have in the database that are not yet/
@@ -280,14 +308,15 @@ impl BlockStore {
280308
.iter()
281309
.filter(|chain| !configured_chains.contains(&chain.name))
282310
{
283-
block_store.add_chain_store(&chain, false)?;
311+
block_store.add_chain_store(&chain, ChainStatus::ReadOnly, false)?;
284312
}
285313
Ok(block_store)
286314
}
287315

288316
fn add_chain_store(
289317
&self,
290318
chain: &primary::Chain,
319+
status: ChainStatus,
291320
create: bool,
292321
) -> Result<Arc<ChainStore>, StoreError> {
293322
let pool = self
@@ -301,6 +330,7 @@ impl BlockStore {
301330
chain.name.clone(),
302331
chain.storage.clone(),
303332
&ident,
333+
status,
304334
self.chain_head_update_listener.clone(),
305335
sender,
306336
pool,
@@ -343,7 +373,7 @@ impl BlockStore {
343373
// of the configured chains
344374
let conn = self.primary.get()?;
345375
primary::find_chain(&conn, chain)?
346-
.map(|chain| self.add_chain_store(&chain, false))
376+
.map(|chain| self.add_chain_store(&chain, ChainStatus::ReadOnly, false))
347377
.transpose()
348378
}
349379

store/postgres/src/chain_store.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use graph::prelude::{
2121
};
2222

2323
use crate::{
24+
block_store::ChainStatus,
2425
chain_head_listener::{ChainHeadUpdateListener, ChainHeadUpdateSender},
2526
connection_pool::ConnectionPool,
2627
};
@@ -1060,6 +1061,7 @@ pub struct ChainStore {
10601061
pub chain: String,
10611062
storage: data::Storage,
10621063
genesis_block_ptr: EthereumBlockPointer,
1064+
status: ChainStatus,
10631065
chain_head_update_listener: Arc<ChainHeadUpdateListener>,
10641066
chain_head_update_sender: ChainHeadUpdateSender,
10651067
}
@@ -1069,6 +1071,7 @@ impl ChainStore {
10691071
chain: String,
10701072
storage: data::Storage,
10711073
net_identifier: &EthereumNetworkIdentifier,
1074+
status: ChainStatus,
10721075
chain_head_update_listener: Arc<ChainHeadUpdateListener>,
10731076
chain_head_update_sender: ChainHeadUpdateSender,
10741077
pool: ConnectionPool,
@@ -1078,13 +1081,18 @@ impl ChainStore {
10781081
chain,
10791082
storage,
10801083
genesis_block_ptr: (net_identifier.genesis_block_hash, 0 as u64).into(),
1084+
status,
10811085
chain_head_update_listener,
10821086
chain_head_update_sender,
10831087
};
10841088

10851089
store
10861090
}
10871091

1092+
pub fn is_ingestible(&self) -> bool {
1093+
matches!(self.status, ChainStatus::Ingestible)
1094+
}
1095+
10881096
fn get_conn(&self) -> Result<PooledConnection<ConnectionManager<PgConnection>>, Error> {
10891097
self.conn.get().map_err(Error::from)
10901098
}

0 commit comments

Comments
 (0)