mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-21 18:32:04 +08:00
fix: migrate SPV schema to include the block hash alongside the block headers
This commit is contained in:
@@ -70,7 +70,7 @@ pub const BITCOIN_GENESIS_BLOCK_HASH_REGTEST: &'static str =
|
||||
pub const BLOCK_DIFFICULTY_CHUNK_SIZE: u64 = 2016;
|
||||
const BLOCK_DIFFICULTY_INTERVAL: u32 = 14 * 24 * 60 * 60; // two weeks, in seconds
|
||||
|
||||
pub const SPV_DB_VERSION: &'static str = "2";
|
||||
pub const SPV_DB_VERSION: &'static str = "3";
|
||||
|
||||
const SPV_INITIAL_SCHEMA: &[&'static str] = &[
|
||||
r#"
|
||||
@@ -98,6 +98,31 @@ const SPV_SCHEMA_2: &[&'static str] = &[r#"
|
||||
);
|
||||
"#];
|
||||
|
||||
// force the node to go and store the burnchain block header hash as well
|
||||
const SPV_SCHEMA_3: &[&'static str] = &[
|
||||
r#"
|
||||
DROP TABLE headers;
|
||||
"#,
|
||||
r#"
|
||||
DELETE FROM chain_work;
|
||||
"#,
|
||||
r#"
|
||||
CREATE TABLE headers(
|
||||
version INTEGER NOT NULL,
|
||||
prev_blockhash TEXT NOT NULL,
|
||||
merkle_root TEXT NOT NULL,
|
||||
time INTEGER NOT NULL,
|
||||
bits INTEGER NOT NULL,
|
||||
nonce INTEGER NOT NULL,
|
||||
height INTEGER PRIMARY KEY NOT NULL, -- not part of BlockHeader, but used by us internally
|
||||
hash TEXT NOT NULL -- not part of BlockHeader, but derived from the data that is
|
||||
);
|
||||
"#,
|
||||
r#"
|
||||
CREATE INDEX index_headers_by_hash ON headers(hash);
|
||||
"#,
|
||||
];
|
||||
|
||||
pub struct SpvClient {
|
||||
pub headers_path: String,
|
||||
pub start_block_height: u64,
|
||||
@@ -159,7 +184,8 @@ impl SpvClient {
|
||||
check_txcount: true,
|
||||
};
|
||||
|
||||
if readwrite && !exists {
|
||||
let empty = client.is_empty()?;
|
||||
if readwrite && (!exists || empty) {
|
||||
client.init_block_headers(true)?;
|
||||
}
|
||||
|
||||
@@ -228,6 +254,9 @@ impl SpvClient {
|
||||
for row_text in SPV_SCHEMA_2 {
|
||||
tx.execute_batch(row_text).map_err(db_error::SqliteError)?;
|
||||
}
|
||||
for row_text in SPV_SCHEMA_3 {
|
||||
tx.execute_batch(row_text).map_err(db_error::SqliteError)?;
|
||||
}
|
||||
|
||||
tx.execute(
|
||||
"INSERT INTO db_config (version) VALUES (?1)",
|
||||
@@ -278,6 +307,16 @@ impl SpvClient {
|
||||
SpvClient::db_set_version(&tx, "2")?;
|
||||
tx.commit().map_err(db_error::SqliteError)?;
|
||||
}
|
||||
"2" => {
|
||||
debug!("Migrate SPV DB from schema 2 to 3");
|
||||
let tx = tx_begin_immediate(conn)?;
|
||||
for row_text in SPV_SCHEMA_3 {
|
||||
tx.execute_batch(row_text).map_err(db_error::SqliteError)?;
|
||||
}
|
||||
|
||||
SpvClient::db_set_version(&tx, "2")?;
|
||||
tx.commit().map_err(db_error::SqliteError)?;
|
||||
}
|
||||
SPV_DB_VERSION => {
|
||||
break;
|
||||
}
|
||||
@@ -629,6 +668,18 @@ impl SpvClient {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the DB devoid of headers? Used during migrations
|
||||
pub fn is_empty(&self) -> Result<bool, btc_error> {
|
||||
match query_row::<BlockHeader, _>(
|
||||
&self.headers_db,
|
||||
"SELECT * FROM headers LIMIT 1",
|
||||
NO_PARAMS,
|
||||
)? {
|
||||
Some(_) => Ok(true),
|
||||
None => Ok(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the block header at a particular height
|
||||
/// Returns None if the requested block height is beyond the end of the headers file
|
||||
pub fn read_block_header(
|
||||
@@ -646,6 +697,19 @@ impl SpvClient {
|
||||
}))
|
||||
}
|
||||
|
||||
/// Find a block header height with a given burnchain header hash, if it is present
|
||||
pub fn find_block_header_height(
|
||||
&self,
|
||||
burn_header_hash: &BurnchainHeaderHash,
|
||||
) -> Result<Option<u64>, btc_error> {
|
||||
query_row(
|
||||
&self.headers_db,
|
||||
"SELECT height FROM headers WHERE hash = ?1",
|
||||
&[burn_header_hash],
|
||||
)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Get a range of block headers from a file.
|
||||
/// If the range falls of the end of the headers file, then the returned array will be
|
||||
/// truncated to not include them (note that this method can return an empty list of the
|
||||
@@ -700,8 +764,8 @@ impl SpvClient {
|
||||
height: u64,
|
||||
) -> Result<(), btc_error> {
|
||||
let sql = "INSERT OR REPLACE INTO headers
|
||||
(version, prev_blockhash, merkle_root, time, bits, nonce, height)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)";
|
||||
(version, prev_blockhash, merkle_root, time, bits, nonce, height, hash)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)";
|
||||
let args: &[&dyn ToSql] = &[
|
||||
&header.version,
|
||||
&header.prev_blockhash,
|
||||
@@ -710,6 +774,7 @@ impl SpvClient {
|
||||
&header.bits,
|
||||
&header.nonce,
|
||||
&u64_to_sql(height)?,
|
||||
&BurnchainHeaderHash::from_bitcoin_hash(&header.bitcoin_hash()),
|
||||
];
|
||||
|
||||
tx.execute(sql, args)
|
||||
|
||||
Reference in New Issue
Block a user