Files
rippled/include/xrpl/protocol/XChainAttestations.h
2025-10-23 11:04:30 -04:00

484 lines
13 KiB
C++

#ifndef XRPL_PROTOCOL_STXATTESTATIONS_H_INCLUDED
#define XRPL_PROTOCOL_STXATTESTATIONS_H_INCLUDED
#include <xrpl/basics/Buffer.h>
#include <xrpl/basics/Expected.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/STXChainBridge.h>
#include <xrpl/protocol/SecretKey.h>
#include <xrpl/protocol/TER.h>
#include <boost/container/flat_set.hpp>
#include <boost/container/vector.hpp>
#include <cstddef>
#include <vector>
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<std::uint8_t>
message(STXChainBridge const& bridge) const = 0;
};
// Attest to a regular cross-chain transfer
struct AttestationClaim : AttestationBase
{
std::uint64_t claimID;
std::optional<AccountID> 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<AccountID> 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<AccountID> 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<std::uint8_t>
message(
STXChainBridge const& bridge,
AccountID const& sendingAccount,
STAmount const& sendingAmount,
AccountID const& rewardAccount,
bool wasLockingChainSend,
std::uint64_t claimID,
std::optional<AccountID> const& dst);
[[nodiscard]] bool
validAmounts() const;
private:
[[nodiscard]] std::vector<std::uint8_t>
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<std::uint8_t>
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<std::uint8_t>
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<AccountID> dst;
struct MatchFields
{
STAmount amount;
bool wasLockingChainSend;
std::optional<AccountID> dst;
MatchFields(TSignedAttestation const& att);
MatchFields(
STAmount const& a,
bool b,
std::optional<AccountID> 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<AccountID> const& dst);
explicit XChainClaimAttestation(
STAccount const& keyAccount_,
PublicKey const& publicKey_,
STAmount const& amount_,
STAccount const& rewardAccount_,
bool wasLockingChainSend_,
std::optional<STAccount> 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 TAttestation>
class XChainAttestationsBase
{
public:
using AttCollection = std::vector<TAttestation>;
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 <class F>
std::size_t
erase_if(F&& f);
std::size_t
size() const;
bool
empty() const;
AttCollection const&
attestations() const;
template <class T>
void
emplace_back(T&& att);
};
template <class TAttestation>
[[nodiscard]] inline bool
operator==(
XChainAttestationsBase<TAttestation> const& lhs,
XChainAttestationsBase<TAttestation> const& rhs)
{
return lhs.attestations() == rhs.attestations();
}
template <class TAttestation>
inline typename XChainAttestationsBase<TAttestation>::AttCollection const&
XChainAttestationsBase<TAttestation>::attestations() const
{
return attestations_;
};
template <class TAttestation>
template <class T>
inline void
XChainAttestationsBase<TAttestation>::emplace_back(T&& att)
{
attestations_.emplace_back(std::forward<T>(att));
};
template <class TAttestation>
template <class F>
inline std::size_t
XChainAttestationsBase<TAttestation>::erase_if(F&& f)
{
return std::erase_if(attestations_, std::forward<F>(f));
}
template <class TAttestation>
inline std::size_t
XChainAttestationsBase<TAttestation>::size() const
{
return attestations_.size();
}
template <class TAttestation>
inline bool
XChainAttestationsBase<TAttestation>::empty() const
{
return attestations_.empty();
}
class XChainClaimAttestations final
: public XChainAttestationsBase<XChainClaimAttestation>
{
using TBase = XChainAttestationsBase<XChainClaimAttestation>;
using TBase::TBase;
};
class XChainCreateAccountAttestations final
: public XChainAttestationsBase<XChainCreateAccountAttestation>
{
using TBase = XChainAttestationsBase<XChainCreateAccountAttestation>;
using TBase::TBase;
};
} // namespace ripple
#endif // STXCHAINATTESTATIONS_H_