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);", |     "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;", |     "INSERT INTO utxos SELECT value, keychain, vout, txid, script, is_spent FROM utxos_old;", | ||||||
|     "DROP TABLE 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
 | /// Sqlite database stored on filesystem
 | ||||||
| @ -88,7 +98,7 @@ impl SqliteDatabase { | |||||||
|         child: u32, |         child: u32, | ||||||
|         script: &[u8], |         script: &[u8], | ||||||
|     ) -> Result<i64, Error> { |     ) -> 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! { |         statement.execute(named_params! { | ||||||
|             ":keychain": keychain, |             ":keychain": keychain, | ||||||
|             ":child": child, |             ":child": child, | ||||||
| @ -1096,4 +1106,44 @@ pub mod test { | |||||||
|     fn test_check_descriptor_checksum() { |     fn test_check_descriptor_checksum() { | ||||||
|         crate::database::test::test_check_descriptor_checksum(get_database()); |         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