@@ -64,6 +64,7 @@ use utils::{check_nlocktime, check_nsequence_rbf, After, Older, SecpCtx};
64
64
use crate :: blockchain:: { GetHeight , NoopProgress , Progress , WalletSync } ;
65
65
use crate :: database:: memory:: MemoryDatabase ;
66
66
use crate :: database:: { AnyDatabase , BatchDatabase , BatchOperations , DatabaseUtils , SyncTime } ;
67
+ use crate :: descriptor:: checksum:: get_checksum_bytes;
67
68
use crate :: descriptor:: derived:: AsDerived ;
68
69
use crate :: descriptor:: policy:: BuildSatisfaction ;
69
70
use crate :: descriptor:: {
@@ -203,28 +204,28 @@ where
203
204
let secp = Secp256k1 :: new ( ) ;
204
205
205
206
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 ( ) ,
207
210
KeychainKind :: External ,
208
- get_checksum ( & descriptor. to_string ( ) ) ?. as_bytes ( ) ,
209
211
) ?;
210
212
let signers = Arc :: new ( SignersContainer :: build ( keymap, & descriptor, & secp) ) ;
213
+
211
214
let ( change_descriptor, change_signers) = match change_descriptor {
212
215
Some ( desc) => {
213
216
let ( change_descriptor, change_keymap) =
214
217
into_wallet_descriptor_checked ( desc, & secp, network) ?;
215
- database. check_descriptor_checksum (
218
+ Self :: db_checksum (
219
+ & mut database,
220
+ & change_descriptor. to_string ( ) ,
216
221
KeychainKind :: Internal ,
217
- get_checksum ( & change_descriptor. to_string ( ) ) ?. as_bytes ( ) ,
218
222
) ?;
219
223
220
224
let change_signers = Arc :: new ( SignersContainer :: build (
221
225
change_keymap,
222
226
& change_descriptor,
223
227
& secp,
224
228
) ) ;
225
- // if !parsed.same_structure(descriptor.as_ref()) {
226
- // return Err(Error::DifferentDescriptorStructure);
227
- // }
228
229
229
230
( Some ( change_descriptor) , change_signers)
230
231
}
@@ -243,6 +244,19 @@ where
243
244
} )
244
245
}
245
246
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
+
246
260
/// Get the Bitcoin network the wallet is using.
247
261
pub fn network ( & self ) -> Network {
248
262
self . network
@@ -1949,6 +1963,34 @@ pub(crate) mod test {
1949
1963
) ;
1950
1964
}
1951
1965
1966
+ #[ test]
1967
+ fn test_db_checksum ( ) {
1968
+ let ( wallet, _, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
1969
+ let desc = wallet. descriptor . to_string ( ) ;
1970
+
1971
+ let checksum = get_checksum_bytes ( & desc, true ) . unwrap ( ) ;
1972
+ let checksum_inception = get_checksum_bytes ( & desc, false ) . unwrap ( ) ;
1973
+ let checksum_invalid = [ 'q' as u8 ; 8 ] ;
1974
+
1975
+ let mut db = MemoryDatabase :: new ( ) ;
1976
+ db. check_descriptor_checksum ( KeychainKind :: External , checksum)
1977
+ . expect ( "failed to save actual checksum" ) ;
1978
+ Wallet :: db_checksum ( & mut db, & desc, KeychainKind :: External )
1979
+ . expect ( "db that uses actual checksum should be supported" ) ;
1980
+
1981
+ let mut db = MemoryDatabase :: new ( ) ;
1982
+ db. check_descriptor_checksum ( KeychainKind :: External , checksum_inception)
1983
+ . expect ( "failed to save checksum inception" ) ;
1984
+ Wallet :: db_checksum ( & mut db, & desc, KeychainKind :: External )
1985
+ . expect ( "db that uses checksum inception should be supported" ) ;
1986
+
1987
+ let mut db = MemoryDatabase :: new ( ) ;
1988
+ db. check_descriptor_checksum ( KeychainKind :: External , checksum_invalid)
1989
+ . expect ( "failed to save invalid checksum" ) ;
1990
+ Wallet :: db_checksum ( & mut db, & desc, KeychainKind :: External )
1991
+ . expect_err ( "db that uses invalid checksum should fail" ) ;
1992
+ }
1993
+
1952
1994
#[ test]
1953
1995
fn test_get_funded_wallet_balance ( ) {
1954
1996
let ( wallet, _, _) = get_funded_wallet ( get_test_wpkh ( ) ) ;
0 commit comments