// 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 "ICoreStub.h" #include "CryptoNoteCore/CryptoNoteFormatUtils.h" #include "CryptoNoteCore/CryptoNoteTools.h" #include "CryptoNoteCore/IBlock.h" #include "CryptoNoteCore/VerificationContext.h" ICoreStub::ICoreStub() : topHeight(0), globalIndicesResult(false), randomOutsResult(false), poolTxVerificationResult(true), poolChangesResult(true) { } ICoreStub::ICoreStub(const CryptoNote::Block& genesisBlock) : topHeight(0), globalIndicesResult(false), randomOutsResult(false), poolTxVerificationResult(true), poolChangesResult(true) { addBlock(genesisBlock); } bool ICoreStub::addObserver(CryptoNote::ICoreObserver* observer) { return true; } bool ICoreStub::removeObserver(CryptoNote::ICoreObserver* observer) { return true; } void ICoreStub::get_blockchain_top(uint32_t& height, Crypto::Hash& top_id) { height = topHeight; top_id = topId; } std::vector ICoreStub::findBlockchainSupplement(const std::vector& remoteBlockIds, size_t maxCount, uint32_t& totalBlockCount, uint32_t& startBlockIndex) { //Sending all blockchain totalBlockCount = static_cast(blocks.size()); startBlockIndex = 0; std::vector result; result.reserve(std::min(blocks.size(), maxCount)); for (uint32_t height = 0; height < static_cast(std::min(blocks.size(), maxCount)); ++height) { assert(blockHashByHeightIndex.count(height) > 0); result.push_back(blockHashByHeightIndex[height]); } return result; } bool ICoreStub::get_random_outs_for_amounts(const CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request& req, CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res) { res = randomOuts; return randomOutsResult; } bool ICoreStub::get_tx_outputs_gindexs(const Crypto::Hash& tx_id, std::vector& indexs) { std::copy(globalIndices.begin(), globalIndices.end(), std::back_inserter(indexs)); return globalIndicesResult; } CryptoNote::i_cryptonote_protocol* ICoreStub::get_protocol() { return nullptr; } bool ICoreStub::handle_incoming_tx(CryptoNote::BinaryArray const& tx_blob, CryptoNote::tx_verification_context& tvc, bool keeped_by_block) { return true; } void ICoreStub::set_blockchain_top(uint32_t height, const Crypto::Hash& top_id) { topHeight = height; topId = top_id; } void ICoreStub::set_outputs_gindexs(const std::vector& indexs, bool result) { globalIndices.clear(); std::copy(indexs.begin(), indexs.end(), std::back_inserter(globalIndices)); globalIndicesResult = result; } void ICoreStub::set_random_outs(const CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& resp, bool result) { randomOuts = resp; randomOutsResult = result; } std::vector ICoreStub::getPoolTransactions() { return std::vector(); } bool ICoreStub::getPoolChanges(const Crypto::Hash& tailBlockId, const std::vector& knownTxsIds, std::vector& addedTxs, std::vector& deletedTxsIds) { std::unordered_set knownSet; for (const Crypto::Hash& txId : knownTxsIds) { if (transactionPool.find(txId) == transactionPool.end()) { deletedTxsIds.push_back(txId); } knownSet.insert(txId); } for (const std::pair& poolEntry : transactionPool) { if (knownSet.find(poolEntry.first) == knownSet.end()) { addedTxs.push_back(poolEntry.second); } } return poolChangesResult; } bool ICoreStub::getPoolChangesLite(const Crypto::Hash& tailBlockId, const std::vector& knownTxsIds, std::vector& addedTxs, std::vector& deletedTxsIds) { std::vector added; bool returnStatus = getPoolChanges(tailBlockId, knownTxsIds, added, deletedTxsIds); for (const auto& tx : added) { CryptoNote::TransactionPrefixInfo tpi; tpi.txPrefix = tx; tpi.txHash = getObjectHash(tx); addedTxs.push_back(std::move(tpi)); } return returnStatus; } void ICoreStub::getPoolChanges(const std::vector& knownTxsIds, std::vector& addedTxs, std::vector& deletedTxsIds) { } bool ICoreStub::queryBlocks(const std::vector& block_ids, uint64_t timestamp, uint32_t& start_height, uint32_t& current_height, uint32_t& full_offset, std::vector& entries) { //stub return true; } bool ICoreStub::queryBlocksLite(const std::vector& block_ids, uint64_t timestamp, uint32_t& start_height, uint32_t& current_height, uint32_t& full_offset, std::vector& entries) { //stub return true; } std::vector ICoreStub::buildSparseChain() { std::vector result; result.reserve(blockHashByHeightIndex.size()); for (auto kvPair : blockHashByHeightIndex) { result.emplace_back(kvPair.second); } std::reverse(result.begin(), result.end()); return result; } std::vector ICoreStub::buildSparseChain(const Crypto::Hash& startBlockId) { // TODO implement assert(blocks.count(startBlockId) > 0); std::vector result; result.emplace_back(blockHashByHeightIndex[0]); return result; } size_t ICoreStub::addChain(const std::vector& chain) { size_t blocksCounter = 0; for (const CryptoNote::IBlock* block : chain) { for (size_t txNumber = 0; txNumber < block->getTransactionCount(); ++txNumber) { const CryptoNote::Transaction& tx = block->getTransaction(txNumber); Crypto::Hash txHash = CryptoNote::NULL_HASH; size_t blobSize = 0; getObjectHash(tx, txHash, blobSize); addTransaction(tx); } addBlock(block->getBlock()); ++blocksCounter; } return blocksCounter; } Crypto::Hash ICoreStub::getBlockIdByHeight(uint32_t height) { auto iter = blockHashByHeightIndex.find(height); if (iter == blockHashByHeightIndex.end()) { return CryptoNote::NULL_HASH; } return iter->second; } bool ICoreStub::getBlockByHash(const Crypto::Hash &h, CryptoNote::Block &blk) { auto iter = blocks.find(h); if (iter == blocks.end()) { return false; } blk = iter->second; return true; } bool ICoreStub::getBlockHeight(const Crypto::Hash& blockId, uint32_t& blockHeight) { auto it = blocks.find(blockId); if (it == blocks.end()) { return false; } blockHeight = get_block_height(it->second); return true; } void ICoreStub::getTransactions(const std::vector& txs_ids, std::list& txs, std::list& missed_txs, bool checkTxPool) { for (const Crypto::Hash& hash : txs_ids) { auto iter = transactions.find(hash); if (iter != transactions.end()) { txs.push_back(iter->second); } else { missed_txs.push_back(hash); } } if (checkTxPool) { std::list pullTxIds(std::move(missed_txs)); missed_txs.clear(); for (const Crypto::Hash& hash : pullTxIds) { auto iter = transactionPool.find(hash); if (iter != transactionPool.end()) { txs.push_back(iter->second); } else { missed_txs.push_back(hash); } } } } bool ICoreStub::getBackwardBlocksSizes(uint32_t fromHeight, std::vector& sizes, size_t count) { return true; } bool ICoreStub::getBlockSize(const Crypto::Hash& hash, size_t& size) { return true; } bool ICoreStub::getAlreadyGeneratedCoins(const Crypto::Hash& hash, uint64_t& generatedCoins) { return true; } bool ICoreStub::getBlockReward(size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins, uint64_t fee, uint64_t& reward, int64_t& emissionChange) { return true; } bool ICoreStub::scanOutputkeysForIndices(const CryptoNote::KeyInput& txInToKey, std::list>& outputReferences) { return true; } bool ICoreStub::getBlockDifficulty(uint32_t height, CryptoNote::difficulty_type& difficulty) { return true; } bool ICoreStub::getBlockContainingTx(const Crypto::Hash& txId, Crypto::Hash& blockId, uint32_t& blockHeight) { auto iter = blockHashByTxHashIndex.find(txId); if (iter == blockHashByTxHashIndex.end()) { return false; } blockId = iter->second; auto blockIter = blocks.find(blockId); if (blockIter == blocks.end()) { return false; } blockHeight = boost::get(blockIter->second.baseTransaction.inputs.front()).blockIndex; return true; } bool ICoreStub::getMultisigOutputReference(const CryptoNote::MultisignatureInput& txInMultisig, std::pair& outputReference) { return true; } void ICoreStub::addBlock(const CryptoNote::Block& block) { uint32_t height = boost::get(block.baseTransaction.inputs.front()).blockIndex; Crypto::Hash hash = CryptoNote::get_block_hash(block); if (height > topHeight) { topHeight = height; topId = hash; } blocks.emplace(std::make_pair(hash, block)); blockHashByHeightIndex.emplace(std::make_pair(height, hash)); blockHashByTxHashIndex.emplace(std::make_pair(CryptoNote::getObjectHash(block.baseTransaction), hash)); for (auto txHash : block.transactionHashes) { blockHashByTxHashIndex.emplace(std::make_pair(txHash, hash)); } } void ICoreStub::addTransaction(const CryptoNote::Transaction& tx) { Crypto::Hash hash = CryptoNote::getObjectHash(tx); transactions.emplace(std::make_pair(hash, tx)); } bool ICoreStub::getGeneratedTransactionsNumber(uint32_t height, uint64_t& generatedTransactions) { return true; } bool ICoreStub::getOrphanBlocksByHeight(uint32_t height, std::vector& blocks) { return true; } bool ICoreStub::getBlocksByTimestamp(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector& blocks, uint32_t& blocksNumberWithinTimestamps) { return true; } bool ICoreStub::getPoolTransactionsByTimestamp(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t transactionsNumberLimit, std::vector& transactions, uint64_t& transactionsNumberWithinTimestamps) { return true; } bool ICoreStub::getTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector& transactions) { return true; } std::error_code ICoreStub::executeLocked(const std::function& func) { return func(); } std::unique_ptr ICoreStub::getBlock(const Crypto::Hash& blockId) { return std::unique_ptr(nullptr); } bool ICoreStub::handleIncomingTransaction(const CryptoNote::Transaction& tx, const Crypto::Hash& txHash, size_t blobSize, CryptoNote::tx_verification_context& tvc, bool keptByBlock) { auto result = transactionPool.emplace(std::make_pair(txHash, tx)); tvc.m_verifivation_failed = !poolTxVerificationResult; tvc.m_added_to_pool = true; tvc.m_should_be_relayed = result.second; return poolTxVerificationResult; } bool ICoreStub::have_block(const Crypto::Hash& id) { return blocks.count(id) > 0; } void ICoreStub::setPoolTxVerificationResult(bool result) { poolTxVerificationResult = result; } bool ICoreStub::addMessageQueue(CryptoNote::MessageQueue& messageQueuePtr) { return true; } bool ICoreStub::removeMessageQueue(CryptoNote::MessageQueue& messageQueuePtr) { return true; } void ICoreStub::setPoolChangesResult(bool result) { poolChangesResult = result; }