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); } }
uint32_t BlockDataViewer::getClosestBlockHeightForTime(uint32_t timestamp) { //get timestamp of genesis block auto& genBlock = blockchain().getGenesisBlock(); //sanity check if (timestamp < genBlock.getTimestamp()) return 0; //get time diff and divide by average time per block (600 sec for Bitcoin) uint32_t diff = timestamp - genBlock.getTimestamp(); int32_t blockHint = diff/600; //look for a block in the hint vicinity with a timestamp lower than ours while (blockHint > 0) { auto& block = blockchain().getHeaderByHeight(blockHint); if (block.getTimestamp() < timestamp) break; blockHint -= 1000; } //another sanity check if (blockHint < 0) return 0; for (uint32_t id = blockHint; id < blockchain().top().getBlockHeight() - 1; id++) { //not looking for a really precise block, //anything within the an hour of the timestamp is enough auto& block = blockchain().getHeaderByHeight(id); if (block.getTimestamp() + 3600 > timestamp) return block.getBlockHeight(); } return blockchain().top().getBlockHeight() - 1; }
uint32_t BlockDataViewer::getBlockTimeByHeight(uint32_t height) const { auto bh = blockchain().getHeaderByHeight(height); return bh.getTimestamp(); }
void BlockDataViewer::scanWallets(shared_ptr<BDV_Notification> action) { uint32_t startBlock = UINT32_MAX; uint32_t endBlock = UINT32_MAX; bool reorg = false; bool refresh = false; BDV_Notification_ZC::zcMapType zcMap; ScanWalletStruct scanData; map<BinaryData, LedgerEntry>* leMapPtr = nullptr; switch (action->action_type()) { case BDV_Init: { startBlock = 0; endBlock = blockchain().top().getBlockHeight(); refresh = true; break; } case BDV_NewBlock: { auto reorgNotif = dynamic_pointer_cast<BDV_Notification_NewBlock>(action); auto& reorgState = reorgNotif->reorgState_; if (!reorgState.hasNewTop) return; if (!reorgState.prevTopStillValid) { //reorg reorg = true; startBlock = reorgState.reorgBranchPoint->getBlockHeight(); } else { startBlock = reorgState.prevTop->getBlockHeight(); } endBlock = reorgState.newTop->getBlockHeight(); //feed current valid zc map to scanwallet as well auto&& actionStruct = createZcStruct(); zcMap = move(actionStruct->scrAddrZcMap_); break; } case BDV_ZC: { auto zcAction = dynamic_pointer_cast<BDV_Notification_ZC>(action); zcMap = move(zcAction->scrAddrZcMap_); leMapPtr = &zcAction->leMap_; startBlock = endBlock = blockchain().top().getBlockHeight(); break; } case BDV_Refresh: { refresh = true; break; } default: return; } scanData.endBlock_ = endBlock; scanData.action_ = action->action_type(); scanData.saStruct_.zcMap_ = move(zcMap); scanData.reorg_ = reorg; //get set of valid zc keys auto validkeymap = zeroConfCont_->getKeyToSpentScrAddrMap(); //get current set of zc keys for wallet for (auto& group : groups_) { auto& groupZcSet = group.getValidZcSet(); //intersect with validkeymap for (auto& zcKey : groupZcSet) { auto keyIter = validkeymap->find(zcKey); if (keyIter != validkeymap->end()) continue; scanData.saStruct_.invalidatedZCKeys_.insert(zcKey); } } vector<uint32_t> startBlocks; for (auto& group : groups_) startBlocks.push_back(startBlock); auto sbIter = startBlocks.begin(); for (auto& group : groups_) { if (group.pageHistory(refresh, false)) { *sbIter = group.hist_.getPageBottom(0); } sbIter++; } //increment update id ++updateID_; sbIter = startBlocks.begin(); for (auto& group : groups_) { scanData.startBlock_ = *sbIter; group.scanWallets(scanData, updateID_); if (leMapPtr != nullptr) leMapPtr->insert(scanData.saStruct_.zcLedgers_.begin(), scanData.saStruct_.zcLedgers_.end()); sbIter++; } lastScanned_ = endBlock; }