//------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled Copyright (c) 2022 Ripple Labs Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #ifndef RIPPLE_PROTOCOL_STXATTESTATIONS_H_INCLUDED #define RIPPLE_PROTOCOL_STXATTESTATIONS_H_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ripple { namespace Attestations { struct AttestationBase { // Account associated with the public key AccountID attestationSignerAccount; // Public key from the witness server attesting to the event PublicKey publicKey; // Signature from the witness server attesting to the event Buffer signature; // Account on the sending chain that triggered the event (sent the // transaction) AccountID sendingAccount; // Amount transfered on the sending chain STAmount sendingAmount; // Account on the destination chain that collects a share of the attestation // reward AccountID rewardAccount; // Amount was transfered on the locking chain bool wasLockingChainSend; explicit AttestationBase( AccountID attestationSignerAccount_, PublicKey const& publicKey_, Buffer signature_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_); AttestationBase(AttestationBase const&) = default; virtual ~AttestationBase() = default; AttestationBase& operator=(AttestationBase const&) = default; // verify that the signature attests to the data. bool verify(STXChainBridge const& bridge) const; protected: explicit AttestationBase(STObject const& o); explicit AttestationBase(Json::Value const& v); [[nodiscard]] static bool equalHelper(AttestationBase const& lhs, AttestationBase const& rhs); [[nodiscard]] static bool sameEventHelper(AttestationBase const& lhs, AttestationBase const& rhs); void addHelper(STObject& o) const; private: [[nodiscard]] virtual std::vector message(STXChainBridge const& bridge) const = 0; }; // Attest to a regular cross-chain transfer struct AttestationClaim : AttestationBase { std::uint64_t claimID; std::optional dst; explicit AttestationClaim( AccountID attestationSignerAccount_, PublicKey const& publicKey_, Buffer signature_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t claimID_, std::optional const& dst_); explicit AttestationClaim( STXChainBridge const& bridge, AccountID attestationSignerAccount_, PublicKey const& publicKey_, SecretKey const& secretKey_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t claimID_, std::optional const& dst_); explicit AttestationClaim(STObject const& o); explicit AttestationClaim(Json::Value const& v); [[nodiscard]] STObject toSTObject() const; // return true if the two attestations attest to the same thing [[nodiscard]] bool sameEvent(AttestationClaim const& rhs) const; [[nodiscard]] static std::vector message( STXChainBridge const& bridge, AccountID const& sendingAccount, STAmount const& sendingAmount, AccountID const& rewardAccount, bool wasLockingChainSend, std::uint64_t claimID, std::optional const& dst); [[nodiscard]] bool validAmounts() const; private: [[nodiscard]] std::vector message(STXChainBridge const& bridge) const override; friend bool operator==(AttestationClaim const& lhs, AttestationClaim const& rhs); }; struct CmpByClaimID { bool operator()(AttestationClaim const& lhs, AttestationClaim const& rhs) const { return lhs.claimID < rhs.claimID; } }; // Attest to a cross-chain transfer that creates an account struct AttestationCreateAccount : AttestationBase { // createCount on the sending chain. This is the value of the `CreateCount` // field of the bridge on the sending chain when the transaction was // executed. std::uint64_t createCount; // Account to create on the destination chain AccountID toCreate; // Total amount of the reward pool STAmount rewardAmount; explicit AttestationCreateAccount(STObject const& o); explicit AttestationCreateAccount(Json::Value const& v); explicit AttestationCreateAccount( AccountID attestationSignerAccount_, PublicKey const& publicKey_, Buffer signature_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, STAmount const& rewardAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t createCount_, AccountID const& toCreate_); explicit AttestationCreateAccount( STXChainBridge const& bridge, AccountID attestationSignerAccount_, PublicKey const& publicKey_, SecretKey const& secretKey_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, STAmount const& rewardAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t createCount_, AccountID const& toCreate_); [[nodiscard]] STObject toSTObject() const; // return true if the two attestations attest to the same thing [[nodiscard]] bool sameEvent(AttestationCreateAccount const& rhs) const; friend bool operator==( AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs); [[nodiscard]] static std::vector message( STXChainBridge const& bridge, AccountID const& sendingAccount, STAmount const& sendingAmount, STAmount const& rewardAmount, AccountID const& rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, AccountID const& dst); [[nodiscard]] bool validAmounts() const; private: [[nodiscard]] std::vector message(STXChainBridge const& bridge) const override; }; struct CmpByCreateCount { bool operator()( AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs) const { return lhs.createCount < rhs.createCount; } }; }; // namespace Attestations // Result when checking when two attestation match. enum class AttestationMatch { // One of the fields doesn't match, and it isn't the dst field nonDstMismatch, // all of the fields match, except the dst field matchExceptDst, // all of the fields match match }; struct XChainClaimAttestation { using TSignedAttestation = Attestations::AttestationClaim; static SField const& ArrayFieldName; AccountID keyAccount; PublicKey publicKey; STAmount amount; AccountID rewardAccount; bool wasLockingChainSend; std::optional dst; struct MatchFields { STAmount amount; bool wasLockingChainSend; std::optional dst; MatchFields(TSignedAttestation const& att); MatchFields( STAmount const& a, bool b, std::optional const& d) : amount{a}, wasLockingChainSend{b}, dst{d} { } }; explicit XChainClaimAttestation( AccountID const& keyAccount_, PublicKey const& publicKey_, STAmount const& amount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::optional const& dst); explicit XChainClaimAttestation( STAccount const& keyAccount_, PublicKey const& publicKey_, STAmount const& amount_, STAccount const& rewardAccount_, bool wasLockingChainSend_, std::optional const& dst); explicit XChainClaimAttestation(TSignedAttestation const& claimAtt); explicit XChainClaimAttestation(STObject const& o); explicit XChainClaimAttestation(Json::Value const& v); AttestationMatch match(MatchFields const& rhs) const; [[nodiscard]] STObject toSTObject() const; friend bool operator==( XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs); }; struct XChainCreateAccountAttestation { using TSignedAttestation = Attestations::AttestationCreateAccount; static SField const& ArrayFieldName; AccountID keyAccount; PublicKey publicKey; STAmount amount; STAmount rewardAmount; AccountID rewardAccount; bool wasLockingChainSend; AccountID dst; struct MatchFields { STAmount amount; STAmount rewardAmount; bool wasLockingChainSend; AccountID dst; MatchFields(TSignedAttestation const& att); }; explicit XChainCreateAccountAttestation( AccountID const& keyAccount_, PublicKey const& publicKey_, STAmount const& amount_, STAmount const& rewardAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, AccountID const& dst_); explicit XChainCreateAccountAttestation(TSignedAttestation const& claimAtt); explicit XChainCreateAccountAttestation(STObject const& o); explicit XChainCreateAccountAttestation(Json::Value const& v); [[nodiscard]] STObject toSTObject() const; AttestationMatch match(MatchFields const& rhs) const; friend bool operator==( XChainCreateAccountAttestation const& lhs, XChainCreateAccountAttestation const& rhs); }; // Attestations from witness servers for a particular claimid and bridge. // Only one attestation per signature is allowed. template class XChainAttestationsBase { public: using AttCollection = std::vector; private: // Set a max number of allowed attestations to limit the amount of memory // allocated and processing time. This number is much larger than the actual // number of attestation a server would ever expect. static constexpr std::uint32_t maxAttestations = 256; AttCollection attestations_; protected: // Prevent slicing to the base class ~XChainAttestationsBase() = default; public: XChainAttestationsBase() = default; XChainAttestationsBase(XChainAttestationsBase const& rhs) = default; XChainAttestationsBase& operator=(XChainAttestationsBase const& rhs) = default; explicit XChainAttestationsBase(AttCollection&& sigs); explicit XChainAttestationsBase(Json::Value const& v); explicit XChainAttestationsBase(STArray const& arr); [[nodiscard]] STArray toSTArray() const; typename AttCollection::const_iterator begin() const; typename AttCollection::const_iterator end() const; typename AttCollection::iterator begin(); typename AttCollection::iterator end(); template std::size_t erase_if(F&& f); std::size_t size() const; bool empty() const; AttCollection const& attestations() const; template void emplace_back(T&& att); }; template [[nodiscard]] inline bool operator==( XChainAttestationsBase const& lhs, XChainAttestationsBase const& rhs) { return lhs.attestations() == rhs.attestations(); } template inline typename XChainAttestationsBase::AttCollection const& XChainAttestationsBase::attestations() const { return attestations_; }; template template inline void XChainAttestationsBase::emplace_back(T&& att) { attestations_.emplace_back(std::forward(att)); }; template template inline std::size_t XChainAttestationsBase::erase_if(F&& f) { return std::erase_if(attestations_, std::forward(f)); } template inline std::size_t XChainAttestationsBase::size() const { return attestations_.size(); } template inline bool XChainAttestationsBase::empty() const { return attestations_.empty(); } class XChainClaimAttestations final : public XChainAttestationsBase { using TBase = XChainAttestationsBase; using TBase::TBase; }; class XChainCreateAccountAttestations final : public XChainAttestationsBase { using TBase = XChainAttestationsBase; using TBase::TBase; }; } // namespace ripple #endif // STXCHAINATTESTATIONS_H_