@@ -64,6 +64,7 @@ use utils::{check_nlocktime, check_nsequence_rbf, After, Older, SecpCtx};
6464use crate :: blockchain:: { GetHeight , NoopProgress , Progress , WalletSync } ;
6565use crate :: database:: memory:: MemoryDatabase ;
6666use crate :: database:: { AnyDatabase , BatchDatabase , BatchOperations , DatabaseUtils , SyncTime } ;
67+ use crate :: descriptor:: checksum:: get_checksum_bytes;
6768use crate :: descriptor:: derived:: AsDerived ;
6869use crate :: descriptor:: policy:: BuildSatisfaction ;
6970use crate :: descriptor:: {
@@ -203,28 +204,28 @@ where
203204 let secp = Secp256k1 :: new ( ) ;
204205
205206 let ( descriptor, keymap) = into_wallet_descriptor_checked ( descriptor, & secp, network) ?;
206- database. check_descriptor_checksum (
207+ Self :: db_checksum (
208+ & mut database,
209+ & descriptor. to_string ( ) ,
207210 KeychainKind :: External ,
208- get_checksum ( & descriptor. to_string ( ) ) ?. as_bytes ( ) ,
209211 ) ?;
210212 let signers = Arc :: new ( SignersContainer :: build ( keymap, & descriptor, & secp) ) ;
213+
211214 let ( change_descriptor, change_signers) = match change_descriptor {
212215 Some ( desc) => {
213216 let ( change_descriptor, change_keymap) =
214217 into_wallet_descriptor_checked ( desc, & secp, network) ?;
215- database. check_descriptor_checksum (
218+ Self :: db_checksum (
219+ & mut database,
220+ & change_descriptor. to_string ( ) ,
216221 KeychainKind :: Internal ,
217- get_checksum ( & change_descriptor. to_string ( ) ) ?. as_bytes ( ) ,
218222 ) ?;
219223
220224 let change_signers = Arc :: new ( SignersContainer :: build (
221225 change_keymap,
222226 & change_descriptor,
223227 & secp,
224228 ) ) ;
225- // if !parsed.same_structure(descriptor.as_ref()) {
226- // return Err(Error::DifferentDescriptorStructure);
227- // }
228229
229230 ( Some ( change_descriptor) , change_signers)
230231 }
@@ -243,6 +244,19 @@ where
243244 } )
244245 }
245246
247+ /// This checks the checksum within [`BatchDatabase`] twice (if needed). The first time with the
248+ /// actual checksum, and the second time with the checksum of `descriptor+checksum`. The second
249+ /// check is necessary for backwards compatibility of a checksum-inception bug.
250+ fn db_checksum ( db : & mut D , desc : & str , kind : KeychainKind ) -> Result < ( ) , Error > {
251+ let checksum = get_checksum_bytes ( desc, true ) ?;
252+ if db. check_descriptor_checksum ( kind, checksum) . is_ok ( ) {
253+ return Ok ( ( ) ) ;
254+ }
255+
256+ let checksum_inception = get_checksum_bytes ( desc, false ) ?;
257+ db. check_descriptor_checksum ( kind, checksum_inception)
258+ }
259+
246260 /// Get the Bitcoin network the wallet is using.
247261 pub fn network ( & self ) -> Network {
248262 self . network
@@ -1963,6 +1977,34 @@ pub(crate) mod test {
19631977 ) ;
19641978 }
19651979
1980+ #[ test]
1981+ fn test_db_checksum ( ) {
1982+ let ( wallet, _, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
1983+ let desc = wallet. descriptor . to_string ( ) ;
1984+
1985+ let checksum = get_checksum_bytes ( & desc, true ) . unwrap ( ) ;
1986+ let checksum_inception = get_checksum_bytes ( & desc, false ) . unwrap ( ) ;
1987+ let checksum_invalid = [ b'q' ; 8 ] ;
1988+
1989+ let mut db = MemoryDatabase :: new ( ) ;
1990+ db. check_descriptor_checksum ( KeychainKind :: External , checksum)
1991+ . expect ( "failed to save actual checksum" ) ;
1992+ Wallet :: db_checksum ( & mut db, & desc, KeychainKind :: External )
1993+ . expect ( "db that uses actual checksum should be supported" ) ;
1994+
1995+ let mut db = MemoryDatabase :: new ( ) ;
1996+ db. check_descriptor_checksum ( KeychainKind :: External , checksum_inception)
1997+ . expect ( "failed to save checksum inception" ) ;
1998+ Wallet :: db_checksum ( & mut db, & desc, KeychainKind :: External )
1999+ . expect ( "db that uses checksum inception should be supported" ) ;
2000+
2001+ let mut db = MemoryDatabase :: new ( ) ;
2002+ db. check_descriptor_checksum ( KeychainKind :: External , checksum_invalid)
2003+ . expect ( "failed to save invalid checksum" ) ;
2004+ Wallet :: db_checksum ( & mut db, & desc, KeychainKind :: External )
2005+ . expect_err ( "db that uses invalid checksum should fail" ) ;
2006+ }
2007+
19662008 #[ test]
19672009 fn test_get_funded_wallet_balance ( ) {
19682010 let ( wallet, _, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
0 commit comments