ImportDescriptors rpc has a race condition where two imports running in parallel can both succeed or fail one of them.
The race happens when there are two threads A and B trying to importdescriptors at the same time.
Thread A calls
BlockUntilSyncedToCurrentChain()(holdingcs_walletfast, no contention) and thenreserve(), acquiring theWalletRescanReserver. It proceeds toProcessDescriptorImport(), which holdscs_walletfor an extended time (specially on slow machines) while importing descriptors.B reaches
BlockUntilSyncedToCurrentChain(), which internally doesWITH_LOCK(cs_wallet, ...). Since A holdscs_wallet, B blocks here for the entire duration of Thread A's descriptors import.Then A finishes importing, releases
cs_wallet, rescans (fast in regtest), and setsfScanningWallet = false.B can now continue in
BlockUntilSyncedToCurrentChain()acquiringcs_wallet, and then callsreserve()which succeeds becausefScanningWalletis alreadyfalse. Both imports succeed.
I don't think the behavior is problematic at all from a usability PoV, but it can be a bad UX if some imports fails and other's no. It also makes testing difficult as race conditions are not easy to test.
This PR fixes it by calling reserver.reserve() before cs_wallet is locked, so multiple threads will be aware of currently imports before being stuck at any point. So only one importdescriptor call can be done at the same time.
I think this should fix #35544 (comment)