diff --git a/crates/sui-indexer-alt/migrations/2024-11-02-014903_kv_feature_flags/down.sql b/crates/sui-indexer-alt/migrations/2024-11-02-014903_kv_feature_flags/down.sql new file mode 100644 index 0000000000000..90412a754d6f3 --- /dev/null +++ b/crates/sui-indexer-alt/migrations/2024-11-02-014903_kv_feature_flags/down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS kv_feature_flags; diff --git a/crates/sui-indexer-alt/migrations/2024-11-02-014903_kv_feature_flags/up.sql b/crates/sui-indexer-alt/migrations/2024-11-02-014903_kv_feature_flags/up.sql new file mode 100644 index 0000000000000..a3ef3cc1b5fbb --- /dev/null +++ b/crates/sui-indexer-alt/migrations/2024-11-02-014903_kv_feature_flags/up.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS kv_feature_flags +( + protocol_version BIGINT NOT NULL, + flag_name TEXT NOT NULL, + flag_value BOOLEAN NOT NULL, + PRIMARY KEY (protocol_version, flag_name) +); diff --git a/crates/sui-indexer-alt/src/handlers/kv_feature_flags.rs b/crates/sui-indexer-alt/src/handlers/kv_feature_flags.rs new file mode 100644 index 0000000000000..f992f0a17c58e --- /dev/null +++ b/crates/sui-indexer-alt/src/handlers/kv_feature_flags.rs @@ -0,0 +1,68 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use anyhow::{Context, Result}; +use diesel_async::RunQueryDsl; +use sui_protocol_config::ProtocolConfig; +use sui_types::full_checkpoint_content::CheckpointData; + +use crate::{ + db, + models::{checkpoints::StoredGenesis, epochs::StoredFeatureFlag}, + pipeline::{concurrent::Handler, Processor}, + schema::kv_feature_flags, +}; + +pub struct KvFeatureFlags(pub StoredGenesis); + +impl Processor for KvFeatureFlags { + const NAME: &'static str = "kv_protocol_configs"; + type Value = StoredFeatureFlag; + + fn process(&self, checkpoint: &Arc) -> Result> { + let CheckpointData { + checkpoint_summary, .. + } = checkpoint.as_ref(); + + let protocol_version = if checkpoint_summary.sequence_number == 0 { + self.0.initial_protocol_version() + } else if let Some(end_of_epoch) = checkpoint_summary.end_of_epoch_data.as_ref() { + end_of_epoch.next_epoch_protocol_version + } else { + return Ok(vec![]); + }; + + let protocol_config = ProtocolConfig::get_for_version( + protocol_version, + self.0.chain().context("Failed to identify chain")?, + ); + + let protocol_version = protocol_version.as_u64() as i64; + Ok(protocol_config + .feature_map() + .into_iter() + .map(|(flag_name, flag_value)| StoredFeatureFlag { + protocol_version, + flag_name, + flag_value, + }) + .collect()) + } +} + +#[async_trait::async_trait] +impl Handler for KvFeatureFlags { + const MIN_EAGER_ROWS: usize = 1; + const MAX_CHUNK_ROWS: usize = i16::MAX as usize / 3; + const MAX_PENDING_ROWS: usize = 10000; + + async fn commit(values: &[Self::Value], conn: &mut db::Connection<'_>) -> Result { + Ok(diesel::insert_into(kv_feature_flags::table) + .values(values) + .on_conflict_do_nothing() + .execute(conn) + .await?) + } +} diff --git a/crates/sui-indexer-alt/src/handlers/mod.rs b/crates/sui-indexer-alt/src/handlers/mod.rs index 7fbe5e441d519..3d74ce6cb0b80 100644 --- a/crates/sui-indexer-alt/src/handlers/mod.rs +++ b/crates/sui-indexer-alt/src/handlers/mod.rs @@ -4,6 +4,7 @@ pub mod ev_emit_mod; pub mod ev_struct_inst; pub mod kv_checkpoints; +pub mod kv_feature_flags; pub mod kv_objects; pub mod kv_protocol_configs; pub mod kv_transactions; diff --git a/crates/sui-indexer-alt/src/main.rs b/crates/sui-indexer-alt/src/main.rs index 2f95da6167778..8e11d1e5dc2a4 100644 --- a/crates/sui-indexer-alt/src/main.rs +++ b/crates/sui-indexer-alt/src/main.rs @@ -6,6 +6,7 @@ use clap::Parser; use sui_indexer_alt::args::Command; use sui_indexer_alt::bootstrap::bootstrap; use sui_indexer_alt::db::reset_database; +use sui_indexer_alt::handlers::kv_feature_flags::KvFeatureFlags; use sui_indexer_alt::handlers::kv_protocol_configs::KvProtocolConfigs; use sui_indexer_alt::{ args::Args, @@ -42,11 +43,13 @@ async fn main() -> Result<()> { let mut indexer = Indexer::new(args.db_config, indexer, cancel.clone()).await?; let genesis = bootstrap(&indexer, retry_interval, cancel.clone()).await?; - let kv_protocol_configs = KvProtocolConfigs(genesis.clone()); + let kv_feature_flags = KvFeatureFlags(genesis.clone()); + let kv_protocol_configs = KvProtocolConfigs(genesis); indexer.concurrent_pipeline(EvEmitMod).await?; indexer.concurrent_pipeline(EvStructInst).await?; indexer.concurrent_pipeline(KvCheckpoints).await?; + indexer.concurrent_pipeline(kv_feature_flags).await?; indexer.concurrent_pipeline(KvObjects).await?; indexer.concurrent_pipeline(kv_protocol_configs).await?; indexer.concurrent_pipeline(KvTransactions).await?; diff --git a/crates/sui-indexer-alt/src/models/epochs.rs b/crates/sui-indexer-alt/src/models/epochs.rs index ab3eb14e7503a..69212a54ec078 100644 --- a/crates/sui-indexer-alt/src/models/epochs.rs +++ b/crates/sui-indexer-alt/src/models/epochs.rs @@ -4,7 +4,15 @@ use diesel::prelude::*; use sui_field_count::FieldCount; -use crate::schema::kv_protocol_configs; +use crate::schema::{kv_feature_flags, kv_protocol_configs}; + +#[derive(Insertable, Debug, Clone, FieldCount)] +#[diesel(table_name = kv_feature_flags)] +pub struct StoredFeatureFlag { + pub protocol_version: i64, + pub flag_name: String, + pub flag_value: bool, +} #[derive(Insertable, Debug, Clone, FieldCount)] #[diesel(table_name = kv_protocol_configs)] diff --git a/crates/sui-indexer-alt/src/schema.rs b/crates/sui-indexer-alt/src/schema.rs index 7e72f700f2b0c..0d98bc2cce021 100644 --- a/crates/sui-indexer-alt/src/schema.rs +++ b/crates/sui-indexer-alt/src/schema.rs @@ -30,6 +30,14 @@ diesel::table! { } } +diesel::table! { + kv_feature_flags (protocol_version, flag_name) { + protocol_version -> Int8, + flag_name -> Text, + flag_value -> Bool, + } +} + diesel::table! { kv_genesis (genesis_digest) { genesis_digest -> Bytea, @@ -205,6 +213,7 @@ diesel::allow_tables_to_appear_in_same_query!( ev_emit_mod, ev_struct_inst, kv_checkpoints, + kv_feature_flags, kv_genesis, kv_objects, kv_protocol_configs,