Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce init tip setting for indexer to skip previous block synchronization #4244

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions resource/ckb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,11 @@ block_uncles_cache_size = 30
# [indexer_v2]
# # Indexing the pending txs in the ckb tx-pool
# index_tx_pool = false
# # Customize block filtering rules to index only retained blocks
# block_filter = "block.header.number.to_uint() >= \"0x0\".to_uint()"
# # Customize cell filtering rules to index only retained cells
# cell_filter = "let script = output.type;script!=() && script.code_hash == \"0x00000000000000000000000000000000000000000000000000545950455f4944\""
# # The initial tip number and hash can be set as the starting height for building indexes in indexer-r. Effective only during the initial index creation.
# init_tip_number = 10000
# # The initial tip hash must match the tip number; otherwise, it will result in a rollback to empty.
# init_tip_hash = "0x8fbd0ec887159d2814cee475911600e3589849670f5ee1ed9798b38fdeef4e44"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest to use one block hash parameter only, indexer may use get_header rpc to fetch the block number, and start the indexing service only when corresponding header was found.

Copy link
Collaborator Author

@EthanYuan EthanYuan Nov 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entering a number manually considering a situation where the block height of the node itself may not have been reached and get_header may fail.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please refer to my previous comment:

start the indexing service only when corresponding header was found.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another issue is that if the hash is wrong, then there is no chance of rollback.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indexer service won't starting if the hash is wrong.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, got it.

9 changes: 9 additions & 0 deletions util/app-config/src/configs/indexer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ckb_types::H256;
use serde::{Deserialize, Serialize};
use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -28,6 +29,12 @@ pub struct IndexerConfig {
/// Maximal db info log files to be kept.
#[serde(default)]
pub db_keep_log_file_num: Option<NonZeroUsize>,
/// The init tip block number
#[serde(default)]
pub init_tip_number: Option<u64>,
/// The init tip block hash
#[serde(default)]
pub init_tip_hash: Option<H256>,
}

const fn default_poll_interval() -> u64 {
Expand All @@ -45,6 +52,8 @@ impl Default for IndexerConfig {
cell_filter: None,
db_background_jobs: None,
db_keep_log_file_num: None,
init_tip_number: None,
init_tip_hash: None,
}
}
}
Expand Down
32 changes: 31 additions & 1 deletion util/indexer/src/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@ impl CustomFilters {
#[cfg(test)]
mod tests {
use super::*;
use crate::store::RocksdbStore;
use crate::{store::RocksdbStore, IndexerService};
use ckb_types::{
bytes::Bytes,
core::{
Expand Down Expand Up @@ -2015,6 +2015,20 @@ mod tests {
)
}

fn new_indexer_with_init_tip(
prefix: &str,
init_tip_number: Option<BlockNumber>,
init_tip_hash: Option<H256>,
) -> Indexer<RocksdbStore> {
let tmp_dir = tempfile::Builder::new().prefix(prefix).tempdir().unwrap();
let store = RocksdbStore::new(
&RocksdbStore::default_options(),
tmp_dir.path().to_str().unwrap(),
);
IndexerService::apply_init_tip(false, init_tip_number, &init_tip_hash, &store);
Indexer::new(store, 10, 1, None, CustomFilters::new(None, None))
}

#[test]
fn with_custom_block_filter() {
let indexer = new_indexer_with_custom_filters::<RocksdbStore>(
Expand Down Expand Up @@ -2364,4 +2378,20 @@ mod tests {
.len()
);
}

#[test]
fn rollback_with_set_init_tip() {
let indexer = new_indexer_with_init_tip(
"rollback_with_set_init_tip",
Some(1000),
Some(H256::default()),
);

indexer.rollback().unwrap();

// tip should be None and store should be empty;
assert!(indexer.tip().unwrap().is_none());
let mut iter = indexer.store.iter([], IteratorDirection::Forward).unwrap();
assert!(iter.next().is_none());
}
}
45 changes: 44 additions & 1 deletion util/indexer/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::indexer::{self, extract_raw_data, CustomFilters, Indexer, Key, KeyPrefix, Value};
use crate::pool::Pool;
use crate::store::{IteratorDirection, RocksdbStore, SecondaryDB, Store};
use crate::store::{Batch, IteratorDirection, RocksdbStore, SecondaryDB, Store};

use crate::error::Error;
use ckb_app_config::{DBConfig, IndexerConfig};
Expand Down Expand Up @@ -46,8 +46,15 @@ pub struct IndexerService {
impl IndexerService {
/// Construct new Indexer service instance from DBConfig and IndexerConfig
pub fn new(ckb_db_config: &DBConfig, config: &IndexerConfig, async_handle: Handle) -> Self {
let is_store_initialized = config.store.exists();
let store_opts = Self::indexer_store_options(config);
let store = RocksdbStore::new(&store_opts, &config.store);
Self::apply_init_tip(
is_store_initialized,
config.init_tip_number,
&config.init_tip_hash,
&store,
);
let pool = if config.index_tx_pool {
Some(Arc::new(RwLock::new(Pool::default())))
} else {
Expand Down Expand Up @@ -247,6 +254,26 @@ impl IndexerService {
);
opts
}

pub(crate) fn apply_init_tip(
is_store_initialized: bool,
init_tip_number: Option<u64>,
init_tip_hash: &Option<H256>,
store: &RocksdbStore,
) {
if let (true, Some(init_tip_number), Some(init_tip_hash)) =
(!is_store_initialized, init_tip_number, init_tip_hash)
{
let mut batch = store.batch().expect("create batch should be OK");
batch
.put_kv(
Key::Header(init_tip_number, &init_tip_hash.pack(), true),
vec![],
)
.expect("insert init tip header should be OK");
batch.commit().expect("commit batch should be OK");
}
}
}

/// Handle to the indexer.
Expand Down Expand Up @@ -1554,6 +1581,22 @@ mod tests {
);
}

#[test]
fn rpc_get_indexer_tip_with_set_init_tip() {
let store = new_store("rpc_get_indexer_tip_with_set_init_tip");
IndexerService::apply_init_tip(false, Some(10000), &Some(H256::default()), &store);
let pool = Arc::new(RwLock::new(Pool::default()));
let rpc = IndexerHandle {
store,
pool: Some(Arc::clone(&pool)),
};

// test get_tip rpc
let tip = rpc.get_indexer_tip().unwrap().unwrap();
assert_eq!(H256::default(), tip.block_hash);
assert_eq!(10000, tip.block_number.value());
}

#[test]
fn script_search_mode_rpc() {
let store = new_store("script_search_mode_rpc");
Expand Down
Loading