#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include class CWallet; namespace MWEB { class Wallet { CWallet* m_pWallet; std::map m_coins; public: Wallet(CWallet* pWallet) : m_pWallet(pWallet) {} bool IsChange(const StealthAddress& address) const; bool GetCoin(const mw::Hash& output_id, mw::Coin& coin) const; // Loops through the transactions in the wallet and attempts to fill // in missing information for mw::Coin's, in particular the spend key. // Intended to be called after unlocking an encrypted wallet. bool UpgradeCoins(); std::vector RewindOutputs(const CTransaction& tx); bool RewindOutput(const Output& output, mw::Coin& coin); bool GetStealthAddress(const mw::Coin& coin, StealthAddress& address) const; bool GetStealthAddress(const uint32_t index, StealthAddress& address) const; void LoadToWallet(const mw::Coin& coin); void SaveToWallet(const std::vector& coins); private: mw::Keychain::Ptr GetKeychain() const; }; struct WalletTxInfo { // When connecting a block, if an output is found that belongs to us, // we check if we have a CWalletTx that created it. // If none is found, then we assume it is a newly received coin, // so we create an empty transaction and store the received coin here. boost::optional received_coin; // When connecting a block, if one of the wallet's coins is spent, // we check if we have a CWalletTx that spent it. // If none is found, then we assume it was spent by another wallet, // so we create an empty Transaction and store the spent hash here. boost::optional spent_input; mutable uint256 hash; WalletTxInfo() : received_coin(boost::none), spent_input(boost::none), hash() { } WalletTxInfo(mw::Coin received) : received_coin(std::move(received)), spent_input(boost::none), hash(received_coin->output_id.vec()) {} WalletTxInfo(mw::Hash spent) : received_coin(boost::none), spent_input(std::move(spent)), hash(spent_input->vec()) {} SERIALIZE_METHODS(WalletTxInfo, obj) { bool received = !!obj.received_coin; READWRITE(received); if (received) { mw::Coin coin; SER_WRITE(obj, coin = *obj.received_coin); READWRITE(coin); SER_READ(obj, obj.hash = uint256(coin.output_id.vec())); SER_READ(obj, obj.received_coin = boost::make_optional(std::move(coin))); } else { mw::Hash output_id; SER_WRITE(obj, output_id = *obj.spent_input); READWRITE(output_id); SER_READ(obj, obj.hash = uint256(output_id.vec())); SER_READ(obj, obj.spent_input = boost::make_optional(std::move(output_id))); } } static WalletTxInfo FromHex(const std::string& str) { std::vector bytes = ParseHex(str); CDataStream stream((const char*)bytes.data(), (const char*)bytes.data() + bytes.size(), SER_DISK, PROTOCOL_VERSION); WalletTxInfo wtx_info; stream >> wtx_info; return wtx_info; } std::string ToHex() const { CDataStream stream(SER_DISK, PROTOCOL_VERSION); stream << *this; return HexStr(std::vector{stream.begin(), stream.end()}); } const uint256& GetHash() const { return hash; } }; } // namespace MWEB