void ScrAddrFilter::checkForMerge()
{
   if (mergeFlag_ == true)
   {
      /***
      We're about to add a set of newly registered scrAddrs to the BDM's
      ScrAddrFilter map. Make sure they are scanned up to the last known
      top block first, then merge it in.
      ***/

      //create SAF to scan the addresses to merge
      std::shared_ptr<ScrAddrFilter> sca(copy());
      for (auto& scraddr : scrAddrDataForSideScan_.scrAddrsToMerge_)
         sca->scrAddrMap_.insert(scraddr);

      if (config().armoryDbType != ARMORY_DB_SUPER)
      {
         BinaryData lastScannedBlockHash = scrAddrDataForSideScan_.lastScannedBlkHash_;

         uint32_t topBlock = currentTopBlockHeight();
         uint32_t startBlock;

         //check last scanned blk hash against the blockchain      
         Blockchain& bc = blockchain();
         const BlockHeader& bh = bc.getHeaderByHash(lastScannedBlockHash);

         if (bh.isMainBranch())
         {
            //last scanned block is still on main branch
            startBlock = bh.getBlockHeight() + 1;
         }
         else
         {
            //last scanned block is off the main branch, undo till branch point
            const Blockchain::ReorganizationState state =
               bc.findReorgPointFromBlock(lastScannedBlockHash);
            ReorgUpdater reorg(state, &bc, lmdb_, config(), sca.get(), true);

            startBlock = state.reorgBranchPoint->getBlockHeight() + 1;
         }

         if (startBlock < topBlock)
            sca->applyBlockRangeToDB(startBlock, topBlock + 1, vector<string>());
      }

      //grab merge lock
      while (mergeLock_.fetch_or(1, memory_order_acquire));

      scrAddrMap_.insert(sca->scrAddrMap_.begin(), sca->scrAddrMap_.end());
      scrAddrDataForSideScan_.scrAddrsToMerge_.clear();

      mergeFlag_ = false;

      //release lock
      mergeLock_.store(0, memory_order_release);
   }
}
void ScrAddrFilter::scanScrAddrThread()
{
   //Only one wallet at a time         
   uint32_t endBlock = currentTopBlockHeight();
   vector<string> wltIDs = scrAddrDataForSideScan_.getWalletIDString();

   BinaryData topScannedBlockHash;
   {
      LMDBEnv::Transaction tx;
      lmdb_->beginDBTransaction(&tx, HEADERS, LMDB::ReadOnly);
      StoredHeader sbh;
      lmdb_->getBareHeader(sbh, endBlock);
      topScannedBlockHash = sbh.thisHash_;
   }

   if(doScan_ == false)
   {
      //new addresses, set their last seen block in the SSH entries
      setSSHLastScanned(currentTopBlockHeight());
   }
   else
   {
      //wipe SSH
      vector<BinaryData> saVec;
      for (const auto& scrAddrPair : scrAddrMap_)
         saVec.push_back(scrAddrPair.first);
      wipeScrAddrsSSH(saVec);
      saVec.clear();

      //scan from 0
      topScannedBlockHash =
         applyBlockRangeToDB(0, endBlock, wltIDs);
   }

   for (auto& batch : scrAddrDataForSideScan_.wltNAddrMap_)
   {
      if (batch.first->hasBdvPtr())
      {
         //merge with main ScrAddrScanData object
         merge(topScannedBlockHash);

         vector<BinaryData> addressVec;
         addressVec.reserve(scrAddrMap_.size());

         //notify the wallets that the scrAddr are ready
         for (auto& scrAddrPair : scrAddrMap_)
         {
            addressVec.push_back(scrAddrPair.first);
         }

         if (!scrAddrMap_.empty())
         {
            batch.first->prepareScrAddrForMerge(addressVec, !((bool)doScan_),
               topScannedBlockHash);

            //notify the bdv that it needs to refresh through the wallet
            batch.first->needsRefresh();
         }
      }
   }

   //clean up
   if (root_ != nullptr)
   {
      ScrAddrFilter* root = root_;
      shared_ptr<ScrAddrFilter> newChild = child_;
      root->child_ = newChild;

      root->isScanning_ = false;

      if (root->child_)
         root->flagForScanThread();
   }

   for (const auto& wID : wltIDs)
      LOGINFO << "Done with side scan of wallet " << wID;
}
void ScrAddrFilter::scanScrAddrThread()
{
   //Only one wallet at a time         
   uint32_t endBlock = currentTopBlockHeight();
   vector<string> wltIDs = scrAddrDataForSideScan_.getWalletIDString();

   BinaryData topScannedBlockHash;
   {
      //grab top scanned block from sdbi
      StoredDBInfo sdbi;
      lmdb_->getStoredDBInfo(SSH, sdbi);
      topScannedBlockHash = sdbi.topScannedBlkHash_;
   }

   if(doScan_ == false)
   {
      //new addresses, create the DB key and 
      //set the last seen block in the SSH entries
      buildSSHKeys();
      setSSHLastScanned(currentTopBlockHeight());
   }
   else
   {
      //no need for that otherwise, the addresses will be scanned, which
      //will create the DB keys and set the proper last seen block for
      //each SSH
      //instead, let's make sure the SSH we are scanning have no prior history
      //by wiping them
      vector<BinaryData> saVec;
      for (const auto& scrAddrPair : scrAddrMap_)
         saVec.push_back(scrAddrPair.first);
      wipeScrAddrsSSH(saVec);
      saVec.clear();

      //scan from height 0
      topScannedBlockHash =
         applyBlockRangeToDB(0, endBlock, wltIDs);
   }

   for (auto& batch : scrAddrDataForSideScan_.wltNAddrMap_)
   {
      if (batch.first->hasBdvPtr())
      {
         //merge with main ScrAddrScanData object
         merge(topScannedBlockHash);

         vector<BinaryData> addressVec;
         addressVec.reserve(scrAddrMap_.size());

         //notify the wallets that the scrAddr are ready
         for (auto& scrAddrPair : scrAddrMap_)
         {
            addressVec.push_back(scrAddrPair.first);
         }

         if (!scrAddrMap_.empty())
         {
            batch.first->prepareScrAddrForMerge(addressVec, !((bool)doScan_),
               topScannedBlockHash);

            //notify the bdv that it needs to refresh through the wallet
            batch.first->needsRefresh();
         }
      }
   }

   //clean up
   if (root_ != nullptr)
   {
      ScrAddrFilter* root = root_;
      shared_ptr<ScrAddrFilter> newChild = child_;
      root->child_ = newChild;

      root->isScanning_ = false;

      if (root->child_)
         root->flagForScanThread();
   }

   for (const auto& wID : wltIDs)
      LOGINFO << "Done with side scan of wallet " << wID;
}