git / moonbite-core / src/libmw/include/mw/models/tx/Transaction.h · raw
#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 <mw/common/Macros.h>#include <mw/common/Traits.h>#include <mw/consensus/Weight.h>#include <mw/models/crypto/Hash.h>#include <mw/models/crypto/BigInteger.h>#include <mw/models/crypto/BlindingFactor.h>#include <mw/models/tx/TxBody.h>#include <memory>#include <numeric>#include <vector>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<const Transaction>; // // 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<Input> inputs, std::vector<Output> outputs, std::vector<Kernel> 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<Input>& GetInputs() const noexcept { return m_body.GetInputs(); } const std::vector<Output>& GetOutputs() const noexcept { return m_body.GetOutputs(); } const std::vector<Kernel>& GetKernels() const noexcept { return m_body.GetKernels(); } boost::optional<CAmount> 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<Commitment> GetKernelCommits() const noexcept { return m_body.GetKernelCommits(); } std::vector<Commitment> GetInputCommits() const noexcept { return m_body.GetInputCommits(); } std::vector<Commitment> GetOutputCommits() const noexcept { return m_body.GetOutputCommits(); } std::vector<PegInCoin> GetPegIns() const noexcept { return m_body.GetPegIns(); } boost::optional<CAmount> GetPegInAmount() const noexcept { return m_body.GetPegInAmount(); } std::vector<PegOutCoin> GetPegOuts() const noexcept { return m_body.GetPegOuts(); } boost::optional<CAmount> 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