// 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. #pragma once #include #include #include #include #include #include #include #include #include "crypto/crypto.h" #include "CryptoNoteCore/CryptoNoteBasic.h" #include "CryptoNoteCore/CryptoNoteSerialization.h" #include "CryptoNoteCore/Currency.h" #include "Serialization/ISerializer.h" #include "Serialization/SerializationOverloads.h" #include "ITransaction.h" #include "ITransfersContainer.h" namespace CryptoNote { struct TransactionOutputInformationIn; class SpentOutputDescriptor { public: SpentOutputDescriptor(); SpentOutputDescriptor(const TransactionOutputInformationIn& transactionInfo); SpentOutputDescriptor(const Crypto::KeyImage* keyImage); SpentOutputDescriptor(uint64_t amount, uint32_t globalOutputIndex); void assign(const Crypto::KeyImage* keyImage); void assign(uint64_t amount, uint32_t globalOutputIndex); bool isValid() const; bool operator==(const SpentOutputDescriptor& other) const; size_t hash() const; private: TransactionTypes::OutputType m_type; union { const Crypto::KeyImage* m_keyImage; struct { uint64_t m_amount; uint32_t m_globalOutputIndex; }; }; }; struct SpentOutputDescriptorHasher { size_t operator()(const SpentOutputDescriptor& descriptor) const { return descriptor.hash(); } }; struct TransactionOutputInformationIn : public TransactionOutputInformation { Crypto::KeyImage keyImage; //!< \attention Used only for TransactionTypes::OutputType::Key }; struct TransactionOutputInformationEx : public TransactionOutputInformationIn { uint64_t unlockTime; uint32_t blockHeight; uint32_t transactionIndex; bool visible; SpentOutputDescriptor getSpentOutputDescriptor() const { return SpentOutputDescriptor(*this); } const Crypto::Hash& getTransactionHash() const { return transactionHash; } void serialize(CryptoNote::ISerializer& s) { s(reinterpret_cast(type), "type"); s(amount, ""); serializeGlobalOutputIndex(s, globalOutputIndex, ""); s(outputInTransaction, ""); s(transactionPublicKey, ""); s(keyImage, ""); s(unlockTime, ""); serializeBlockHeight(s, blockHeight, ""); s(transactionIndex, ""); s(transactionHash, ""); s(visible, ""); if (type == TransactionTypes::OutputType::Key) s(outputKey, ""); else if (type == TransactionTypes::OutputType::Multisignature) s(requiredSignatures, ""); } }; struct TransactionBlockInfo { uint32_t height; uint64_t timestamp; uint32_t transactionIndex; void serialize(ISerializer& s) { serializeBlockHeight(s, height, "height"); s(timestamp, "timestamp"); s(transactionIndex, "transactionIndex"); } }; struct SpentTransactionOutput : TransactionOutputInformationEx { TransactionBlockInfo spendingBlock; Crypto::Hash spendingTransactionHash; uint32_t inputInTransaction; const Crypto::Hash& getSpendingTransactionHash() const { return spendingTransactionHash; } void serialize(ISerializer& s) { TransactionOutputInformationEx::serialize(s); s(spendingBlock, "spendingBlock"); s(spendingTransactionHash, "spendingTransactionHash"); s(inputInTransaction, "inputInTransaction"); } }; enum class KeyImageState { Unconfirmed, Confirmed, Spent }; struct KeyOutputInfo { KeyImageState state; size_t count; }; class TransfersContainer : public ITransfersContainer { public: TransfersContainer(const CryptoNote::Currency& currency, size_t transactionSpendableAge); bool addTransaction(const TransactionBlockInfo& block, const ITransactionReader& tx, const std::vector& transfers); bool deleteUnconfirmedTransaction(const Crypto::Hash& transactionHash); bool markTransactionConfirmed(const TransactionBlockInfo& block, const Crypto::Hash& transactionHash, const std::vector& globalIndices); std::vector detach(uint32_t height); bool advanceHeight(uint32_t height); // ITransfersContainer virtual size_t transfersCount() const override; virtual size_t transactionsCount() const override; virtual uint64_t balance(uint32_t flags) const override; virtual void getOutputs(std::vector& transfers, uint32_t flags) const override; virtual bool getTransactionInformation(const Crypto::Hash& transactionHash, TransactionInformation& info, uint64_t* amountIn = nullptr, uint64_t* amountOut = nullptr) const override; virtual std::vector getTransactionOutputs(const Crypto::Hash& transactionHash, uint32_t flags) const override; //only type flags are feasible for this function virtual std::vector getTransactionInputs(const Crypto::Hash& transactionHash, uint32_t flags) const override; virtual void getUnconfirmedTransactions(std::vector& transactions) const override; virtual std::vector getSpentOutputs() const override; // IStreamSerializable virtual void save(std::ostream& os) override; virtual void load(std::istream& in) override; private: struct ContainingTransactionIndex { }; struct SpendingTransactionIndex { }; struct SpentOutputDescriptorIndex { }; typedef boost::multi_index_container< TransactionInformation, boost::multi_index::indexed_by< boost::multi_index::hashed_unique, boost::multi_index::ordered_non_unique < BOOST_MULTI_INDEX_MEMBER(TransactionInformation, uint32_t, blockHeight) > > > TransactionMultiIndex; typedef boost::multi_index_container< TransactionOutputInformationEx, boost::multi_index::indexed_by< boost::multi_index::hashed_non_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun< TransactionOutputInformationEx, SpentOutputDescriptor, &TransactionOutputInformationEx::getSpentOutputDescriptor>, SpentOutputDescriptorHasher >, boost::multi_index::hashed_non_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun< TransactionOutputInformationEx, const Crypto::Hash&, &TransactionOutputInformationEx::getTransactionHash> > > > UnconfirmedTransfersMultiIndex; typedef boost::multi_index_container< TransactionOutputInformationEx, boost::multi_index::indexed_by< boost::multi_index::hashed_non_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun< TransactionOutputInformationEx, SpentOutputDescriptor, &TransactionOutputInformationEx::getSpentOutputDescriptor>, SpentOutputDescriptorHasher >, boost::multi_index::hashed_non_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun< TransactionOutputInformationEx, const Crypto::Hash&, &TransactionOutputInformationEx::getTransactionHash> > > > AvailableTransfersMultiIndex; typedef boost::multi_index_container< SpentTransactionOutput, boost::multi_index::indexed_by< boost::multi_index::hashed_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun< TransactionOutputInformationEx, SpentOutputDescriptor, &TransactionOutputInformationEx::getSpentOutputDescriptor>, SpentOutputDescriptorHasher >, boost::multi_index::hashed_non_unique< boost::multi_index::tag, boost::multi_index::const_mem_fun< TransactionOutputInformationEx, const Crypto::Hash&, &SpentTransactionOutput::getTransactionHash> >, boost::multi_index::hashed_non_unique < boost::multi_index::tag, boost::multi_index::const_mem_fun < SpentTransactionOutput, const Crypto::Hash&, &SpentTransactionOutput::getSpendingTransactionHash> > > > SpentTransfersMultiIndex; private: void addTransaction(const TransactionBlockInfo& block, const ITransactionReader& tx); bool addTransactionOutputs(const TransactionBlockInfo& block, const ITransactionReader& tx, const std::vector& transfers); bool addTransactionInputs(const TransactionBlockInfo& block, const ITransactionReader& tx); void deleteTransactionTransfers(const Crypto::Hash& transactionHash); bool isSpendTimeUnlocked(uint64_t unlockTime) const; bool isIncluded(const TransactionOutputInformationEx& info, uint32_t flags) const; static bool isIncluded(TransactionTypes::OutputType type, uint32_t state, uint32_t flags); void updateTransfersVisibility(const Crypto::KeyImage& keyImage); void copyToSpent(const TransactionBlockInfo& block, const ITransactionReader& tx, size_t inputIndex, const TransactionOutputInformationEx& output); private: TransactionMultiIndex m_transactions; UnconfirmedTransfersMultiIndex m_unconfirmedTransfers; AvailableTransfersMultiIndex m_availableTransfers; SpentTransfersMultiIndex m_spentTransfers; //std::unordered_map> m_keyImages; uint32_t m_currentHeight; // current height is needed to check if a transfer is unlocked size_t m_transactionSpendableAge; const CryptoNote::Currency& m_currency; mutable std::mutex m_mutex; }; }