void unspent_outputs::remove(const output_point& point) { if (capacity_ == 0) return; const unspent_transaction key{ point }; // Critical Section /////////////////////////////////////////////////////////////////////////// mutex_.lock_upgrade(); // Find the unspent tx entry that may contain the output. auto tx = unspent_.left.find(key); if (tx == unspent_.left.end()) { mutex_.unlock_upgrade(); //--------------------------------------------------------------------- return; } const auto outputs = tx->first.outputs(); mutex_.unlock_upgrade_and_lock(); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Erase the output if found at the specified index for the found tx. outputs->erase(point.index()); // Erase the unspent transaction if it is now fully spent. if (outputs->empty()) unspent_.left.erase(tx); mutex_.unlock(); /////////////////////////////////////////////////////////////////////////// }
bool unspent_outputs::get(output& out_output, size_t& out_height, bool& out_coinbase, const output_point& point, size_t fork_height) const { if (capacity_ == 0) return false; ++queries_; const unspent_transaction key{ point }; // Critical Section /////////////////////////////////////////////////////////////////////////// shared_lock lock(mutex_); // Find the unspent tx entry. const auto tx = unspent_.left.find(key); if (tx == unspent_.left.end()) return false; // Find the output at the specified index for the found unspent tx. const auto outputs = tx->first.outputs(); const auto output = outputs->find(point.index()); if (output == outputs->end()) return false; // Determine if the cached unspent tx is above specified fork_height. // Since the hash table does not allow duplicates there are no others. const auto& unspent = tx->first; const auto height = tx->first.height(); if (height > fork_height) return false; ++hits_; out_height = height; out_coinbase = unspent.is_coinbase(); out_output = output->second; return true; /////////////////////////////////////////////////////////////////////////// }
// All responses are unspent, metadata should be defaulted by caller. bool unspent_outputs::populate(const output_point& point, size_t fork_height) const { if (disabled()) return false; ++queries_; auto& prevout = point.metadata; const unspent_transaction key{ point }; // Critical Section /////////////////////////////////////////////////////////////////////////// shared_lock lock(mutex_); // Find the unspent tx entry. const auto tx = unspent_.left.find(key); if (tx == unspent_.left.end()) return false; // Find the output at the specified index for the found unspent tx. const auto& transaction = tx->first; const auto outputs = transaction.outputs(); const auto output = outputs->find(point.index()); if (output == outputs->end()) return false; ++hits_; const auto height = transaction.height(); // Populate the output metadata. prevout.spent = false; prevout.candidate = false; prevout.confirmed = transaction.is_confirmed() && height <= fork_height; prevout.coinbase = transaction.is_coinbase(); prevout.height = height; prevout.median_time_past = transaction.median_time_past(); prevout.cache = output->second; return true; /////////////////////////////////////////////////////////////////////////// }