Skip to content

Commit c694612

Browse files
author
Aaron Blankstein
authored
Merge pull request #2930 from blockstack/fix/existing-state
Fix: insert epochs on migration in SortitionDB::connect
2 parents 0b10997 + e50bf43 commit c694612

File tree

1 file changed

+61
-25
lines changed

1 file changed

+61
-25
lines changed

src/chainstate/burn/db/sortdb.rs

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,7 +2044,7 @@ impl SortitionDB {
20442044
first_burn_header_hash: first_snapshot.burn_header_hash.clone(),
20452045
};
20462046

2047-
db.check_schema_version_and_update()?;
2047+
db.check_schema_version_or_error()?;
20482048
Ok(db)
20492049
}
20502050

@@ -2112,7 +2112,7 @@ impl SortitionDB {
21122112
}
21132113
}
21142114

2115-
db.check_schema_version_and_update()?;
2115+
db.check_schema_version_and_update(epochs)?;
21162116
Ok(db)
21172117
}
21182118

@@ -2274,20 +2274,7 @@ impl SortitionDB {
22742274
db_tx.execute_batch(row_text)?;
22752275
}
22762276

2277-
let epochs = SortitionDB::validate_epochs(epochs_ref);
2278-
for epoch in epochs.into_iter() {
2279-
let args: &[&dyn ToSql] = &[
2280-
&(epoch.epoch_id as u32),
2281-
&u64_to_sql(epoch.start_height)?,
2282-
&u64_to_sql(epoch.end_height)?,
2283-
&epoch.block_limit,
2284-
&epoch.network_epoch,
2285-
];
2286-
db_tx.execute(
2287-
"INSERT INTO epochs (epoch_id,start_block_height,end_block_height,block_limit,network_epoch) VALUES (?1,?2,?3,?4,?5)",
2288-
args
2289-
)?;
2290-
}
2277+
SortitionDB::validate_and_insert_epochs(&db_tx, epochs_ref)?;
22912278

22922279
db_tx.execute(
22932280
"INSERT OR REPLACE INTO db_config (version) VALUES (?1)",
@@ -2312,6 +2299,29 @@ impl SortitionDB {
23122299
Ok(())
23132300
}
23142301

2302+
/// Validates given StacksEpochs (will runtime panic if there is any invalid StacksEpoch structuring) and
2303+
/// inserts them into the SortitionDB's epochs table.
2304+
fn validate_and_insert_epochs(
2305+
db_tx: &Transaction,
2306+
epochs: &[StacksEpoch],
2307+
) -> Result<(), db_error> {
2308+
let epochs = SortitionDB::validate_epochs(epochs);
2309+
for epoch in epochs.into_iter() {
2310+
let args: &[&dyn ToSql] = &[
2311+
&(epoch.epoch_id as u32),
2312+
&u64_to_sql(epoch.start_height)?,
2313+
&u64_to_sql(epoch.end_height)?,
2314+
&epoch.block_limit,
2315+
&epoch.network_epoch,
2316+
];
2317+
db_tx.execute(
2318+
"INSERT INTO epochs (epoch_id,start_block_height,end_block_height,block_limit,network_epoch) VALUES (?1,?2,?3,?4,?5)",
2319+
args
2320+
)?;
2321+
}
2322+
Ok(())
2323+
}
2324+
23152325
#[cfg(test)]
23162326
fn instantiate_v1(
23172327
&mut self,
@@ -2384,9 +2394,8 @@ impl SortitionDB {
23842394
query_rows(self.conn(), qry, NO_PARAMS)
23852395
}
23862396

2387-
pub fn get_schema_version(&self) -> Result<Option<String>, db_error> {
2388-
let version = self
2389-
.conn()
2397+
fn get_schema_version(conn: &Connection) -> Result<Option<String>, db_error> {
2398+
let version = conn
23902399
.query_row(
23912400
"SELECT MAX(version) from db_config",
23922401
rusqlite::NO_PARAMS,
@@ -2396,11 +2405,13 @@ impl SortitionDB {
23962405
Ok(version)
23972406
}
23982407

2399-
fn apply_schema_2(tx: &SortitionDBTx) -> Result<(), db_error> {
2408+
fn apply_schema_2(tx: &SortitionDBTx, epochs: &[StacksEpoch]) -> Result<(), db_error> {
24002409
for sql_exec in SORTITION_DB_SCHEMA_2 {
24012410
tx.execute_batch(sql_exec)?;
24022411
}
24032412

2413+
SortitionDB::validate_and_insert_epochs(&tx, epochs)?;
2414+
24042415
tx.execute(
24052416
"INSERT OR REPLACE INTO db_config (version) VALUES (?1)",
24062417
&["2"],
@@ -2409,16 +2420,34 @@ impl SortitionDB {
24092420
Ok(())
24102421
}
24112422

2412-
fn check_schema_version_and_update(&mut self) -> Result<(), db_error> {
2413-
match self.get_schema_version() {
2423+
fn check_schema_version_or_error(&mut self) -> Result<(), db_error> {
2424+
match SortitionDB::get_schema_version(self.conn()) {
2425+
Ok(Some(version)) => {
2426+
let expected_version = SORTITION_DB_VERSION.to_string();
2427+
if version == expected_version {
2428+
Ok(())
2429+
} else {
2430+
Err(db_error::Other(format!(
2431+
"The version of the sortition DB {} does not match the expected {} and cannot be updated from SortitionDB::open()",
2432+
version, expected_version
2433+
)))
2434+
}
2435+
}
2436+
Ok(None) => panic!("The schema version of the sortition DB is not recorded."),
2437+
Err(e) => panic!("Error obtaining the version of the sortition DB: {:?}", e),
2438+
}
2439+
}
2440+
2441+
fn check_schema_version_and_update(&mut self, epochs: &[StacksEpoch]) -> Result<(), db_error> {
2442+
let tx = self.tx_begin()?;
2443+
match SortitionDB::get_schema_version(&tx) {
24142444
Ok(Some(version)) => {
24152445
let expected_version = SORTITION_DB_VERSION.to_string();
24162446
if version == expected_version {
24172447
return Ok(());
24182448
}
24192449
if version == "1" {
2420-
let tx = self.tx_begin()?;
2421-
SortitionDB::apply_schema_2(&tx)?;
2450+
SortitionDB::apply_schema_2(&tx, epochs)?;
24222451
tx.commit()?;
24232452
Ok(())
24242453
} else {
@@ -4276,6 +4305,8 @@ pub mod tests {
42764305
assert!(res.is_err());
42774306
assert!(format!("{:?}", res).contains("no such table: epochs"));
42784307

4308+
assert!(SortitionDB::open(&db_path_dir, true).is_err());
4309+
42794310
// create a v2 sortition DB at the same path as the v1 DB.
42804311
// the schema migration should be successfully applied, and the epochs table should exist.
42814312
let db = SortitionDB::connect(
@@ -4287,7 +4318,12 @@ pub mod tests {
42874318
true,
42884319
)
42894320
.unwrap();
4290-
assert!(SortitionDB::get_stacks_epoch(db.conn(), first_block_height).is_ok());
4321+
// assert that an epoch is returned
4322+
SortitionDB::get_stacks_epoch(db.conn(), first_block_height)
4323+
.expect("Database should not error querying epochs")
4324+
.expect("Database should have an epoch entry");
4325+
4326+
assert!(SortitionDB::open(&db_path_dir, true).is_ok());
42914327
}
42924328

42934329
#[test]

0 commit comments

Comments
 (0)