#ifndef XRPL_PROTOCOL_STXATTESTATIONS_H_INCLUDED #define XRPL_PROTOCOL_STXATTESTATIONS_H_INCLUDED #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_