Skip to content

Commit ad19ec2

Browse files
authored
Merge branch 'develop' into ci/separate-signer-release
2 parents bef210f + 202b45c commit ad19ec2

File tree

16 files changed

+2259
-1557
lines changed

16 files changed

+2259
-1557
lines changed

stacks-signer/src/signerdb.rs

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@ use std::time::SystemTime;
1919

2020
use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockVote};
2121
use blockstack_lib::util_lib::db::{
22-
query_row, sqlite_open, table_exists, u64_to_sql, Error as DBError,
22+
query_row, sqlite_open, table_exists, tx_begin_immediate, u64_to_sql, Error as DBError,
2323
};
2424
use clarity::types::chainstate::BurnchainHeaderHash;
2525
use clarity::util::get_epoch_time_secs;
2626
use libsigner::BlockProposal;
27-
use rusqlite::{params, Connection, Error as SqliteError, OpenFlags};
27+
use rusqlite::{
28+
params, Connection, Error as SqliteError, OpenFlags, OptionalExtension, Transaction,
29+
};
2830
use serde::{Deserialize, Serialize};
2931
use slog::{slog_debug, slog_error};
3032
use stacks_common::types::chainstate::ConsensusHash;
31-
use stacks_common::types::sqlite::NO_PARAMS;
3233
use stacks_common::util::hash::Sha512Trunc256Sum;
3334
use stacks_common::{debug, error};
3435
use wsts::net::NonceRequest;
@@ -107,7 +108,7 @@ pub struct SignerDb {
107108
db: Connection,
108109
}
109110

110-
const CREATE_BLOCKS_TABLE: &str = "
111+
static CREATE_BLOCKS_TABLE: &str = "
111112
CREATE TABLE IF NOT EXISTS blocks (
112113
reward_cycle INTEGER NOT NULL,
113114
signer_signature_hash TEXT NOT NULL,
@@ -119,55 +120,111 @@ CREATE TABLE IF NOT EXISTS blocks (
119120
PRIMARY KEY (reward_cycle, signer_signature_hash)
120121
) STRICT";
121122

122-
const CREATE_INDEXES: &str = "
123+
static CREATE_INDEXES: &str = "
123124
CREATE INDEX IF NOT EXISTS blocks_signed_over ON blocks (signed_over);
124125
CREATE INDEX IF NOT EXISTS blocks_consensus_hash ON blocks (consensus_hash);
125126
CREATE INDEX IF NOT EXISTS blocks_valid ON blocks ((json_extract(block_info, '$.valid')));
126127
CREATE INDEX IF NOT EXISTS burn_blocks_height ON burn_blocks (block_height);
127128
";
128129

129-
const CREATE_SIGNER_STATE_TABLE: &str = "
130+
static CREATE_SIGNER_STATE_TABLE: &str = "
130131
CREATE TABLE IF NOT EXISTS signer_states (
131132
reward_cycle INTEGER PRIMARY KEY,
132133
encrypted_state BLOB NOT NULL
133134
) STRICT";
134135

135-
const CREATE_BURN_STATE_TABLE: &str = "
136+
static CREATE_BURN_STATE_TABLE: &str = "
136137
CREATE TABLE IF NOT EXISTS burn_blocks (
137138
block_hash TEXT PRIMARY KEY,
138139
block_height INTEGER NOT NULL,
139140
received_time INTEGER NOT NULL
140141
) STRICT";
141142

143+
static CREATE_DB_CONFIG: &str = "
144+
CREATE TABLE db_config(
145+
version INTEGER NOT NULL
146+
) STRICT
147+
";
148+
149+
static DROP_SCHEMA_0: &str = "
150+
DROP TABLE IF EXISTS burn_blocks;
151+
DROP TABLE IF EXISTS signer_states;
152+
DROP TABLE IF EXISTS blocks;
153+
DROP TABLE IF EXISTS db_config;";
154+
155+
static SCHEMA_1: &[&str] = &[
156+
DROP_SCHEMA_0,
157+
CREATE_DB_CONFIG,
158+
CREATE_BURN_STATE_TABLE,
159+
CREATE_BLOCKS_TABLE,
160+
CREATE_SIGNER_STATE_TABLE,
161+
CREATE_INDEXES,
162+
"INSERT INTO db_config (version) VALUES (1);",
163+
];
164+
142165
impl SignerDb {
166+
/// The current schema version used in this build of the signer binary.
167+
pub const SCHEMA_VERSION: u32 = 1;
168+
143169
/// Create a new `SignerState` instance.
144170
/// This will create a new SQLite database at the given path
145171
/// or an in-memory database if the path is ":memory:"
146172
pub fn new(db_path: impl AsRef<Path>) -> Result<Self, DBError> {
147173
let connection = Self::connect(db_path)?;
148174

149-
let signer_db = Self { db: connection };
150-
151-
signer_db.instantiate_db()?;
175+
let mut signer_db = Self { db: connection };
176+
signer_db.create_or_migrate()?;
152177

153178
Ok(signer_db)
154179
}
155180

156-
fn instantiate_db(&self) -> Result<(), DBError> {
157-
if !table_exists(&self.db, "blocks")? {
158-
self.db.execute(CREATE_BLOCKS_TABLE, NO_PARAMS)?;
181+
/// Returns the schema version of the database
182+
fn get_schema_version(conn: &Connection) -> Result<u32, DBError> {
183+
if !table_exists(conn, "db_config")? {
184+
return Ok(0);
159185
}
186+
let result = conn
187+
.query_row("SELECT version FROM db_config LIMIT 1", [], |row| {
188+
row.get(0)
189+
})
190+
.optional();
191+
match result {
192+
Ok(x) => Ok(x.unwrap_or_else(|| 0)),
193+
Err(e) => Err(DBError::from(e)),
194+
}
195+
}
160196

161-
if !table_exists(&self.db, "signer_states")? {
162-
self.db.execute(CREATE_SIGNER_STATE_TABLE, NO_PARAMS)?;
197+
/// Migrate from schema 0 to schema 1
198+
fn schema_1_migration(tx: &Transaction) -> Result<(), DBError> {
199+
if Self::get_schema_version(tx)? >= 1 {
200+
// no migration necessary
201+
return Ok(());
163202
}
164203

165-
if !table_exists(&self.db, "burn_blocks")? {
166-
self.db.execute(CREATE_BURN_STATE_TABLE, NO_PARAMS)?;
204+
for statement in SCHEMA_1.iter() {
205+
tx.execute_batch(statement)?;
167206
}
168207

169-
self.db.execute_batch(CREATE_INDEXES)?;
208+
Ok(())
209+
}
170210

211+
/// Either instantiate a new database, or migrate an existing one
212+
/// If the detected version of the existing database is 0 (i.e., a pre-migration
213+
/// logic DB, the DB will be dropped).
214+
fn create_or_migrate(&mut self) -> Result<(), DBError> {
215+
let sql_tx = tx_begin_immediate(&mut self.db)?;
216+
loop {
217+
let version = Self::get_schema_version(&sql_tx)?;
218+
match version {
219+
0 => Self::schema_1_migration(&sql_tx)?,
220+
1 => break,
221+
x => return Err(DBError::Other(format!(
222+
"Database schema is newer than supported by this binary. Expected version = {}, Database version = {x}",
223+
Self::SCHEMA_VERSION,
224+
))),
225+
}
226+
}
227+
sql_tx.commit()?;
171228
Ok(())
172229
}
173230

@@ -597,7 +654,7 @@ mod tests {
597654
let db_path = tmp_db_path();
598655
let db = SignerDb::new(db_path).expect("Failed to create signer db");
599656
assert_eq!(
600-
query_row(&db.db, "SELECT sqlite_version()", NO_PARAMS).unwrap(),
657+
query_row(&db.db, "SELECT sqlite_version()", []).unwrap(),
601658
Some("3.45.0".to_string())
602659
);
603660
}

stackslib/src/chainstate/nakamoto/coordinator/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ impl<
758758
match self.handle_new_nakamoto_burnchain_block() {
759759
Ok(can_proceed) => {
760760
if !can_proceed {
761-
error!("Missing canonical anchor block",);
761+
error!("Missing canonical anchor block");
762762
}
763763
}
764764
Err(e) => {

stackslib/src/chainstate/stacks/miner.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ pub fn signal_mining_blocked(miner_status: Arc<Mutex<MinerStatus>>) {
133133

134134
/// resume mining if we blocked it earlier
135135
pub fn signal_mining_ready(miner_status: Arc<Mutex<MinerStatus>>) {
136+
debug!("Signaling miner to resume"; "thread_id" => ?std::thread::current().id());
136137
match miner_status.lock() {
137138
Ok(mut status) => {
138139
status.remove_blocked();
@@ -1203,7 +1204,6 @@ impl<'a> StacksMicroblockBuilder<'a> {
12031204
intermediate_result = mem_pool.iterate_candidates(
12041205
&mut clarity_tx,
12051206
&mut tx_events,
1206-
self.anchor_block_height,
12071207
mempool_settings.clone(),
12081208
|clarity_tx, to_consider, estimator| {
12091209
let mempool_tx = &to_consider.tx;
@@ -2210,7 +2210,6 @@ impl StacksBlockBuilder {
22102210
intermediate_result = mempool.iterate_candidates(
22112211
epoch_tx,
22122212
&mut tx_events,
2213-
tip_height,
22142213
mempool_settings.clone(),
22152214
|epoch_tx, to_consider, estimator| {
22162215
// first, have we been preempted?

stackslib/src/chainstate/stacks/tests/block_construction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,7 +3060,7 @@ fn test_build_microblock_stream_forks_with_descendants() {
30603060

30613061
// erase any pending transactions -- this is a "worse" poison-microblock,
30623062
// and we want to avoid mining the "better" one
3063-
mempool.clear_before_height(10).unwrap();
3063+
mempool.clear_before_coinbase_height(10).unwrap();
30643064

30653065
let mut tx_bytes = vec![];
30663066
poison_microblock_tx
@@ -4784,6 +4784,7 @@ fn paramaterized_mempool_walk_test(
47844784
&mut chainstate,
47854785
&b_1.0,
47864786
&b_1.1,
4787+
true,
47874788
txid,
47884789
tx_bytes,
47894790
tx_fee,
@@ -4832,7 +4833,6 @@ fn paramaterized_mempool_walk_test(
48324833
.iterate_candidates::<_, ChainstateError, _>(
48334834
clarity_conn,
48344835
&mut tx_events,
4835-
2,
48364836
mempool_settings.clone(),
48374837
|_, available_tx, _| {
48384838
count_txs += 1;

0 commit comments

Comments
 (0)