void LayerIterator::next() { assert( !end ); if (start) { seekToFirst(); return; } if (iterator.isValid()) { iterator.next(); if (!iterator.isValid()) { end = true; } } else { end = true; } }
void BlockchainScanner::preloadUtxos() { LMDBEnv::Transaction tx; db_->beginDBTransaction(&tx, STXO, LMDB::ReadOnly); auto dbIter = db_->getIterator(STXO); dbIter.seekToFirst(); while (dbIter.advanceAndRead()) { StoredTxOut stxo; stxo.unserializeDBKey(dbIter.getKeyRef()); stxo.unserializeDBValue(dbIter.getValueRef()); if (stxo.spentness_ == TXOUT_SPENT) continue; stxo.parentHash_ = move(db_->getTxHashForLdbKey( stxo.getDBKeyOfParentTx(false))); auto& idMap = utxoMap_[stxo.parentHash_]; idMap.insert(make_pair(stxo.txOutIndex_, move(stxo))); } }
LayerIterator::LayerIterator(Layer* layout) : iterator(layout) { seekToFirst(); }
void BlockchainScanner::updateSSH() { //loop over all subssh entiers in SUBSSH db, //compile balance, txio count and summary map for each address { StoredDBInfo sdbi; db_->getStoredDBInfo(SSH, sdbi); BlockHeader* sdbiblock = nullptr; try { sdbiblock = &blockchain_->getHeaderByHash(sdbi.topScannedBlkHash_); } catch (...) { sdbiblock = &blockchain_->getHeaderByHeight(0); } if (sdbiblock->isMainBranch()) { if (sdbi.topBlkHgt_ != 0 && sdbi.topBlkHgt_ >= blockchain_->top().getBlockHeight()) { LOGINFO << "no SSH to scan"; return; } } } map<BinaryData, StoredScriptHistory> sshMap_; { StoredScriptHistory* sshPtr = nullptr; LMDBEnv::Transaction historyTx, sshTx; db_->beginDBTransaction(&historyTx, SSH, LMDB::ReadOnly); db_->beginDBTransaction(&sshTx, SUBSSH, LMDB::ReadOnly); auto sshIter = db_->getIterator(SUBSSH); sshIter.seekToFirst(); while (sshIter.advanceAndRead()) { while (sshIter.isValid()) { if (sshPtr != nullptr && sshIter.getKeyRef().contains(sshPtr->uniqueKey_)) break; //new address auto&& subsshkey = sshIter.getKey(); auto sshKey = subsshkey.getSliceRef(1, subsshkey.getSize() - 5); sshPtr = &sshMap_[sshKey]; if (!scrAddrFilter_->hasScrAddress(sshKey)) { LOGWARN << "invalid scrAddr in SUBSSH db"; continue; } //get what's already in the db db_->getStoredScriptHistorySummary(*sshPtr, sshKey); if (sshPtr->isInitialized()) { //set iterator at unscanned height auto hgtx = sshIter.getKeyRef().getSliceRef(-4, 4); auto height = DBUtils::hgtxToHeight(hgtx); if (sshPtr->alreadyScannedUpToBlk_ >= height) { //this ssh has already been scanned beyond the height sshIter is at, //let's set the iterator to the correct height (or the next key) auto&& newKey = sshIter.getKey().getSliceCopy(0, subsshkey.getSize() - 4); auto&& newHgtx = DBUtils::heightAndDupToHgtx( sshPtr->alreadyScannedUpToBlk_ + 1, 0); newKey.append(newHgtx); sshIter.seekTo(newKey); continue; } } else { sshPtr->uniqueKey_ = sshKey; break; } } //sanity check if (!sshIter.isValid()) break; //deser subssh StoredSubHistory subssh; subssh.unserializeDBKey(sshIter.getKeyRef()); //check dupID if (db_->getValidDupIDForHeight(subssh.height_) != subssh.dupID_) continue; subssh.unserializeDBValue(sshIter.getValueRef()); for (auto& txioPair : subssh.txioMap_) { if (!txioPair.second.isMultisig()) { //add up balance if (txioPair.second.hasTxIn()) { //check for same block fund&spend auto&& keyOfOutput = txioPair.second.getDBKeyOfOutput(); auto&& keyOfInput = txioPair.second.getDBKeyOfInput(); if (keyOfOutput.startsWith(keyOfInput.getSliceRef(0, 4))) { //both output and input are part of the same block, skip continue; } sshPtr->totalUnspent_ -= txioPair.second.getValue(); } else { sshPtr->totalUnspent_ += txioPair.second.getValue(); } } } //txio count sshPtr->totalTxioCount_ += subssh.txioCount_; //build subssh summary sshPtr->subsshSummary_[subssh.height_] = subssh.txioCount_; } } //write it auto& topheader = blockchain_->getHeaderByHash(topScannedBlockHash_); auto topheight = topheader.getBlockHeight(); LMDBEnv::Transaction putsshtx; db_->beginDBTransaction(&putsshtx, SSH, LMDB::ReadWrite); auto& scrAddrMap = scrAddrFilter_->getScrAddrMap(); for (auto& scrAddr : scrAddrMap) { auto& ssh = sshMap_[scrAddr.first]; if (!ssh.isInitialized()) { ssh.uniqueKey_ = scrAddr.first; } BinaryData&& sshKey = ssh.getDBKey(); ssh.alreadyScannedUpToBlk_ = topheight; BinaryWriter bw; ssh.serializeDBValue(bw, ARMORY_DB_BARE, DB_PRUNE_NONE); db_->putValue(SSH, sshKey.getRef(), bw.getDataRef()); } //update sdbi StoredDBInfo sdbi; db_->getStoredDBInfo(SSH, sdbi); sdbi.topScannedBlkHash_ = topScannedBlockHash_; sdbi.topBlkHgt_ = topheight; db_->putStoredDBInfo(SSH, sdbi); }