#pragma once // Copyright (c) 2018-2019 David Burkett // Distributed under the MIT software license, see the accompanying // file LICENSE or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include MW_NAMESPACE //////////////////////////////////////// // TRANSACTION - Represents a transaction or merged transactions before they've been included in a block. //////////////////////////////////////// class Transaction : public Traits::IPrintable, public Traits::ISerializable, public Traits::IHashable { public: using CPtr = std::shared_ptr; // // Constructors // Transaction(BlindingFactor kernel_offset, BlindingFactor stealth_offset, TxBody body) : m_kernelOffset(std::move(kernel_offset)), m_stealthOffset(std::move(stealth_offset)), m_body(std::move(body)) { m_hash = Hashed(*this); } Transaction(const Transaction& transaction) = default; Transaction(Transaction&& transaction) noexcept = default; Transaction() = default; // // Factory // static mw::Transaction::CPtr Create( BlindingFactor kernel_offset, BlindingFactor owner_offset, std::vector inputs, std::vector outputs, std::vector kernels ); // // Destructor // virtual ~Transaction() = default; // // Operators // Transaction& operator=(const Transaction& transaction) = default; Transaction& operator=(Transaction&& transaction) noexcept = default; bool operator<(const Transaction& transaction) const noexcept { return GetHash() < transaction.GetHash(); } bool operator==(const Transaction& transaction) const noexcept { return GetHash() == transaction.GetHash(); } bool operator!=(const Transaction& transaction) const noexcept { return GetHash() != transaction.GetHash(); } // // Getters // const BlindingFactor& GetKernelOffset() const noexcept { return m_kernelOffset; } const BlindingFactor& GetStealthOffset() const noexcept { return m_stealthOffset; } const TxBody& GetBody() const noexcept { return m_body; } const std::vector& GetInputs() const noexcept { return m_body.GetInputs(); } const std::vector& GetOutputs() const noexcept { return m_body.GetOutputs(); } const std::vector& GetKernels() const noexcept { return m_body.GetKernels(); } boost::optional GetTotalFee() const noexcept { return m_body.GetTotalFee(); } int32_t GetLockHeight() const noexcept { return m_body.GetLockHeight(); } uint64_t CalcWeight() const noexcept { return (uint64_t)Weight::Calculate(m_body); } std::vector GetKernelCommits() const noexcept { return m_body.GetKernelCommits(); } std::vector GetInputCommits() const noexcept { return m_body.GetInputCommits(); } std::vector GetOutputCommits() const noexcept { return m_body.GetOutputCommits(); } std::vector GetPegIns() const noexcept { return m_body.GetPegIns(); } boost::optional GetPegInAmount() const noexcept { return m_body.GetPegInAmount(); } std::vector GetPegOuts() const noexcept { return m_body.GetPegOuts(); } boost::optional GetSupplyChange() const noexcept { return m_body.GetSupplyChange(); } // // Serialization/Deserialization // IMPL_SERIALIZABLE(Transaction, obj) { READWRITE(obj.m_kernelOffset); READWRITE(obj.m_stealthOffset); READWRITE(obj.m_body); SER_READ(obj, obj.m_hash = Hashed(obj)); if (ser_action.ForRead()) { if (obj.m_body.GetKernels().empty()) { throw std::ios_base::failure("Transaction requires at least one kernel"); } } } // // Traits // std::string Format() const final { return "Tx(" + GetHash().Format() + ")"; } const mw::Hash& GetHash() const noexcept final { return m_hash; } bool IsStandard() const noexcept; void Validate() const; std::string Print() const { auto print_kernel = [](const Kernel& kernel) -> std::string { const auto pegout_amount = kernel.GetPegOutAmount(); return StringUtil::Format( "kern(kernel_id:{}, commit:{}, pegin: {}, pegout: {}, fee: {})", kernel.GetKernelID(), kernel.GetCommitment(), kernel.GetPegIn(), pegout_amount ? StringUtil::Format("{}", *pegout_amount) : "INVALID", kernel.GetFee() ); }; std::string kernels_str = std::accumulate( GetKernels().begin(), GetKernels().end(), std::string{}, [&print_kernel](std::string str, const Kernel& kern) { return str.empty() ? print_kernel(kern) : std::move(str) + ", " + print_kernel(kern); } ); return StringUtil::Format( "tx(hash:{}, offset:{}, kernels:[{}], inputs:{}, outputs:{})", GetHash(), GetKernelOffset().ToHex(), kernels_str, GetInputs(), GetOutputs() ); } private: // The kernel "offset" k2 excess is k1G after splitting the key k = k1 + k2. BlindingFactor m_kernelOffset; BlindingFactor m_stealthOffset; // The transaction body. TxBody m_body; mw::Hash m_hash; }; END_NAMESPACE