Merge bitcoindevkit/bdk#806: Ensure there are no duplicated script_pubkeys in sqlite
b5fcddcf1ab795b96481f3e46da9356e4f9c8b41 Add sqlite migration to drop duplicated script_pubkeys rows (Steve Myers) 21c96c9c811337ba04a0f85b48a7dec58ba8b416 Add test for issue #801 (Alekos Filini) c51d544932a666851c39f79a517e2e0a1e783b05 [wip] Ensure there are no duplicated script_pubkeys in sqlite (Alekos Filini) Pull request description: ### Description Add a `UNIQUE` constraint on the script_pubkeys table so that it doesn't grow constantly when caching new addresses. Fixes #801 ### Notes to the reviewers Adding it to the 0.25 milestone since it's just a bugfix. Still in draft because I need to add extra migration queries to clean up existing dbs. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### Bugfixes: * [ ] This pull request breaks the existing API * [x] I've added tests to reproduce the issue which are now passing * [x] I'm linking the issue being fixed by this PR ACKs for top commit: notmandatory: ACK b5fcddcf1ab795b96481f3e46da9356e4f9c8b41 Tree-SHA512: 7b10e453bb38af5c4f80f77692a56e37259680e50f9c2c9e554a0e5f04fb9cab897da6476c6c9930f1c501b455472984a1c92c4f137cff49acdc390d2e705107
This commit is contained in:
commit
4c5ceaff14
@ -57,7 +57,17 @@ static MIGRATIONS: &[&str] = &[
|
||||
"CREATE TABLE utxos (value INTEGER, keychain TEXT, vout INTEGER, txid BLOB, script BLOB, is_spent BOOLEAN DEFAULT 0);",
|
||||
"INSERT INTO utxos SELECT value, keychain, vout, txid, script, is_spent FROM utxos_old;",
|
||||
"DROP TABLE utxos_old;",
|
||||
"CREATE UNIQUE INDEX idx_utxos_txid_vout ON utxos(txid, vout);"
|
||||
"CREATE UNIQUE INDEX idx_utxos_txid_vout ON utxos(txid, vout);",
|
||||
// Fix issue https://github.com/bitcoindevkit/bdk/issues/801: drop duplicated script_pubkeys
|
||||
"ALTER TABLE script_pubkeys RENAME TO script_pubkeys_old;",
|
||||
"DROP INDEX idx_keychain_child;",
|
||||
"DROP INDEX idx_script;",
|
||||
"CREATE TABLE script_pubkeys (keychain TEXT, child INTEGER, script BLOB);",
|
||||
"CREATE INDEX idx_keychain_child ON script_pubkeys(keychain, child);",
|
||||
"CREATE INDEX idx_script ON script_pubkeys(script);",
|
||||
"CREATE UNIQUE INDEX idx_script_pks_unique ON script_pubkeys(keychain, child);",
|
||||
"INSERT OR REPLACE INTO script_pubkeys SELECT keychain, child, script FROM script_pubkeys_old;",
|
||||
"DROP TABLE script_pubkeys_old;"
|
||||
];
|
||||
|
||||
/// Sqlite database stored on filesystem
|
||||
@ -88,7 +98,7 @@ impl SqliteDatabase {
|
||||
child: u32,
|
||||
script: &[u8],
|
||||
) -> Result<i64, Error> {
|
||||
let mut statement = self.connection.prepare_cached("INSERT INTO script_pubkeys (keychain, child, script) VALUES (:keychain, :child, :script)")?;
|
||||
let mut statement = self.connection.prepare_cached("INSERT OR REPLACE INTO script_pubkeys (keychain, child, script) VALUES (:keychain, :child, :script)")?;
|
||||
statement.execute(named_params! {
|
||||
":keychain": keychain,
|
||||
":child": child,
|
||||
@ -1096,4 +1106,44 @@ pub mod test {
|
||||
fn test_check_descriptor_checksum() {
|
||||
crate::database::test::test_check_descriptor_checksum(get_database());
|
||||
}
|
||||
|
||||
// Issue 801: https://github.com/bitcoindevkit/bdk/issues/801
|
||||
#[test]
|
||||
fn test_unique_spks() {
|
||||
use crate::bitcoin::hashes::hex::FromHex;
|
||||
use crate::database::*;
|
||||
|
||||
let mut db = get_database();
|
||||
|
||||
let script = Script::from(
|
||||
Vec::<u8>::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(),
|
||||
);
|
||||
let path = 42;
|
||||
let keychain = KeychainKind::External;
|
||||
|
||||
for _ in 0..100 {
|
||||
db.set_script_pubkey(&script, keychain, path).unwrap();
|
||||
}
|
||||
|
||||
let mut statement = db
|
||||
.connection
|
||||
.prepare_cached(
|
||||
"select keychain,child,count(child) from script_pubkeys group by keychain,child;",
|
||||
)
|
||||
.unwrap();
|
||||
let mut rows = statement.query([]).unwrap();
|
||||
while let Some(row) = rows.next().unwrap() {
|
||||
let keychain: String = row.get(0).unwrap();
|
||||
let child: u32 = row.get(1).unwrap();
|
||||
let count: usize = row.get(2).unwrap();
|
||||
|
||||
assert!(
|
||||
count == 1,
|
||||
"keychain={}, child={}, count={}",
|
||||
keychain,
|
||||
child,
|
||||
count
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user