Skip to content

Commit bfcd096

Browse files
Add configurable max-savepoints and savepoint-interval (ordinals#4191)
Co-authored-by: raph <[email protected]>
1 parent 0a0916a commit bfcd096

File tree

4 files changed

+68
-10
lines changed

4 files changed

+68
-10
lines changed

src/index/reorg.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ impl Display for Error {
1919

2020
impl std::error::Error for Error {}
2121

22-
const MAX_SAVEPOINTS: u32 = 2;
23-
const SAVEPOINT_INTERVAL: u32 = 10;
24-
const CHAIN_TIP_DISTANCE: u32 = 21;
25-
2622
pub(crate) struct Reorg {}
2723

2824
impl Reorg {
@@ -32,8 +28,10 @@ impl Reorg {
3228
match index.block_hash(height.checked_sub(1))? {
3329
Some(index_prev_blockhash) if index_prev_blockhash == bitcoind_prev_blockhash => Ok(()),
3430
Some(index_prev_blockhash) if index_prev_blockhash != bitcoind_prev_blockhash => {
31+
let savepoint_interval = u32::try_from(index.settings.savepoint_interval()).unwrap();
32+
let max_savepoints = u32::try_from(index.settings.max_savepoints()).unwrap();
3533
let max_recoverable_reorg_depth =
36-
(MAX_SAVEPOINTS - 1) * SAVEPOINT_INTERVAL + height % SAVEPOINT_INTERVAL;
34+
(max_savepoints - 1) * savepoint_interval + height % savepoint_interval;
3735

3836
for depth in 1..max_recoverable_reorg_depth {
3937
let index_block_hash = index.block_hash(height.checked_sub(depth))?;
@@ -94,9 +92,13 @@ impl Reorg {
9492
.unwrap_or(0);
9593

9694
let blocks = index.client.get_blockchain_info()?.headers;
97-
let result = (height < SAVEPOINT_INTERVAL.into()
98-
|| height.saturating_sub(last_savepoint_height) >= SAVEPOINT_INTERVAL.into())
99-
&& blocks.saturating_sub(height) <= CHAIN_TIP_DISTANCE.into();
95+
96+
let savepoint_interval = u64::try_from(index.settings.savepoint_interval()).unwrap();
97+
let max_savepoints = u64::try_from(index.settings.max_savepoints()).unwrap();
98+
99+
let result = (height < savepoint_interval
100+
|| height.saturating_sub(last_savepoint_height) >= savepoint_interval)
101+
&& blocks.saturating_sub(height) <= savepoint_interval * max_savepoints + 1;
100102

101103
log::trace!(
102104
"is_savepoint_required={}: height={}, last_savepoint_height={}, blocks={}",
@@ -119,7 +121,11 @@ impl Reorg {
119121

120122
let savepoints = wtx.list_persistent_savepoints()?.collect::<Vec<u64>>();
121123

122-
if savepoints.len() >= usize::try_from(MAX_SAVEPOINTS).unwrap() {
124+
if savepoints.len() >= index.settings.max_savepoints() {
125+
log::info!(
126+
"Cleaning up savepoints, keeping max {}",
127+
index.settings.max_savepoints()
128+
);
123129
wtx.delete_persistent_savepoint(savepoints.into_iter().min().unwrap())?;
124130
}
125131

@@ -128,7 +134,8 @@ impl Reorg {
128134

129135
let wtx = index.begin_write()?;
130136

131-
log::info!("creating savepoint at height {}", height);
137+
log::info!("Creating savepoint at height {}", height);
138+
132139
wtx.persistent_savepoint()?;
133140

134141
wtx

src/options.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ pub struct Options {
3030
help = "Commit to index every <COMMIT_INTERVAL> blocks. [default: 5000]"
3131
)]
3232
pub(crate) commit_interval: Option<usize>,
33+
#[arg(
34+
long,
35+
help = "Create a savepoint every <SAVEPOINT_INTERVAL> blocks. [default: 10]"
36+
)]
37+
pub(crate) savepoint_interval: Option<usize>,
38+
#[arg(long, help = "Store maximum <MAX_SAVEPOINTS> blocks. [default: 2]")]
39+
pub(crate) max_savepoints: Option<usize>,
3340
#[arg(long, help = "Load configuration from <CONFIG>.")]
3441
pub(crate) config: Option<PathBuf>,
3542
#[arg(long, help = "Load configuration from <CONFIG_DIR>.")]

src/settings.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub struct Settings {
1010
bitcoin_rpc_username: Option<String>,
1111
chain: Option<Chain>,
1212
commit_interval: Option<usize>,
13+
savepoint_interval: Option<usize>,
14+
max_savepoints: Option<usize>,
1315
config: Option<PathBuf>,
1416
config_dir: Option<PathBuf>,
1517
cookie_file: Option<PathBuf>,
@@ -115,6 +117,8 @@ impl Settings {
115117
bitcoin_rpc_username: self.bitcoin_rpc_username.or(source.bitcoin_rpc_username),
116118
chain: self.chain.or(source.chain),
117119
commit_interval: self.commit_interval.or(source.commit_interval),
120+
savepoint_interval: self.savepoint_interval.or(source.savepoint_interval),
121+
max_savepoints: self.max_savepoints.or(source.max_savepoints),
118122
config: self.config.or(source.config),
119123
config_dir: self.config_dir.or(source.config_dir),
120124
cookie_file: self.cookie_file.or(source.cookie_file),
@@ -159,6 +163,8 @@ impl Settings {
159163
.or(options.testnet4.then_some(Chain::Testnet4))
160164
.or(options.chain_argument),
161165
commit_interval: options.commit_interval,
166+
savepoint_interval: options.savepoint_interval,
167+
max_savepoints: options.max_savepoints,
162168
config: options.config,
163169
config_dir: options.config_dir,
164170
cookie_file: options.cookie_file,
@@ -247,6 +253,8 @@ impl Settings {
247253
bitcoin_rpc_username: get_string("BITCOIN_RPC_USERNAME"),
248254
chain: get_chain("CHAIN")?,
249255
commit_interval: get_usize("COMMIT_INTERVAL")?,
256+
savepoint_interval: get_usize("SAVEPOINT_INTERVAL")?,
257+
max_savepoints: get_usize("MAX_SAVEPOINTS")?,
250258
config: get_path("CONFIG"),
251259
config_dir: get_path("CONFIG_DIR"),
252260
cookie_file: get_path("COOKIE_FILE"),
@@ -277,6 +285,8 @@ impl Settings {
277285
bitcoin_rpc_limit: None,
278286
chain: Some(Chain::Regtest),
279287
commit_interval: None,
288+
savepoint_interval: None,
289+
max_savepoints: None,
280290
config: None,
281291
config_dir: None,
282292
cookie_file: None,
@@ -344,6 +354,8 @@ impl Settings {
344354
bitcoin_rpc_username: self.bitcoin_rpc_username,
345355
chain: Some(chain),
346356
commit_interval: Some(self.commit_interval.unwrap_or(5000)),
357+
savepoint_interval: Some(self.savepoint_interval.unwrap_or(10)),
358+
max_savepoints: Some(self.max_savepoints.unwrap_or(2)),
347359
config: None,
348360
config_dir: None,
349361
cookie_file: Some(cookie_file),
@@ -470,6 +482,14 @@ impl Settings {
470482
self.commit_interval.unwrap()
471483
}
472484

485+
pub fn savepoint_interval(&self) -> usize {
486+
self.savepoint_interval.unwrap()
487+
}
488+
489+
pub fn max_savepoints(&self) -> usize {
490+
self.max_savepoints.unwrap()
491+
}
492+
473493
pub fn cookie_file(&self) -> Result<PathBuf> {
474494
if let Some(cookie_file) = &self.cookie_file {
475495
return Ok(cookie_file.clone());
@@ -933,6 +953,20 @@ mod tests {
933953
assert_eq!(arguments.options.commit_interval, Some(500));
934954
}
935955

956+
#[test]
957+
fn setting_savepoint_interval() {
958+
let arguments =
959+
Arguments::try_parse_from(["ord", "--savepoint-interval", "500", "index", "update"]).unwrap();
960+
assert_eq!(arguments.options.savepoint_interval, Some(500));
961+
}
962+
963+
#[test]
964+
fn setting_max_savepoints() {
965+
let arguments =
966+
Arguments::try_parse_from(["ord", "--max-savepoints", "10", "index", "update"]).unwrap();
967+
assert_eq!(arguments.options.max_savepoints, Some(10));
968+
}
969+
936970
#[test]
937971
fn index_runes() {
938972
assert!(parse(&["--chain=signet", "--index-runes"]).index_runes_raw());
@@ -1032,6 +1066,8 @@ mod tests {
10321066
("BITCOIN_RPC_USERNAME", "bitcoin username"),
10331067
("CHAIN", "signet"),
10341068
("COMMIT_INTERVAL", "1"),
1069+
("SAVEPOINT_INTERVAL", "10"),
1070+
("MAX_SAVEPOINTS", "2"),
10351071
("CONFIG", "config"),
10361072
("CONFIG_DIR", "config dir"),
10371073
("COOKIE_FILE", "cookie file"),
@@ -1065,6 +1101,8 @@ mod tests {
10651101
bitcoin_rpc_username: Some("bitcoin username".into()),
10661102
chain: Some(Chain::Signet),
10671103
commit_interval: Some(1),
1104+
savepoint_interval: Some(10),
1105+
max_savepoints: Some(2),
10681106
config: Some("config".into()),
10691107
config_dir: Some("config dir".into()),
10701108
cookie_file: Some("cookie file".into()),
@@ -1111,6 +1149,8 @@ mod tests {
11111149
"--bitcoin-rpc-username=bitcoin username",
11121150
"--chain=signet",
11131151
"--commit-interval=1",
1152+
"--savepoint-interval=10",
1153+
"--max-savepoints=2",
11141154
"--config=config",
11151155
"--config-dir=config dir",
11161156
"--cookie-file=cookie file",
@@ -1137,6 +1177,8 @@ mod tests {
11371177
bitcoin_rpc_username: Some("bitcoin username".into()),
11381178
chain: Some(Chain::Signet),
11391179
commit_interval: Some(1),
1180+
savepoint_interval: Some(10),
1181+
max_savepoints: Some(2),
11401182
config: Some("config".into()),
11411183
config_dir: Some("config dir".into()),
11421184
cookie_file: Some("cookie file".into()),

tests/settings.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ fn default() {
1313
"bitcoin_rpc_username": null,
1414
"chain": "mainnet",
1515
"commit_interval": 5000,
16+
"savepoint_interval": 10,
17+
"max_savepoints": 2,
1618
"config": null,
1719
"config_dir": null,
1820
"cookie_file": ".*\.cookie",

0 commit comments

Comments
 (0)