iota_core/
verify_indexes.rs1use std::{collections::BTreeMap, sync::Arc};
6
7use anyhow::{Result, anyhow, bail};
8use iota_types::{base_types::ObjectInfo, object::Owner};
9use tracing::info;
10use typed_store::traits::Map;
11
12use crate::{
13 authority::authority_store_tables::LiveObject,
14 jsonrpc_index::{CoinInfo, IndexStore},
15 state_accumulator::AccumulatorStore,
16};
17
18pub fn verify_indexes(store: &dyn AccumulatorStore, indexes: Arc<IndexStore>) -> Result<()> {
22 info!("Begin running index verification checks");
23
24 let mut owner_index = BTreeMap::new();
25 let mut coin_index = BTreeMap::new();
26
27 tracing::info!("Reading live objects set");
28 for object in store.iter_live_object_set() {
29 let LiveObject::Normal(object) = object else {
30 continue;
31 };
32 let Owner::AddressOwner(owner) = object.owner else {
33 continue;
34 };
35
36 let owner_index_key = (owner, object.id());
38 let object_info = ObjectInfo::new(&object.compute_object_reference(), &object);
39
40 owner_index.insert(owner_index_key, object_info);
41
42 if let Some(type_tag) = object.coin_type_maybe() {
44 let info =
45 CoinInfo::from_object(&object).expect("already checked that this is a coin type");
46 let key = (owner, type_tag.to_string(), object.id());
47
48 coin_index.insert(key, info);
49 }
50 }
51
52 tracing::info!("Live objects set is prepared, about to verify indexes");
53
54 for item in indexes.tables().owner_index().safe_iter() {
56 let (key, info) = item?;
57 let calculated_info = owner_index.remove(&key).ok_or_else(|| {
58 anyhow!(
59 "owner_index: found extra, unexpected entry {:?}",
60 (&key, &info)
61 )
62 })?;
63
64 if calculated_info != info {
65 bail!(
66 "owner_index: entry {key:?} is different: expected {calculated_info:?} found {info:?}"
67 );
68 }
69 }
70
71 if !owner_index.is_empty() {
72 bail!("owner_index: is missing entries: {owner_index:?}");
73 }
74 tracing::info!("Owner index is good");
75
76 for item in indexes.tables().coin_index().safe_iter() {
78 let (key, info) = item?;
79 let calculated_info = coin_index.remove(&key).ok_or_else(|| {
80 anyhow!(
81 "coin_index: found extra, unexpected entry {:?}",
82 (&key, &info)
83 )
84 })?;
85
86 if calculated_info != info {
87 bail!(
88 "coin_index: entry {key:?} is different: expected {calculated_info:?} found {info:?}"
89 );
90 }
91 }
92 tracing::info!("Coin index is good");
93
94 if !coin_index.is_empty() {
95 bail!("coin_index: is missing entries: {coin_index:?}");
96 }
97
98 info!("Finished running index verification checks");
99
100 Ok(())
101}