@@ -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