// Copyright (c) 2011-2016 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "BlockchainIndices.h" #include "Common/StringTools.h" #include "CryptoNoteCore/CryptoNoteTools.h" #include "CryptoNoteCore/CryptoNoteFormatUtils.h" #include "BlockchainExplorer/BlockchainExplorerDataBuilder.h" #include "CryptoNoteBasicImpl.h" namespace CryptoNote { bool PaymentIdIndex::add(const Transaction& transaction) { Crypto::Hash paymentId; Crypto::Hash transactionHash = getObjectHash(transaction); if (!BlockchainExplorerDataBuilder::getPaymentId(transaction, paymentId)) { return false; } index.emplace(paymentId, transactionHash); return true; } bool PaymentIdIndex::remove(const Transaction& transaction) { Crypto::Hash paymentId; Crypto::Hash transactionHash = getObjectHash(transaction); if (!BlockchainExplorerDataBuilder::getPaymentId(transaction, paymentId)) { return false; } auto range = index.equal_range(paymentId); for (auto iter = range.first; iter != range.second; ++iter){ if (iter->second == transactionHash) { index.erase(iter); return true; } } return false; } bool PaymentIdIndex::find(const Crypto::Hash& paymentId, std::vector& transactionHashes) { bool found = false; auto range = index.equal_range(paymentId); for (auto iter = range.first; iter != range.second; ++iter){ found = true; transactionHashes.emplace_back(iter->second); } return found; } void PaymentIdIndex::clear() { index.clear(); } void PaymentIdIndex::serialize(ISerializer& s) { s(index, "index"); } bool TimestampBlocksIndex::add(uint64_t timestamp, const Crypto::Hash& hash) { index.emplace(timestamp, hash); return true; } bool TimestampBlocksIndex::remove(uint64_t timestamp, const Crypto::Hash& hash) { auto range = index.equal_range(timestamp); for (auto iter = range.first; iter != range.second; ++iter) { if (iter->second == hash) { index.erase(iter); return true; } } return false; } bool TimestampBlocksIndex::find(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t hashesNumberLimit, std::vector& hashes, uint32_t& hashesNumberWithinTimestamps) { uint32_t hashesNumber = 0; if (timestampBegin > timestampEnd) { //std::swap(timestampBegin, timestampEnd); return false; } auto begin = index.lower_bound(timestampBegin); auto end = index.upper_bound(timestampEnd); hashesNumberWithinTimestamps = static_cast(std::distance(begin, end)); for (auto iter = begin; iter != end && hashesNumber < hashesNumberLimit; ++iter){ ++hashesNumber; hashes.emplace_back(iter->second); } return hashesNumber > 0; } void TimestampBlocksIndex::clear() { index.clear(); } void TimestampBlocksIndex::serialize(ISerializer& s) { s(index, "index"); } bool TimestampTransactionsIndex::add(uint64_t timestamp, const Crypto::Hash& hash) { index.emplace(timestamp, hash); return true; } bool TimestampTransactionsIndex::remove(uint64_t timestamp, const Crypto::Hash& hash) { auto range = index.equal_range(timestamp); for (auto iter = range.first; iter != range.second; ++iter) { if (iter->second == hash) { index.erase(iter); return true; } } return false; } bool TimestampTransactionsIndex::find(uint64_t timestampBegin, uint64_t timestampEnd, uint64_t hashesNumberLimit, std::vector& hashes, uint64_t& hashesNumberWithinTimestamps) { uint32_t hashesNumber = 0; if (timestampBegin > timestampEnd) { //std::swap(timestampBegin, timestampEnd); return false; } auto begin = index.lower_bound(timestampBegin); auto end = index.upper_bound(timestampEnd); hashesNumberWithinTimestamps = static_cast(std::distance(begin, end)); for (auto iter = begin; iter != end && hashesNumber < hashesNumberLimit; ++iter) { ++hashesNumber; hashes.emplace_back(iter->second); } return hashesNumber > 0; } void TimestampTransactionsIndex::clear() { index.clear(); } void TimestampTransactionsIndex::serialize(ISerializer& s) { s(index, "index"); } GeneratedTransactionsIndex::GeneratedTransactionsIndex() : lastGeneratedTxNumber(0) { } bool GeneratedTransactionsIndex::add(const Block& block) { uint32_t blockHeight = boost::get(block.baseTransaction.inputs.front()).blockIndex; if (index.size() != blockHeight) { return false; } bool status = index.emplace(blockHeight, lastGeneratedTxNumber + block.transactionHashes.size() + 1).second; //Plus miner tx if (status) { lastGeneratedTxNumber += block.transactionHashes.size() + 1; } return status; } bool GeneratedTransactionsIndex::remove(const Block& block) { uint32_t blockHeight = boost::get(block.baseTransaction.inputs.front()).blockIndex; if (blockHeight != index.size() - 1) { return false; } auto iter = index.find(blockHeight); assert(iter != index.end()); index.erase(iter); if (blockHeight != 0) { iter = index.find(blockHeight - 1); assert(iter != index.end()); lastGeneratedTxNumber = iter->second; } else { lastGeneratedTxNumber = 0; } return true; } bool GeneratedTransactionsIndex::find(uint32_t height, uint64_t& generatedTransactions) { if (height > std::numeric_limits::max()) { return false; } auto iter = index.find(height); if (iter == index.end()) { return false; } generatedTransactions = iter->second; return true; } void GeneratedTransactionsIndex::clear() { index.clear(); } void GeneratedTransactionsIndex::serialize(ISerializer& s) { s(index, "index"); s(lastGeneratedTxNumber, "lastGeneratedTxNumber"); } bool OrphanBlocksIndex::add(const Block& block) { Crypto::Hash blockHash = get_block_hash(block); uint32_t blockHeight = boost::get(block.baseTransaction.inputs.front()).blockIndex; index.emplace(blockHeight, blockHash); return true; } bool OrphanBlocksIndex::remove(const Block& block) { Crypto::Hash blockHash = get_block_hash(block); uint32_t blockHeight = boost::get(block.baseTransaction.inputs.front()).blockIndex; auto range = index.equal_range(blockHeight); for (auto iter = range.first; iter != range.second; ++iter) { if (iter->second == blockHash) { index.erase(iter); return true; } } return false; } bool OrphanBlocksIndex::find(uint32_t height, std::vector& blockHashes) { if (height > std::numeric_limits::max()) { return false; } bool found = false; auto range = index.equal_range(height); for (auto iter = range.first; iter != range.second; ++iter) { found = true; blockHashes.emplace_back(iter->second); } return found; } void OrphanBlocksIndex::clear() { index.clear(); } }