git / moonbite-core / src/libmw/include/mw/models/tx/Kernel.h · raw
#pragma once#include <mw/common/Macros.h>#include <mw/common/Traits.h>#include <mw/consensus/Amount.h>#include <mw/crypto/Hasher.h>#include <mw/models/crypto/BlindingFactor.h>#include <mw/models/crypto/Commitment.h>#include <mw/models/crypto/SecretKey.h>#include <mw/models/crypto/Signature.h>#include <mw/models/crypto/SignedMessage.h>#include <mw/models/tx/PegOutCoin.h>#include <amount.h>#include <boost/optional.hpp>#include <numeric>class Kernel : public Traits::ICommitted, public Traits::IHashable, public Traits::ISerializable{public: Kernel() = default; Kernel( const uint8_t features, boost::optional<CAmount> fee, boost::optional<CAmount> pegin, std::vector<PegOutCoin> pegouts, boost::optional<int32_t> lockHeight, boost::optional<PublicKey> stealthExcess, std::vector<uint8_t> extraData, Commitment excess, Signature signature ) : m_features(features), m_fee(fee), m_pegin(pegin), m_pegouts(std::move(pegouts)), m_lockHeight(lockHeight), m_stealthExcess(std::move(stealthExcess)), m_extraData(std::move(extraData)), m_excess(std::move(excess)), m_signature(std::move(signature)) { m_hash = Hashed(*this); } enum FeatureBit { FEE_FEATURE_BIT = 0x01, PEGIN_FEATURE_BIT = 0x02, PEGOUT_FEATURE_BIT = 0x04, HEIGHT_LOCK_FEATURE_BIT = 0x08, STEALTH_EXCESS_FEATURE_BIT = 0x10, EXTRA_DATA_FEATURE_BIT = 0x20, ALL_FEATURE_BITS = FEE_FEATURE_BIT | PEGIN_FEATURE_BIT | PEGOUT_FEATURE_BIT | HEIGHT_LOCK_FEATURE_BIT | STEALTH_EXCESS_FEATURE_BIT | EXTRA_DATA_FEATURE_BIT }; // // Factories // static Kernel Create( const BlindingFactor& blind, const boost::optional<SecretKey>& stealth_blind, const boost::optional<CAmount>& fee, const boost::optional<CAmount>& pegin_amount, const std::vector<PegOutCoin>& pegouts, const boost::optional<int32_t>& lock_height ); // // Operators // bool operator<(const Kernel& rhs) const { return GetKernelID() < rhs.GetKernelID(); } bool operator==(const Kernel& rhs) const { return GetKernelID() == rhs.GetKernelID(); } bool operator!=(const Kernel& rhs) const { return GetKernelID() != rhs.GetKernelID(); } // // Getters // const mw::Hash& GetKernelID() const noexcept { return m_hash; } uint8_t GetFeatures() const noexcept { return m_features; } CAmount GetFee() const noexcept { return m_fee.value_or(0); } int32_t GetLockHeight() const noexcept { return m_lockHeight.value_or(0); } const Commitment& GetExcess() const noexcept { return m_excess; } const PublicKey& GetStealthExcess() const noexcept { return m_stealthExcess.value(); } const Signature& GetSignature() const noexcept { return m_signature; } const std::vector<uint8_t>& GetExtraData() const noexcept { return m_extraData; } bool IsStandard() const noexcept { return m_features < EXTRA_DATA_FEATURE_BIT; } SignedMessage BuildSignedMsg() const; static mw::Hash GetSignatureMessage( const uint8_t features, const Commitment& excess_commitment, const boost::optional<PublicKey>& stealth_commitment, const boost::optional<CAmount>& fee, const boost::optional<CAmount>& pegin_amount, const std::vector<PegOutCoin>& pegouts, const boost::optional<int32_t>& lock_height, const std::vector<uint8_t>& extra_data ); bool HasPegIn() const noexcept { return !!m_pegin; } bool HasPegOut() const noexcept { return !m_pegouts.empty(); } bool HasStealthExcess() const noexcept { return !!m_stealthExcess; } CAmount GetPegIn() const noexcept { return m_pegin.value_or(0); } const std::vector<PegOutCoin>& GetPegOuts() const noexcept { return m_pegouts; } boost::optional<CAmount> GetPegOutAmount() const noexcept { CAmount total = 0; for (const PegOutCoin& pegout : m_pegouts) { if (!AmountUtil::IsValidMoney(pegout.GetAmount())) { return boost::none; } const auto next_total = AmountUtil::TrySafeAdd(total, pegout.GetAmount()); if (!next_total || !AmountUtil::IsValidMoney(*next_total)) { return boost::none; } total = *next_total; } return total; } boost::optional<CAmount> GetSupplyChange() const noexcept { const CAmount pegin = m_pegin.value_or(0); const CAmount fee = m_fee.value_or(0); const auto pegout_amount = GetPegOutAmount(); if (!AmountUtil::IsValidMoney(pegin) || !AmountUtil::IsValidMoney(fee) || !pegout_amount) { return boost::none; } const auto supply_after_fee = AmountUtil::TrySafeSubtract(pegin, fee); if (!supply_after_fee) { return boost::none; } const auto supply_change = AmountUtil::TrySafeSubtract(*supply_after_fee, *pegout_amount); if (!supply_change || !AmountUtil::IsValidAmountRange(*supply_change)) { return boost::none; } return *supply_change; } // // Serialization/Deserialization // IMPL_SERIALIZED(Kernel); template <typename Stream> void Serialize(Stream& s) const { s << m_features; if (m_fee) { ::WriteVarInt<Stream, VarIntMode::NONNEGATIVE_SIGNED, CAmount>(s, m_fee.value()); } if (m_pegin) { ::WriteVarInt<Stream, VarIntMode::NONNEGATIVE_SIGNED, CAmount>(s, m_pegin.value()); } if (!m_pegouts.empty()) { s << m_pegouts; } if (m_lockHeight) { ::WriteVarInt<Stream, VarIntMode::NONNEGATIVE_SIGNED, int32_t>(s, m_lockHeight.value()); } if (m_stealthExcess) { s << m_stealthExcess.value(); } if (!m_extraData.empty()) { s << m_extraData; } s << m_excess << m_signature; } template <typename Stream> void Unserialize(Stream& s) { s >> m_features; if (m_features & FEE_FEATURE_BIT) { m_fee = ::ReadVarInt<Stream, VarIntMode::NONNEGATIVE_SIGNED, CAmount>(s); } if (m_features & PEGIN_FEATURE_BIT) { m_pegin = ::ReadVarInt<Stream, VarIntMode::NONNEGATIVE_SIGNED, CAmount>(s); } if (m_features & PEGOUT_FEATURE_BIT) { s >>m_pegouts; } if (m_features & HEIGHT_LOCK_FEATURE_BIT) { m_lockHeight = ::ReadVarInt<Stream, VarIntMode::NONNEGATIVE_SIGNED, int32_t>(s); } if (m_features & STEALTH_EXCESS_FEATURE_BIT) { PublicKey stealth_excess; s >> stealth_excess; m_stealthExcess = boost::make_optional(std::move(stealth_excess)); } if (m_features & EXTRA_DATA_FEATURE_BIT) { s >> m_extraData; } s >> m_excess >> m_signature; m_hash = Hashed(*this); } // // Traits // const mw::Hash& GetHash() const noexcept final { return m_hash; } const Commitment& GetCommitment() const noexcept final { return m_excess; }private: uint8_t m_features; boost::optional<CAmount> m_fee; boost::optional<CAmount> m_pegin; std::vector<PegOutCoin> m_pegouts; boost::optional<int32_t> m_lockHeight; boost::optional<PublicKey> m_stealthExcess; std::vector<uint8_t> m_extraData; // Remainder of the sum of all transaction commitments. // If the transaction is well formed, amounts components should sum to zero and the excess is hence a valid public key. Commitment m_excess; // The signature proving the excess is a valid public key, which signs the transaction fee. Signature m_signature; mw::Hash m_hash;};// Sorts by net supply increase [pegin - (fee + pegout)] with highest increase first, then sorts by hash.static const struct{ bool operator()(const Kernel& a, const Kernel& b) const { const auto a_supply_change = a.GetSupplyChange(); const auto b_supply_change = b.GetSupplyChange(); if (a_supply_change && b_supply_change) { return (*a_supply_change > *b_supply_change) || (*a_supply_change == *b_supply_change && a.GetHash() < b.GetHash()); } if (a_supply_change) { return true; } if (b_supply_change) { return false; } return a.GetHash() < b.GetHash(); }} KernelSort;