The `Broadcast`/`ResendWalletTransactions` interface is strange:

- it's the node saying to the wallet "Try to submit your unconfirmed transactions to the mempool again"
- it's called in one place by the node, in `SendMessages()` here: https://github.com/bitcoin/bitcoin/blob/c033c4b5cef89a654e4d9d5c5f9bd823871b068b/src/net_processing.cpp#L3515. `SendMessages()` is called on the message handling thread on a loop.
- the actual scheduling of when the wallet sends messages is handled in the `ResendWalletTransactions()` function itself, using the `nNextResend` and `nLastResend` wallet globals (which could as easily be static variables in `ResendWalletTransactions()`).

Therefore the only use of `Broadcast()` is to periodically prod the wallet. The wallet itself decides whether it's time to resend transactions. This could be done by scheduling regular calls to `ResendWalletTransactions()`, in the same way that we schedule regular wallet flushes here: https://github.com/bitcoin/bitcoin/blob/c033c4b5cef89a654e4d9d5c5f9bd823871b068b/src/wallet/init.cpp#L215.

A couple of minor implementation details:

- the call to `Broadcast()` in `SendMessages()` is protected by an if statement `if (!fReindex && !fImporting && !IsInitialBlockDownload()) {`. Those tests could be moved into `ResendWalletTransactions()` (through the `Chain` interface).
- The `Broadcast` notification passes in the `nTimeBestReceived` time of the best block. That could be fetched by `ResendWalletTransactions()` through the `Chain` interface.
if (rescan_height != block_height) {
                chain.initError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
                return nullptr;
            }
        }
        chain.initMessage(_("Rescanning..."));
        walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
        
        
        if (walletInstance->nTimeFirstKey) {
            if (Optional<int> first_block = locked_chain->findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height)) {
                rescan_height = *first_block;
            }
        }
        nStart = GetTimeMillis();
        {
            WalletRescanReserver reserver(walletInstance.get());
            if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(locked_chain->getBlockHash(rescan_height), {} , reserver, true ).status)) {
                chain.initError(_("Failed to rescan the wallet during initialization"));
                return nullptr;
            }
        }
        walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
        walletInstance->ChainStateFlushed(locked_chain->getTipLocator());
        walletInstance->database->IncrementUpdateCounter();
        
        if (gArgs.GetBoolArg("-zapwallettxes", false) && gArgs.GetArg("-zapwallettxes", "1") != "2")
        {
            WalletBatch batch(*walletInstance->database);
            for (const CWalletTx& wtxOld : vWtx)