diff --git a/.cspell.config.yaml b/.cspell.config.yaml index dc24bf833b..d9c7978b3b 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -294,7 +294,6 @@ words: - sttx - stvar - stvector - - stxchainattestations - summands - superpeer - superpeers @@ -348,8 +347,6 @@ words: - writeme - wsrch - wthread - - xbridge - - xchain - ximinez - XMACRO - xrpkuwait diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 79ecd05ad5..3c55559354 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -255,17 +254,6 @@ amm(uint256 const& amm) noexcept; Keylet delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept; -Keylet -bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType); - -// `seq` is stored as `sfXChainClaimID` in the object -Keylet -xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq); - -// `seq` is stored as `sfXChainAccountCreateCount` in the object -Keylet -xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq); - Keylet did(AccountID const& account) noexcept; diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index d97bcb0a1d..785cf7826a 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -31,7 +31,6 @@ class STBitString; template class STInteger; class STNumber; -class STXChainBridge; class STVector256; class STCurrency; @@ -71,7 +70,7 @@ class STCurrency; STYPE(STI_UINT384, 22) \ STYPE(STI_UINT512, 23) \ STYPE(STI_ISSUE, 24) \ - STYPE(STI_XCHAIN_BRIDGE, 25) \ + /* 25 is unused */ \ STYPE(STI_CURRENCY, 26) \ \ /* high-level types */ \ @@ -353,7 +352,6 @@ using SF_CURRENCY = TypedField; using SF_NUMBER = TypedField; using SF_VL = TypedField; using SF_VECTOR256 = TypedField; -using SF_XCHAIN_BRIDGE = TypedField; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 9abf56e91b..0a1c4fb0c4 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/include/xrpl/protocol/STXChainBridge.h b/include/xrpl/protocol/STXChainBridge.h deleted file mode 100644 index 24d64ef02b..0000000000 --- a/include/xrpl/protocol/STXChainBridge.h +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace xrpl { - -class Serializer; -class STObject; - -class STXChainBridge final : public STBase, public CountedObject -{ - STAccount lockingChainDoor_{sfLockingChainDoor}; - STIssue lockingChainIssue_{sfLockingChainIssue}; - STAccount issuingChainDoor_{sfIssuingChainDoor}; - STIssue issuingChainIssue_{sfIssuingChainIssue}; - -public: - using value_type = STXChainBridge; - - enum class ChainType { Locking, Issuing }; - - static ChainType - otherChain(ChainType ct); - - static ChainType - srcChain(bool wasLockingChainSend); - - static ChainType - dstChain(bool wasLockingChainSend); - - STXChainBridge(); - - explicit STXChainBridge(SField const& name); - - STXChainBridge(STXChainBridge const& rhs) = default; - - STXChainBridge(STObject const& o); - - STXChainBridge( - AccountID const& srcChainDoor, - Issue const& srcChainIssue, - AccountID const& dstChainDoor, - Issue const& dstChainIssue); - - explicit STXChainBridge(json::Value const& v); - - explicit STXChainBridge(SField const& name, json::Value const& v); - - explicit STXChainBridge(SerialIter& sit, SField const& name); - - STXChainBridge& - operator=(STXChainBridge const& rhs) = default; - - [[nodiscard]] std::string - getText() const override; - - [[nodiscard]] STObject - toSTObject() const; - - [[nodiscard]] AccountID const& - lockingChainDoor() const; - - [[nodiscard]] Issue const& - lockingChainIssue() const; - - [[nodiscard]] AccountID const& - issuingChainDoor() const; - - [[nodiscard]] Issue const& - issuingChainIssue() const; - - [[nodiscard]] AccountID const& - door(ChainType ct) const; - - [[nodiscard]] Issue const& - issue(ChainType ct) const; - - [[nodiscard]] SerializedTypeID - getSType() const override; - - [[nodiscard]] json::Value getJson(JsonOptions) const override; - - void - add(Serializer& s) const override; - - [[nodiscard]] bool - isEquivalent(STBase const& t) const override; - - [[nodiscard]] bool - isDefault() const override; - - [[nodiscard]] value_type const& - value() const noexcept; - -private: - static std::unique_ptr - construct(SerialIter&, SField const& name); - - STBase* - copy(std::size_t n, void* buf) const override; - STBase* - move(std::size_t n, void* buf) override; - - friend bool - operator==(STXChainBridge const& lhs, STXChainBridge const& rhs); - - friend bool - operator<(STXChainBridge const& lhs, STXChainBridge const& rhs); -}; - -inline bool -operator==(STXChainBridge const& lhs, STXChainBridge const& rhs) -{ - return std::tie( - lhs.lockingChainDoor_, - lhs.lockingChainIssue_, - lhs.issuingChainDoor_, - lhs.issuingChainIssue_) == - std::tie( - rhs.lockingChainDoor_, - rhs.lockingChainIssue_, - rhs.issuingChainDoor_, - rhs.issuingChainIssue_); -} - -inline bool -operator<(STXChainBridge const& lhs, STXChainBridge const& rhs) -{ - return std::tie( - lhs.lockingChainDoor_, - lhs.lockingChainIssue_, - lhs.issuingChainDoor_, - lhs.issuingChainIssue_) < - std::tie( - rhs.lockingChainDoor_, - rhs.lockingChainIssue_, - rhs.issuingChainDoor_, - rhs.issuingChainIssue_); -} - -inline AccountID const& -STXChainBridge::lockingChainDoor() const -{ - return lockingChainDoor_.value(); -}; - -inline Issue const& -STXChainBridge::lockingChainIssue() const -{ - return lockingChainIssue_.value().get(); -}; - -inline AccountID const& -STXChainBridge::issuingChainDoor() const -{ - return issuingChainDoor_.value(); -}; - -inline Issue const& -STXChainBridge::issuingChainIssue() const -{ - return issuingChainIssue_.value().get(); -}; - -inline STXChainBridge::value_type const& -STXChainBridge::value() const noexcept -{ - return *this; -} - -inline AccountID const& -STXChainBridge::door(ChainType ct) const -{ - if (ct == ChainType::Locking) - return lockingChainDoor(); - return issuingChainDoor(); -} - -inline Issue const& -STXChainBridge::issue(ChainType ct) const -{ - if (ct == ChainType::Locking) - return lockingChainIssue(); - return issuingChainIssue(); -} - -inline STXChainBridge::ChainType -STXChainBridge::otherChain(ChainType ct) -{ - if (ct == ChainType::Locking) - return ChainType::Issuing; - return ChainType::Locking; -} - -inline STXChainBridge::ChainType -STXChainBridge::srcChain(bool wasLockingChainSend) -{ - if (wasLockingChainSend) - return ChainType::Locking; - return ChainType::Issuing; -} - -inline STXChainBridge::ChainType -STXChainBridge::dstChain(bool wasLockingChainSend) -{ - if (wasLockingChainSend) - return ChainType::Issuing; - return ChainType::Locking; -} - -} // namespace xrpl diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index 1d4f33a39d..79629465aa 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -181,10 +181,6 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal; TF_FLAG(tfClawTwoAssets, 0x00000001), \ MASK_ADJ(0)) \ \ - TRANSACTION(XChainModifyBridge, \ - TF_FLAG(tfClearAccountCreateAmount, 0x00010000), \ - MASK_ADJ(0)) \ - \ TRANSACTION(VaultCreate, \ TF_FLAG(tfVaultPrivate, lsfVaultPrivate) \ TF_FLAG(tfVaultShareNonTransferable, 0x00020000), \ diff --git a/include/xrpl/protocol/XChainAttestations.h b/include/xrpl/protocol/XChainAttestations.h deleted file mode 100644 index 8f1c7a4ce3..0000000000 --- a/include/xrpl/protocol/XChainAttestations.h +++ /dev/null @@ -1,471 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace xrpl { - -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 transferred on the sending chain - STAmount sendingAmount; - // Account on the destination chain that collects a share of the attestation - // reward - AccountID rewardAccount; - // Amount was transferred on the locking chain - bool wasLockingChainSend; - - explicit AttestationBase( - AccountID attestationSignerAccount, - PublicKey const& publicKey, - Buffer signature, - AccountID const& sendingAccount, - STAmount 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. - [[nodiscard]] 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 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 a, bool b, std::optional const& d) - : amount{std::move(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); - - [[nodiscard]] 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; - - [[nodiscard]] AttestationMatch - match(MatchFields const& rhs) const; - - friend bool - operator==( - XChainCreateAccountAttestation const& lhs, - XChainCreateAccountAttestation const& rhs); -}; - -// Attestations from witness servers for a particular claim ID 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 kMaxAttestations = 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; - - [[nodiscard]] AttCollection::const_iterator - begin() const; - - [[nodiscard]] AttCollection::const_iterator - end() const; - - AttCollection::iterator - begin(); - - AttCollection::iterator - end(); - - template - std::size_t - eraseIf(F&& f); - - [[nodiscard]] std::size_t - size() const; - - [[nodiscard]] bool - empty() const; - - [[nodiscard]] AttCollection const& - attestations() const; - - template - void - emplaceBack(T&& att); -}; - -template -[[nodiscard]] inline bool -operator==( - XChainAttestationsBase const& lhs, - XChainAttestationsBase const& rhs) -{ - return lhs.attestations() == rhs.attestations(); -} - -template -inline XChainAttestationsBase::AttCollection const& -XChainAttestationsBase::attestations() const -{ - return attestations_; -}; - -template -template -inline void -XChainAttestationsBase::emplaceBack(T&& att) -{ - attestations_.emplace_back(std::forward(att)); -}; - -template -template -inline std::size_t -XChainAttestationsBase::eraseIf(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 xrpl diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index bfe03a6303..21032cd8be 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -55,13 +55,13 @@ XRPL_FIX (ReducedOffersV2, Supported::Yes, VoteBehavior::DefaultNo XRPL_FEATURE(NFTokenMintOffer, Supported::Yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMv1_1, Supported::Yes, VoteBehavior::DefaultNo) XRPL_FIX (PreviousTxnID, Supported::Yes, VoteBehavior::DefaultNo) -XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::DefaultNo) +XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::Obsolete) XRPL_FIX (EmptyDID, Supported::Yes, VoteBehavior::DefaultNo) XRPL_FEATURE(PriceOracle, Supported::Yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMOverflowOffer, Supported::Yes, VoteBehavior::DefaultYes) XRPL_FIX (FillOrKill, Supported::Yes, VoteBehavior::DefaultNo) XRPL_FEATURE(DID, Supported::Yes, VoteBehavior::DefaultNo) -XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::Obsolete) XRPL_FEATURE(AMM, Supported::Yes, VoteBehavior::DefaultNo) XRPL_FEATURE(XRPFees, Supported::Yes, VoteBehavior::DefaultNo) XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYes) diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index 90810e06d2..a90fdcc4ec 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -206,23 +206,6 @@ LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, hashes, ({ {sfHashes, SoeRequired}, })) -/** The ledger object which lists details about sidechains. - - \sa keylet::bridge -*/ -LEDGER_ENTRY(ltBRIDGE, 0x0069, Bridge, bridge, ({ - {sfAccount, SoeRequired}, - {sfSignatureReward, SoeRequired}, - {sfMinAccountCreateAmount, SoeOptional}, - {sfXChainBridge, SoeRequired}, - {sfXChainClaimID, SoeRequired}, - {sfXChainAccountCreateCount, SoeRequired}, - {sfXChainAccountClaimCount, SoeRequired}, - {sfOwnerNode, SoeRequired}, - {sfPreviousTxnID, SoeRequired}, - {sfPreviousTxnLgrSeq, SoeRequired}, -})) - /** A ledger object which describes an offer on the DEX. \sa keylet::offer @@ -255,22 +238,6 @@ LEDGER_ENTRY_DUPLICATE(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, deposit_preaut {sfAuthorizeCredentials, SoeOptional}, })) -/** A claim id for a cross chain transaction. - - \sa keylet::xChainClaimID -*/ -LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_claim_id, ({ - {sfAccount, SoeRequired}, - {sfXChainBridge, SoeRequired}, - {sfXChainClaimID, SoeRequired}, - {sfOtherChainSource, SoeRequired}, - {sfXChainClaimAttestations, SoeRequired}, - {sfSignatureReward, SoeRequired}, - {sfOwnerNode, SoeRequired}, - {sfPreviousTxnID, SoeRequired}, - {sfPreviousTxnLgrSeq, SoeRequired}, -})) - /** A ledger object which describes a bidirectional trust line. @note Per Vinnie Falco this should be renamed to ltTRUST_LINE @@ -313,20 +280,6 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({ {sfPreviousTxnLgrSeq, SoeOptional}, })) -/** A claim id for a cross chain create account transaction. - - \sa keylet::xChainCreateAccountClaimID -*/ -LEDGER_ENTRY(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, 0x0074, XChainOwnedCreateAccountClaimID, xchain_owned_create_account_claim_id, ({ - {sfAccount, SoeRequired}, - {sfXChainBridge, SoeRequired}, - {sfXChainAccountCreateCount, SoeRequired}, - {sfXChainCreateAccountAttestations, SoeRequired}, - {sfOwnerNode, SoeRequired}, - {sfPreviousTxnID, SoeRequired}, - {sfPreviousTxnLgrSeq, SoeRequired}, -})) - /** A ledger object describing a single escrow. \sa keylet::escrow diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index 4ef76c8b75..f073e74be2 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -23,7 +23,7 @@ TYPED_SFIELD(sfAssetScale, UINT8, 5) TYPED_SFIELD(sfTickSize, UINT8, 16) TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17) TYPED_SFIELD(sfHookResult, UINT8, 18) -TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19) +// 19 unused TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20) // 16-bit integers (common) @@ -140,9 +140,7 @@ TYPED_SFIELD(sfHookOn, UINT64, 16) TYPED_SFIELD(sfHookInstructionCount, UINT64, 17) TYPED_SFIELD(sfHookReturnCode, UINT64, 18) TYPED_SFIELD(sfReferenceCount, UINT64, 19) -TYPED_SFIELD(sfXChainClaimID, UINT64, 20) -TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21) -TYPED_SFIELD(sfXChainAccountClaimCount, UINT64, 22) +// 20-22 unused TYPED_SFIELD(sfAssetPrice, UINT64, 23) TYPED_SFIELD(sfMaximumAmount, UINT64, 24, SField::kSmdBaseTen|SField::kSmdDefault) TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::kSmdBaseTen|SField::kSmdDefault) @@ -343,12 +341,7 @@ TYPED_SFIELD(sfDelegate, ACCOUNT, 12) // account (uncommon) TYPED_SFIELD(sfHookAccount, ACCOUNT, 16) -TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18) -TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19) -TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20) -TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21) -TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22) -TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23) +// 17-23 are unused TYPED_SFIELD(sfSubject, ACCOUNT, 24) TYPED_SFIELD(sfBorrower, ACCOUNT, 25) TYPED_SFIELD(sfCounterparty, ACCOUNT, 26) @@ -373,14 +366,10 @@ TYPED_SFIELD(sfBaseAsset, CURRENCY, 1) TYPED_SFIELD(sfQuoteAsset, CURRENCY, 2) // issue -TYPED_SFIELD(sfLockingChainIssue, ISSUE, 1) -TYPED_SFIELD(sfIssuingChainIssue, ISSUE, 2) +// 1 and 2 are unused TYPED_SFIELD(sfAsset, ISSUE, 3) TYPED_SFIELD(sfAsset2, ISSUE, 4) -// bridge -TYPED_SFIELD(sfXChainBridge, XCHAIN_BRIDGE, 1) - // inner object // OBJECT/1 is reserved for end of object UNTYPED_SFIELD(sfTransactionMetaData, OBJECT, 2) @@ -411,10 +400,7 @@ UNTYPED_SFIELD(sfHookGrant, OBJECT, 24) UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25) UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26) UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27) -UNTYPED_SFIELD(sfXChainClaimProofSig, OBJECT, 28) -UNTYPED_SFIELD(sfXChainCreateAccountProofSig, OBJECT, 29) -UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, OBJECT, 30) -UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, OBJECT, 31) +// 28 to 31 unused UNTYPED_SFIELD(sfPriceData, OBJECT, 32) UNTYPED_SFIELD(sfCredential, OBJECT, 33) UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34) @@ -445,9 +431,7 @@ UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17) UNTYPED_SFIELD(sfHookExecutions, ARRAY, 18) UNTYPED_SFIELD(sfHookParameters, ARRAY, 19) UNTYPED_SFIELD(sfHookGrants, ARRAY, 20) -UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21) -UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22) -// 23 unused +// 21-23 unused UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24) UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25) UNTYPED_SFIELD(sfAuthorizeCredentials, ARRAY, 26) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index e805596c00..ce8753aaca 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -509,120 +509,7 @@ TRANSACTION(ttAMM_DELETE, 40, AMMDelete, {sfAsset2, SoeRequired, SoeMptSupported}, })) -/** This transactions creates a crosschain sequence number */ -#if TRANSACTION_INCLUDE -# include -#endif -TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID, - Delegation::Delegable, - featureXChainBridge, - NoPriv, - ({ - {sfXChainBridge, SoeRequired}, - {sfSignatureReward, SoeRequired}, - {sfOtherChainSource, SoeRequired}, -})) - -/** This transactions initiates a crosschain transaction */ -TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, - Delegation::Delegable, - featureXChainBridge, - NoPriv, - ({ - {sfXChainBridge, SoeRequired}, - {sfXChainClaimID, SoeRequired}, - {sfAmount, SoeRequired}, - {sfOtherChainDestination, SoeOptional}, -})) - -/** This transaction completes a crosschain transaction */ -TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, - Delegation::Delegable, - featureXChainBridge, - NoPriv, - ({ - {sfXChainBridge, SoeRequired}, - {sfXChainClaimID, SoeRequired}, - {sfDestination, SoeRequired}, - {sfDestinationTag, SoeOptional}, - {sfAmount, SoeRequired}, -})) - -/** This transaction initiates a crosschain account create transaction */ -TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, - Delegation::Delegable, - featureXChainBridge, - NoPriv, - ({ - {sfXChainBridge, SoeRequired}, - {sfDestination, SoeRequired}, - {sfAmount, SoeRequired}, - {sfSignatureReward, SoeRequired}, -})) - -/** This transaction adds an attestation to a claim */ -TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, - Delegation::Delegable, - featureXChainBridge, - CreateAcct, - ({ - {sfXChainBridge, SoeRequired}, - - {sfAttestationSignerAccount, SoeRequired}, - {sfPublicKey, SoeRequired}, - {sfSignature, SoeRequired}, - {sfOtherChainSource, SoeRequired}, - {sfAmount, SoeRequired}, - {sfAttestationRewardAccount, SoeRequired}, - {sfWasLockingChainSend, SoeRequired}, - - {sfXChainClaimID, SoeRequired}, - {sfDestination, SoeOptional}, -})) - -/** This transaction adds an attestation to an account */ -TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, - XChainAddAccountCreateAttestation, - Delegation::Delegable, - featureXChainBridge, - CreateAcct, - ({ - {sfXChainBridge, SoeRequired}, - - {sfAttestationSignerAccount, SoeRequired}, - {sfPublicKey, SoeRequired}, - {sfSignature, SoeRequired}, - {sfOtherChainSource, SoeRequired}, - {sfAmount, SoeRequired}, - {sfAttestationRewardAccount, SoeRequired}, - {sfWasLockingChainSend, SoeRequired}, - - {sfXChainAccountCreateCount, SoeRequired}, - {sfDestination, SoeRequired}, - {sfSignatureReward, SoeRequired}, -})) - -/** This transaction modifies a sidechain */ -TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge, - Delegation::Delegable, - featureXChainBridge, - NoPriv, - ({ - {sfXChainBridge, SoeRequired}, - {sfSignatureReward, SoeOptional}, - {sfMinAccountCreateAmount, SoeOptional}, -})) - -/** This transactions creates a sidechain */ -TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge, - Delegation::Delegable, - featureXChainBridge, - NoPriv, - ({ - {sfXChainBridge, SoeRequired}, - {sfSignatureReward, SoeRequired}, - {sfMinAccountCreateAmount, SoeOptional}, -})) +// 41 to 48 are unused /** This transaction type creates or updates a DID */ #if TRANSACTION_INCLUDE diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index b20b71661a..01f12226aa 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -157,7 +157,6 @@ JSS(both); // in: Subscribe, Unsubscribe JSS(both_sides); // in: Subscribe, Unsubscribe JSS(branch); // out: server_info JSS(broadcast); // out: SubmitTransaction -JSS(bridge_account); // in: LedgerEntry JSS(build_path); // in: TransactionSign JSS(build_version); // out: NetworkOPs JSS(cancel_after); // out: AccountChannels diff --git a/include/xrpl/protocol_autogen/TransactionBuilderBase.h b/include/xrpl/protocol_autogen/TransactionBuilderBase.h index 14975b152e..8fa89f4667 100644 --- a/include/xrpl/protocol_autogen/TransactionBuilderBase.h +++ b/include/xrpl/protocol_autogen/TransactionBuilderBase.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/include/xrpl/protocol_autogen/ledger_entries/Bridge.h b/include/xrpl/protocol_autogen/ledger_entries/Bridge.h deleted file mode 100644 index 2c7479b243..0000000000 --- a/include/xrpl/protocol_autogen/ledger_entries/Bridge.h +++ /dev/null @@ -1,346 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::ledger_entries { - -class BridgeBuilder; - -/** - * @brief Ledger Entry: Bridge - * - * Type: ltBRIDGE (0x0069) - * RPC Name: bridge - * - * Immutable wrapper around SLE providing type-safe field access. - * Use BridgeBuilder to construct new ledger entries. - */ -class Bridge : public LedgerEntryBase -{ -public: - static constexpr LedgerEntryType entryType = ltBRIDGE; - - /** - * @brief Construct a Bridge ledger entry wrapper from an existing SLE object. - * @throws std::runtime_error if the ledger entry type doesn't match. - */ - explicit Bridge(SLE::const_pointer sle) - : LedgerEntryBase(std::move(sle)) - { - // Verify ledger entry type - if (sle_->getType() != entryType) - { - throw std::runtime_error("Invalid ledger entry type for Bridge"); - } - } - - // Ledger entry-specific field getters - - /** - * @brief Get sfAccount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getAccount() const - { - return this->sle_->at(sfAccount); - } - - /** - * @brief Get sfSignatureReward (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getSignatureReward() const - { - return this->sle_->at(sfSignatureReward); - } - - /** - * @brief Get sfMinAccountCreateAmount (SoeOptional) - * @return The field value, or std::nullopt if not present. - */ - [[nodiscard]] - protocol_autogen::Optional - getMinAccountCreateAmount() const - { - if (hasMinAccountCreateAmount()) - return this->sle_->at(sfMinAccountCreateAmount); - return std::nullopt; - } - - /** - * @brief Check if sfMinAccountCreateAmount is present. - * @return True if the field is present, false otherwise. - */ - [[nodiscard]] - bool - hasMinAccountCreateAmount() const - { - return this->sle_->isFieldPresent(sfMinAccountCreateAmount); - } - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->sle_->at(sfXChainBridge); - } - - /** - * @brief Get sfXChainClaimID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainClaimID() const - { - return this->sle_->at(sfXChainClaimID); - } - - /** - * @brief Get sfXChainAccountCreateCount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainAccountCreateCount() const - { - return this->sle_->at(sfXChainAccountCreateCount); - } - - /** - * @brief Get sfXChainAccountClaimCount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainAccountClaimCount() const - { - return this->sle_->at(sfXChainAccountClaimCount); - } - - /** - * @brief Get sfOwnerNode (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getOwnerNode() const - { - return this->sle_->at(sfOwnerNode); - } - - /** - * @brief Get sfPreviousTxnID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT256::type::value_type - getPreviousTxnID() const - { - return this->sle_->at(sfPreviousTxnID); - } - - /** - * @brief Get sfPreviousTxnLgrSeq (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT32::type::value_type - getPreviousTxnLgrSeq() const - { - return this->sle_->at(sfPreviousTxnLgrSeq); - } -}; - -/** - * @brief Builder for Bridge ledger entries. - * - * Provides a fluent interface for constructing ledger entries with method chaining. - * Uses STObject internally for flexible ledger entry construction. - * Inherits common field setters from LedgerEntryBuilderBase. - */ -class BridgeBuilder : public LedgerEntryBuilderBase -{ -public: - /** - * @brief Construct a new BridgeBuilder with required fields. - * @param account The sfAccount field value. - * @param signatureReward The sfSignatureReward field value. - * @param xChainBridge The sfXChainBridge field value. - * @param xChainClaimID The sfXChainClaimID field value. - * @param xChainAccountCreateCount The sfXChainAccountCreateCount field value. - * @param xChainAccountClaimCount The sfXChainAccountClaimCount field value. - * @param ownerNode The sfOwnerNode field value. - * @param previousTxnID The sfPreviousTxnID field value. - * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. - */ - BridgeBuilder(std::decay_t const& account,std::decay_t const& signatureReward,std::decay_t const& xChainBridge,std::decay_t const& xChainClaimID,std::decay_t const& xChainAccountCreateCount,std::decay_t const& xChainAccountClaimCount,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) - : LedgerEntryBuilderBase(ltBRIDGE) - { - setAccount(account); - setSignatureReward(signatureReward); - setXChainBridge(xChainBridge); - setXChainClaimID(xChainClaimID); - setXChainAccountCreateCount(xChainAccountCreateCount); - setXChainAccountClaimCount(xChainAccountClaimCount); - setOwnerNode(ownerNode); - setPreviousTxnID(previousTxnID); - setPreviousTxnLgrSeq(previousTxnLgrSeq); - } - - /** - * @brief Construct a BridgeBuilder from an existing SLE object. - * @param sle The existing ledger entry to copy from. - * @throws std::runtime_error if the ledger entry type doesn't match. - */ - BridgeBuilder(SLE::const_pointer sle) - { - if (sle->at(sfLedgerEntryType) != ltBRIDGE) - { - throw std::runtime_error("Invalid ledger entry type for Bridge"); - } - object_ = *sle; - } - - /** @brief Ledger entry-specific field setters */ - - /** - * @brief Set sfAccount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setAccount(std::decay_t const& value) - { - object_[sfAccount] = value; - return *this; - } - - /** - * @brief Set sfSignatureReward (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setSignatureReward(std::decay_t const& value) - { - object_[sfSignatureReward] = value; - return *this; - } - - /** - * @brief Set sfMinAccountCreateAmount (SoeOptional) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setMinAccountCreateAmount(std::decay_t const& value) - { - object_[sfMinAccountCreateAmount] = value; - return *this; - } - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfXChainClaimID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setXChainClaimID(std::decay_t const& value) - { - object_[sfXChainClaimID] = value; - return *this; - } - - /** - * @brief Set sfXChainAccountCreateCount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setXChainAccountCreateCount(std::decay_t const& value) - { - object_[sfXChainAccountCreateCount] = value; - return *this; - } - - /** - * @brief Set sfXChainAccountClaimCount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setXChainAccountClaimCount(std::decay_t const& value) - { - object_[sfXChainAccountClaimCount] = value; - return *this; - } - - /** - * @brief Set sfOwnerNode (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setOwnerNode(std::decay_t const& value) - { - object_[sfOwnerNode] = value; - return *this; - } - - /** - * @brief Set sfPreviousTxnID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setPreviousTxnID(std::decay_t const& value) - { - object_[sfPreviousTxnID] = value; - return *this; - } - - /** - * @brief Set sfPreviousTxnLgrSeq (SoeRequired) - * @return Reference to this builder for method chaining. - */ - BridgeBuilder& - setPreviousTxnLgrSeq(std::decay_t const& value) - { - object_[sfPreviousTxnLgrSeq] = value; - return *this; - } - - /** - * @brief Build and return the completed Bridge wrapper. - * @param index The ledger entry index. - * @return The constructed ledger entry wrapper. - */ - Bridge - build(uint256 const& index) - { - return Bridge{std::make_shared(std::move(object_), index)}; - } -}; - -} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedClaimID.h b/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedClaimID.h deleted file mode 100644 index 3f8058a4a1..0000000000 --- a/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedClaimID.h +++ /dev/null @@ -1,312 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::ledger_entries { - -class XChainOwnedClaimIDBuilder; - -/** - * @brief Ledger Entry: XChainOwnedClaimID - * - * Type: ltXCHAIN_OWNED_CLAIM_ID (0x0071) - * RPC Name: xchain_owned_claim_id - * - * Immutable wrapper around SLE providing type-safe field access. - * Use XChainOwnedClaimIDBuilder to construct new ledger entries. - */ -class XChainOwnedClaimID : public LedgerEntryBase -{ -public: - static constexpr LedgerEntryType entryType = ltXCHAIN_OWNED_CLAIM_ID; - - /** - * @brief Construct a XChainOwnedClaimID ledger entry wrapper from an existing SLE object. - * @throws std::runtime_error if the ledger entry type doesn't match. - */ - explicit XChainOwnedClaimID(SLE::const_pointer sle) - : LedgerEntryBase(std::move(sle)) - { - // Verify ledger entry type - if (sle_->getType() != entryType) - { - throw std::runtime_error("Invalid ledger entry type for XChainOwnedClaimID"); - } - } - - // Ledger entry-specific field getters - - /** - * @brief Get sfAccount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getAccount() const - { - return this->sle_->at(sfAccount); - } - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->sle_->at(sfXChainBridge); - } - - /** - * @brief Get sfXChainClaimID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainClaimID() const - { - return this->sle_->at(sfXChainClaimID); - } - - /** - * @brief Get sfOtherChainSource (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getOtherChainSource() const - { - return this->sle_->at(sfOtherChainSource); - } - - /** - * @brief Get sfXChainClaimAttestations (SoeRequired) - * @note This is an untyped field (unknown). - * @return The field value. - */ - [[nodiscard]] - STArray const& - getXChainClaimAttestations() const - { - return this->sle_->getFieldArray(sfXChainClaimAttestations); - } - - /** - * @brief Get sfSignatureReward (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getSignatureReward() const - { - return this->sle_->at(sfSignatureReward); - } - - /** - * @brief Get sfOwnerNode (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getOwnerNode() const - { - return this->sle_->at(sfOwnerNode); - } - - /** - * @brief Get sfPreviousTxnID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT256::type::value_type - getPreviousTxnID() const - { - return this->sle_->at(sfPreviousTxnID); - } - - /** - * @brief Get sfPreviousTxnLgrSeq (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT32::type::value_type - getPreviousTxnLgrSeq() const - { - return this->sle_->at(sfPreviousTxnLgrSeq); - } -}; - -/** - * @brief Builder for XChainOwnedClaimID ledger entries. - * - * Provides a fluent interface for constructing ledger entries with method chaining. - * Uses STObject internally for flexible ledger entry construction. - * Inherits common field setters from LedgerEntryBuilderBase. - */ -class XChainOwnedClaimIDBuilder : public LedgerEntryBuilderBase -{ -public: - /** - * @brief Construct a new XChainOwnedClaimIDBuilder with required fields. - * @param account The sfAccount field value. - * @param xChainBridge The sfXChainBridge field value. - * @param xChainClaimID The sfXChainClaimID field value. - * @param otherChainSource The sfOtherChainSource field value. - * @param xChainClaimAttestations The sfXChainClaimAttestations field value. - * @param signatureReward The sfSignatureReward field value. - * @param ownerNode The sfOwnerNode field value. - * @param previousTxnID The sfPreviousTxnID field value. - * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. - */ - XChainOwnedClaimIDBuilder(std::decay_t const& account,std::decay_t const& xChainBridge,std::decay_t const& xChainClaimID,std::decay_t const& otherChainSource,STArray const& xChainClaimAttestations,std::decay_t const& signatureReward,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) - : LedgerEntryBuilderBase(ltXCHAIN_OWNED_CLAIM_ID) - { - setAccount(account); - setXChainBridge(xChainBridge); - setXChainClaimID(xChainClaimID); - setOtherChainSource(otherChainSource); - setXChainClaimAttestations(xChainClaimAttestations); - setSignatureReward(signatureReward); - setOwnerNode(ownerNode); - setPreviousTxnID(previousTxnID); - setPreviousTxnLgrSeq(previousTxnLgrSeq); - } - - /** - * @brief Construct a XChainOwnedClaimIDBuilder from an existing SLE object. - * @param sle The existing ledger entry to copy from. - * @throws std::runtime_error if the ledger entry type doesn't match. - */ - XChainOwnedClaimIDBuilder(SLE::const_pointer sle) - { - if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CLAIM_ID) - { - throw std::runtime_error("Invalid ledger entry type for XChainOwnedClaimID"); - } - object_ = *sle; - } - - /** @brief Ledger entry-specific field setters */ - - /** - * @brief Set sfAccount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setAccount(std::decay_t const& value) - { - object_[sfAccount] = value; - return *this; - } - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfXChainClaimID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setXChainClaimID(std::decay_t const& value) - { - object_[sfXChainClaimID] = value; - return *this; - } - - /** - * @brief Set sfOtherChainSource (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setOtherChainSource(std::decay_t const& value) - { - object_[sfOtherChainSource] = value; - return *this; - } - - /** - * @brief Set sfXChainClaimAttestations (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setXChainClaimAttestations(STArray const& value) - { - object_.setFieldArray(sfXChainClaimAttestations, value); - return *this; - } - - /** - * @brief Set sfSignatureReward (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setSignatureReward(std::decay_t const& value) - { - object_[sfSignatureReward] = value; - return *this; - } - - /** - * @brief Set sfOwnerNode (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setOwnerNode(std::decay_t const& value) - { - object_[sfOwnerNode] = value; - return *this; - } - - /** - * @brief Set sfPreviousTxnID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setPreviousTxnID(std::decay_t const& value) - { - object_[sfPreviousTxnID] = value; - return *this; - } - - /** - * @brief Set sfPreviousTxnLgrSeq (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedClaimIDBuilder& - setPreviousTxnLgrSeq(std::decay_t const& value) - { - object_[sfPreviousTxnLgrSeq] = value; - return *this; - } - - /** - * @brief Build and return the completed XChainOwnedClaimID wrapper. - * @param index The ledger entry index. - * @return The constructed ledger entry wrapper. - */ - XChainOwnedClaimID - build(uint256 const& index) - { - return XChainOwnedClaimID{std::make_shared(std::move(object_), index)}; - } -}; - -} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimID.h b/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimID.h deleted file mode 100644 index e24009a4b7..0000000000 --- a/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimID.h +++ /dev/null @@ -1,264 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::ledger_entries { - -class XChainOwnedCreateAccountClaimIDBuilder; - -/** - * @brief Ledger Entry: XChainOwnedCreateAccountClaimID - * - * Type: ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID (0x0074) - * RPC Name: xchain_owned_create_account_claim_id - * - * Immutable wrapper around SLE providing type-safe field access. - * Use XChainOwnedCreateAccountClaimIDBuilder to construct new ledger entries. - */ -class XChainOwnedCreateAccountClaimID : public LedgerEntryBase -{ -public: - static constexpr LedgerEntryType entryType = ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID; - - /** - * @brief Construct a XChainOwnedCreateAccountClaimID ledger entry wrapper from an existing SLE object. - * @throws std::runtime_error if the ledger entry type doesn't match. - */ - explicit XChainOwnedCreateAccountClaimID(SLE::const_pointer sle) - : LedgerEntryBase(std::move(sle)) - { - // Verify ledger entry type - if (sle_->getType() != entryType) - { - throw std::runtime_error("Invalid ledger entry type for XChainOwnedCreateAccountClaimID"); - } - } - - // Ledger entry-specific field getters - - /** - * @brief Get sfAccount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getAccount() const - { - return this->sle_->at(sfAccount); - } - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->sle_->at(sfXChainBridge); - } - - /** - * @brief Get sfXChainAccountCreateCount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainAccountCreateCount() const - { - return this->sle_->at(sfXChainAccountCreateCount); - } - - /** - * @brief Get sfXChainCreateAccountAttestations (SoeRequired) - * @note This is an untyped field (unknown). - * @return The field value. - */ - [[nodiscard]] - STArray const& - getXChainCreateAccountAttestations() const - { - return this->sle_->getFieldArray(sfXChainCreateAccountAttestations); - } - - /** - * @brief Get sfOwnerNode (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getOwnerNode() const - { - return this->sle_->at(sfOwnerNode); - } - - /** - * @brief Get sfPreviousTxnID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT256::type::value_type - getPreviousTxnID() const - { - return this->sle_->at(sfPreviousTxnID); - } - - /** - * @brief Get sfPreviousTxnLgrSeq (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT32::type::value_type - getPreviousTxnLgrSeq() const - { - return this->sle_->at(sfPreviousTxnLgrSeq); - } -}; - -/** - * @brief Builder for XChainOwnedCreateAccountClaimID ledger entries. - * - * Provides a fluent interface for constructing ledger entries with method chaining. - * Uses STObject internally for flexible ledger entry construction. - * Inherits common field setters from LedgerEntryBuilderBase. - */ -class XChainOwnedCreateAccountClaimIDBuilder : public LedgerEntryBuilderBase -{ -public: - /** - * @brief Construct a new XChainOwnedCreateAccountClaimIDBuilder with required fields. - * @param account The sfAccount field value. - * @param xChainBridge The sfXChainBridge field value. - * @param xChainAccountCreateCount The sfXChainAccountCreateCount field value. - * @param xChainCreateAccountAttestations The sfXChainCreateAccountAttestations field value. - * @param ownerNode The sfOwnerNode field value. - * @param previousTxnID The sfPreviousTxnID field value. - * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. - */ - XChainOwnedCreateAccountClaimIDBuilder(std::decay_t const& account,std::decay_t const& xChainBridge,std::decay_t const& xChainAccountCreateCount,STArray const& xChainCreateAccountAttestations,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) - : LedgerEntryBuilderBase(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID) - { - setAccount(account); - setXChainBridge(xChainBridge); - setXChainAccountCreateCount(xChainAccountCreateCount); - setXChainCreateAccountAttestations(xChainCreateAccountAttestations); - setOwnerNode(ownerNode); - setPreviousTxnID(previousTxnID); - setPreviousTxnLgrSeq(previousTxnLgrSeq); - } - - /** - * @brief Construct a XChainOwnedCreateAccountClaimIDBuilder from an existing SLE object. - * @param sle The existing ledger entry to copy from. - * @throws std::runtime_error if the ledger entry type doesn't match. - */ - XChainOwnedCreateAccountClaimIDBuilder(SLE::const_pointer sle) - { - if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID) - { - throw std::runtime_error("Invalid ledger entry type for XChainOwnedCreateAccountClaimID"); - } - object_ = *sle; - } - - /** @brief Ledger entry-specific field setters */ - - /** - * @brief Set sfAccount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedCreateAccountClaimIDBuilder& - setAccount(std::decay_t const& value) - { - object_[sfAccount] = value; - return *this; - } - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedCreateAccountClaimIDBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfXChainAccountCreateCount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedCreateAccountClaimIDBuilder& - setXChainAccountCreateCount(std::decay_t const& value) - { - object_[sfXChainAccountCreateCount] = value; - return *this; - } - - /** - * @brief Set sfXChainCreateAccountAttestations (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedCreateAccountClaimIDBuilder& - setXChainCreateAccountAttestations(STArray const& value) - { - object_.setFieldArray(sfXChainCreateAccountAttestations, value); - return *this; - } - - /** - * @brief Set sfOwnerNode (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedCreateAccountClaimIDBuilder& - setOwnerNode(std::decay_t const& value) - { - object_[sfOwnerNode] = value; - return *this; - } - - /** - * @brief Set sfPreviousTxnID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedCreateAccountClaimIDBuilder& - setPreviousTxnID(std::decay_t const& value) - { - object_[sfPreviousTxnID] = value; - return *this; - } - - /** - * @brief Set sfPreviousTxnLgrSeq (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainOwnedCreateAccountClaimIDBuilder& - setPreviousTxnLgrSeq(std::decay_t const& value) - { - object_[sfPreviousTxnLgrSeq] = value; - return *this; - } - - /** - * @brief Build and return the completed XChainOwnedCreateAccountClaimID wrapper. - * @param index The ledger entry index. - * @return The constructed ledger entry wrapper. - */ - XChainOwnedCreateAccountClaimID - build(uint256 const& index) - { - return XChainOwnedCreateAccountClaimID{std::make_shared(std::move(object_), index)}; - } -}; - -} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/transactions/XChainAccountCreateCommit.h b/include/xrpl/protocol_autogen/transactions/XChainAccountCreateCommit.h deleted file mode 100644 index 36d8170af1..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainAccountCreateCommit.h +++ /dev/null @@ -1,201 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainAccountCreateCommitBuilder; - -/** - * @brief Transaction: XChainAccountCreateCommit - * - * Type: ttXCHAIN_ACCOUNT_CREATE_COMMIT (44) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: NoPriv - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainAccountCreateCommitBuilder to construct new transactions. - */ -class XChainAccountCreateCommit : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_ACCOUNT_CREATE_COMMIT; - - /** - * @brief Construct a XChainAccountCreateCommit transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainAccountCreateCommit(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainAccountCreateCommit"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfDestination (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getDestination() const - { - return this->tx_->at(sfDestination); - } - - /** - * @brief Get sfAmount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getAmount() const - { - return this->tx_->at(sfAmount); - } - - /** - * @brief Get sfSignatureReward (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getSignatureReward() const - { - return this->tx_->at(sfSignatureReward); - } -}; - -/** - * @brief Builder for XChainAccountCreateCommit transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainAccountCreateCommitBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainAccountCreateCommitBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param destination The sfDestination field value. - * @param amount The sfAmount field value. - * @param signatureReward The sfSignatureReward field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainAccountCreateCommitBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::decay_t const& destination, std::decay_t const& amount, std::decay_t const& signatureReward, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_ACCOUNT_CREATE_COMMIT, account, sequence, fee) - { - setXChainBridge(xChainBridge); - setDestination(destination); - setAmount(amount); - setSignatureReward(signatureReward); - } - - /** - * @brief Construct a XChainAccountCreateCommitBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainAccountCreateCommitBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_ACCOUNT_CREATE_COMMIT) - { - throw std::runtime_error("Invalid transaction type for XChainAccountCreateCommitBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAccountCreateCommitBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfDestination (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAccountCreateCommitBuilder& - setDestination(std::decay_t const& value) - { - object_[sfDestination] = value; - return *this; - } - - /** - * @brief Set sfAmount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAccountCreateCommitBuilder& - setAmount(std::decay_t const& value) - { - object_[sfAmount] = value; - return *this; - } - - /** - * @brief Set sfSignatureReward (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAccountCreateCommitBuilder& - setSignatureReward(std::decay_t const& value) - { - object_[sfSignatureReward] = value; - return *this; - } - - /** - * @brief Build and return the XChainAccountCreateCommit wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainAccountCreateCommit - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainAccountCreateCommit{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestation.h b/include/xrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestation.h deleted file mode 100644 index a04eec1505..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestation.h +++ /dev/null @@ -1,369 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainAddAccountCreateAttestationBuilder; - -/** - * @brief Transaction: XChainAddAccountCreateAttestation - * - * Type: ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION (46) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: CreateAcct - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainAddAccountCreateAttestationBuilder to construct new transactions. - */ -class XChainAddAccountCreateAttestation : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION; - - /** - * @brief Construct a XChainAddAccountCreateAttestation transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainAddAccountCreateAttestation(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainAddAccountCreateAttestation"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfAttestationSignerAccount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getAttestationSignerAccount() const - { - return this->tx_->at(sfAttestationSignerAccount); - } - - /** - * @brief Get sfPublicKey (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_VL::type::value_type - getPublicKey() const - { - return this->tx_->at(sfPublicKey); - } - - /** - * @brief Get sfSignature (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_VL::type::value_type - getSignature() const - { - return this->tx_->at(sfSignature); - } - - /** - * @brief Get sfOtherChainSource (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getOtherChainSource() const - { - return this->tx_->at(sfOtherChainSource); - } - - /** - * @brief Get sfAmount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getAmount() const - { - return this->tx_->at(sfAmount); - } - - /** - * @brief Get sfAttestationRewardAccount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getAttestationRewardAccount() const - { - return this->tx_->at(sfAttestationRewardAccount); - } - - /** - * @brief Get sfWasLockingChainSend (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT8::type::value_type - getWasLockingChainSend() const - { - return this->tx_->at(sfWasLockingChainSend); - } - - /** - * @brief Get sfXChainAccountCreateCount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainAccountCreateCount() const - { - return this->tx_->at(sfXChainAccountCreateCount); - } - - /** - * @brief Get sfDestination (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getDestination() const - { - return this->tx_->at(sfDestination); - } - - /** - * @brief Get sfSignatureReward (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getSignatureReward() const - { - return this->tx_->at(sfSignatureReward); - } -}; - -/** - * @brief Builder for XChainAddAccountCreateAttestation transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainAddAccountCreateAttestationBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainAddAccountCreateAttestationBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param attestationSignerAccount The sfAttestationSignerAccount field value. - * @param publicKey The sfPublicKey field value. - * @param signature The sfSignature field value. - * @param otherChainSource The sfOtherChainSource field value. - * @param amount The sfAmount field value. - * @param attestationRewardAccount The sfAttestationRewardAccount field value. - * @param wasLockingChainSend The sfWasLockingChainSend field value. - * @param xChainAccountCreateCount The sfXChainAccountCreateCount field value. - * @param destination The sfDestination field value. - * @param signatureReward The sfSignatureReward field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainAddAccountCreateAttestationBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::decay_t const& attestationSignerAccount, std::decay_t const& publicKey, std::decay_t const& signature, std::decay_t const& otherChainSource, std::decay_t const& amount, std::decay_t const& attestationRewardAccount, std::decay_t const& wasLockingChainSend, std::decay_t const& xChainAccountCreateCount, std::decay_t const& destination, std::decay_t const& signatureReward, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, account, sequence, fee) - { - setXChainBridge(xChainBridge); - setAttestationSignerAccount(attestationSignerAccount); - setPublicKey(publicKey); - setSignature(signature); - setOtherChainSource(otherChainSource); - setAmount(amount); - setAttestationRewardAccount(attestationRewardAccount); - setWasLockingChainSend(wasLockingChainSend); - setXChainAccountCreateCount(xChainAccountCreateCount); - setDestination(destination); - setSignatureReward(signatureReward); - } - - /** - * @brief Construct a XChainAddAccountCreateAttestationBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainAddAccountCreateAttestationBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION) - { - throw std::runtime_error("Invalid transaction type for XChainAddAccountCreateAttestationBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfAttestationSignerAccount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setAttestationSignerAccount(std::decay_t const& value) - { - object_[sfAttestationSignerAccount] = value; - return *this; - } - - /** - * @brief Set sfPublicKey (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setPublicKey(std::decay_t const& value) - { - object_[sfPublicKey] = value; - return *this; - } - - /** - * @brief Set sfSignature (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setSignature(std::decay_t const& value) - { - object_[sfSignature] = value; - return *this; - } - - /** - * @brief Set sfOtherChainSource (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setOtherChainSource(std::decay_t const& value) - { - object_[sfOtherChainSource] = value; - return *this; - } - - /** - * @brief Set sfAmount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setAmount(std::decay_t const& value) - { - object_[sfAmount] = value; - return *this; - } - - /** - * @brief Set sfAttestationRewardAccount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setAttestationRewardAccount(std::decay_t const& value) - { - object_[sfAttestationRewardAccount] = value; - return *this; - } - - /** - * @brief Set sfWasLockingChainSend (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setWasLockingChainSend(std::decay_t const& value) - { - object_[sfWasLockingChainSend] = value; - return *this; - } - - /** - * @brief Set sfXChainAccountCreateCount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setXChainAccountCreateCount(std::decay_t const& value) - { - object_[sfXChainAccountCreateCount] = value; - return *this; - } - - /** - * @brief Set sfDestination (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setDestination(std::decay_t const& value) - { - object_[sfDestination] = value; - return *this; - } - - /** - * @brief Set sfSignatureReward (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddAccountCreateAttestationBuilder& - setSignatureReward(std::decay_t const& value) - { - object_[sfSignatureReward] = value; - return *this; - } - - /** - * @brief Build and return the XChainAddAccountCreateAttestation wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainAddAccountCreateAttestation - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainAddAccountCreateAttestation{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainAddClaimAttestation.h b/include/xrpl/protocol_autogen/transactions/XChainAddClaimAttestation.h deleted file mode 100644 index 1896f11681..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainAddClaimAttestation.h +++ /dev/null @@ -1,358 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainAddClaimAttestationBuilder; - -/** - * @brief Transaction: XChainAddClaimAttestation - * - * Type: ttXCHAIN_ADD_CLAIM_ATTESTATION (45) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: CreateAcct - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainAddClaimAttestationBuilder to construct new transactions. - */ -class XChainAddClaimAttestation : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_ADD_CLAIM_ATTESTATION; - - /** - * @brief Construct a XChainAddClaimAttestation transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainAddClaimAttestation(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainAddClaimAttestation"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfAttestationSignerAccount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getAttestationSignerAccount() const - { - return this->tx_->at(sfAttestationSignerAccount); - } - - /** - * @brief Get sfPublicKey (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_VL::type::value_type - getPublicKey() const - { - return this->tx_->at(sfPublicKey); - } - - /** - * @brief Get sfSignature (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_VL::type::value_type - getSignature() const - { - return this->tx_->at(sfSignature); - } - - /** - * @brief Get sfOtherChainSource (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getOtherChainSource() const - { - return this->tx_->at(sfOtherChainSource); - } - - /** - * @brief Get sfAmount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getAmount() const - { - return this->tx_->at(sfAmount); - } - - /** - * @brief Get sfAttestationRewardAccount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getAttestationRewardAccount() const - { - return this->tx_->at(sfAttestationRewardAccount); - } - - /** - * @brief Get sfWasLockingChainSend (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT8::type::value_type - getWasLockingChainSend() const - { - return this->tx_->at(sfWasLockingChainSend); - } - - /** - * @brief Get sfXChainClaimID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainClaimID() const - { - return this->tx_->at(sfXChainClaimID); - } - - /** - * @brief Get sfDestination (SoeOptional) - * @return The field value, or std::nullopt if not present. - */ - [[nodiscard]] - protocol_autogen::Optional - getDestination() const - { - if (hasDestination()) - { - return this->tx_->at(sfDestination); - } - return std::nullopt; - } - - /** - * @brief Check if sfDestination is present. - * @return True if the field is present, false otherwise. - */ - [[nodiscard]] - bool - hasDestination() const - { - return this->tx_->isFieldPresent(sfDestination); - } -}; - -/** - * @brief Builder for XChainAddClaimAttestation transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainAddClaimAttestationBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainAddClaimAttestationBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param attestationSignerAccount The sfAttestationSignerAccount field value. - * @param publicKey The sfPublicKey field value. - * @param signature The sfSignature field value. - * @param otherChainSource The sfOtherChainSource field value. - * @param amount The sfAmount field value. - * @param attestationRewardAccount The sfAttestationRewardAccount field value. - * @param wasLockingChainSend The sfWasLockingChainSend field value. - * @param xChainClaimID The sfXChainClaimID field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainAddClaimAttestationBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::decay_t const& attestationSignerAccount, std::decay_t const& publicKey, std::decay_t const& signature, std::decay_t const& otherChainSource, std::decay_t const& amount, std::decay_t const& attestationRewardAccount, std::decay_t const& wasLockingChainSend, std::decay_t const& xChainClaimID, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_ADD_CLAIM_ATTESTATION, account, sequence, fee) - { - setXChainBridge(xChainBridge); - setAttestationSignerAccount(attestationSignerAccount); - setPublicKey(publicKey); - setSignature(signature); - setOtherChainSource(otherChainSource); - setAmount(amount); - setAttestationRewardAccount(attestationRewardAccount); - setWasLockingChainSend(wasLockingChainSend); - setXChainClaimID(xChainClaimID); - } - - /** - * @brief Construct a XChainAddClaimAttestationBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainAddClaimAttestationBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_ADD_CLAIM_ATTESTATION) - { - throw std::runtime_error("Invalid transaction type for XChainAddClaimAttestationBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfAttestationSignerAccount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setAttestationSignerAccount(std::decay_t const& value) - { - object_[sfAttestationSignerAccount] = value; - return *this; - } - - /** - * @brief Set sfPublicKey (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setPublicKey(std::decay_t const& value) - { - object_[sfPublicKey] = value; - return *this; - } - - /** - * @brief Set sfSignature (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setSignature(std::decay_t const& value) - { - object_[sfSignature] = value; - return *this; - } - - /** - * @brief Set sfOtherChainSource (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setOtherChainSource(std::decay_t const& value) - { - object_[sfOtherChainSource] = value; - return *this; - } - - /** - * @brief Set sfAmount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setAmount(std::decay_t const& value) - { - object_[sfAmount] = value; - return *this; - } - - /** - * @brief Set sfAttestationRewardAccount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setAttestationRewardAccount(std::decay_t const& value) - { - object_[sfAttestationRewardAccount] = value; - return *this; - } - - /** - * @brief Set sfWasLockingChainSend (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setWasLockingChainSend(std::decay_t const& value) - { - object_[sfWasLockingChainSend] = value; - return *this; - } - - /** - * @brief Set sfXChainClaimID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setXChainClaimID(std::decay_t const& value) - { - object_[sfXChainClaimID] = value; - return *this; - } - - /** - * @brief Set sfDestination (SoeOptional) - * @return Reference to this builder for method chaining. - */ - XChainAddClaimAttestationBuilder& - setDestination(std::decay_t const& value) - { - object_[sfDestination] = value; - return *this; - } - - /** - * @brief Build and return the XChainAddClaimAttestation wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainAddClaimAttestation - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainAddClaimAttestation{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainClaim.h b/include/xrpl/protocol_autogen/transactions/XChainClaim.h deleted file mode 100644 index f5b680049e..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainClaim.h +++ /dev/null @@ -1,238 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainClaimBuilder; - -/** - * @brief Transaction: XChainClaim - * - * Type: ttXCHAIN_CLAIM (43) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: NoPriv - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainClaimBuilder to construct new transactions. - */ -class XChainClaim : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_CLAIM; - - /** - * @brief Construct a XChainClaim transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainClaim(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainClaim"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfXChainClaimID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainClaimID() const - { - return this->tx_->at(sfXChainClaimID); - } - - /** - * @brief Get sfDestination (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getDestination() const - { - return this->tx_->at(sfDestination); - } - - /** - * @brief Get sfDestinationTag (SoeOptional) - * @return The field value, or std::nullopt if not present. - */ - [[nodiscard]] - protocol_autogen::Optional - getDestinationTag() const - { - if (hasDestinationTag()) - { - return this->tx_->at(sfDestinationTag); - } - return std::nullopt; - } - - /** - * @brief Check if sfDestinationTag is present. - * @return True if the field is present, false otherwise. - */ - [[nodiscard]] - bool - hasDestinationTag() const - { - return this->tx_->isFieldPresent(sfDestinationTag); - } - - /** - * @brief Get sfAmount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getAmount() const - { - return this->tx_->at(sfAmount); - } -}; - -/** - * @brief Builder for XChainClaim transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainClaimBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainClaimBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param xChainClaimID The sfXChainClaimID field value. - * @param destination The sfDestination field value. - * @param amount The sfAmount field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainClaimBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::decay_t const& xChainClaimID, std::decay_t const& destination, std::decay_t const& amount, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_CLAIM, account, sequence, fee) - { - setXChainBridge(xChainBridge); - setXChainClaimID(xChainClaimID); - setDestination(destination); - setAmount(amount); - } - - /** - * @brief Construct a XChainClaimBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainClaimBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_CLAIM) - { - throw std::runtime_error("Invalid transaction type for XChainClaimBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainClaimBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfXChainClaimID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainClaimBuilder& - setXChainClaimID(std::decay_t const& value) - { - object_[sfXChainClaimID] = value; - return *this; - } - - /** - * @brief Set sfDestination (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainClaimBuilder& - setDestination(std::decay_t const& value) - { - object_[sfDestination] = value; - return *this; - } - - /** - * @brief Set sfDestinationTag (SoeOptional) - * @return Reference to this builder for method chaining. - */ - XChainClaimBuilder& - setDestinationTag(std::decay_t const& value) - { - object_[sfDestinationTag] = value; - return *this; - } - - /** - * @brief Set sfAmount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainClaimBuilder& - setAmount(std::decay_t const& value) - { - object_[sfAmount] = value; - return *this; - } - - /** - * @brief Build and return the XChainClaim wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainClaim - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainClaim{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainCommit.h b/include/xrpl/protocol_autogen/transactions/XChainCommit.h deleted file mode 100644 index a9ce7d1d08..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainCommit.h +++ /dev/null @@ -1,214 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainCommitBuilder; - -/** - * @brief Transaction: XChainCommit - * - * Type: ttXCHAIN_COMMIT (42) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: NoPriv - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainCommitBuilder to construct new transactions. - */ -class XChainCommit : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_COMMIT; - - /** - * @brief Construct a XChainCommit transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainCommit(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainCommit"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfXChainClaimID (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_UINT64::type::value_type - getXChainClaimID() const - { - return this->tx_->at(sfXChainClaimID); - } - - /** - * @brief Get sfAmount (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getAmount() const - { - return this->tx_->at(sfAmount); - } - - /** - * @brief Get sfOtherChainDestination (SoeOptional) - * @return The field value, or std::nullopt if not present. - */ - [[nodiscard]] - protocol_autogen::Optional - getOtherChainDestination() const - { - if (hasOtherChainDestination()) - { - return this->tx_->at(sfOtherChainDestination); - } - return std::nullopt; - } - - /** - * @brief Check if sfOtherChainDestination is present. - * @return True if the field is present, false otherwise. - */ - [[nodiscard]] - bool - hasOtherChainDestination() const - { - return this->tx_->isFieldPresent(sfOtherChainDestination); - } -}; - -/** - * @brief Builder for XChainCommit transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainCommitBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainCommitBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param xChainClaimID The sfXChainClaimID field value. - * @param amount The sfAmount field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainCommitBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::decay_t const& xChainClaimID, std::decay_t const& amount, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_COMMIT, account, sequence, fee) - { - setXChainBridge(xChainBridge); - setXChainClaimID(xChainClaimID); - setAmount(amount); - } - - /** - * @brief Construct a XChainCommitBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainCommitBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_COMMIT) - { - throw std::runtime_error("Invalid transaction type for XChainCommitBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCommitBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfXChainClaimID (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCommitBuilder& - setXChainClaimID(std::decay_t const& value) - { - object_[sfXChainClaimID] = value; - return *this; - } - - /** - * @brief Set sfAmount (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCommitBuilder& - setAmount(std::decay_t const& value) - { - object_[sfAmount] = value; - return *this; - } - - /** - * @brief Set sfOtherChainDestination (SoeOptional) - * @return Reference to this builder for method chaining. - */ - XChainCommitBuilder& - setOtherChainDestination(std::decay_t const& value) - { - object_[sfOtherChainDestination] = value; - return *this; - } - - /** - * @brief Build and return the XChainCommit wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainCommit - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainCommit{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainCreateBridge.h b/include/xrpl/protocol_autogen/transactions/XChainCreateBridge.h deleted file mode 100644 index ae5be4108f..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainCreateBridge.h +++ /dev/null @@ -1,190 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainCreateBridgeBuilder; - -/** - * @brief Transaction: XChainCreateBridge - * - * Type: ttXCHAIN_CREATE_BRIDGE (48) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: NoPriv - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainCreateBridgeBuilder to construct new transactions. - */ -class XChainCreateBridge : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_CREATE_BRIDGE; - - /** - * @brief Construct a XChainCreateBridge transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainCreateBridge(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainCreateBridge"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfSignatureReward (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getSignatureReward() const - { - return this->tx_->at(sfSignatureReward); - } - - /** - * @brief Get sfMinAccountCreateAmount (SoeOptional) - * @return The field value, or std::nullopt if not present. - */ - [[nodiscard]] - protocol_autogen::Optional - getMinAccountCreateAmount() const - { - if (hasMinAccountCreateAmount()) - { - return this->tx_->at(sfMinAccountCreateAmount); - } - return std::nullopt; - } - - /** - * @brief Check if sfMinAccountCreateAmount is present. - * @return True if the field is present, false otherwise. - */ - [[nodiscard]] - bool - hasMinAccountCreateAmount() const - { - return this->tx_->isFieldPresent(sfMinAccountCreateAmount); - } -}; - -/** - * @brief Builder for XChainCreateBridge transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainCreateBridgeBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainCreateBridgeBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param signatureReward The sfSignatureReward field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainCreateBridgeBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::decay_t const& signatureReward, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_CREATE_BRIDGE, account, sequence, fee) - { - setXChainBridge(xChainBridge); - setSignatureReward(signatureReward); - } - - /** - * @brief Construct a XChainCreateBridgeBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainCreateBridgeBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_CREATE_BRIDGE) - { - throw std::runtime_error("Invalid transaction type for XChainCreateBridgeBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCreateBridgeBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfSignatureReward (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCreateBridgeBuilder& - setSignatureReward(std::decay_t const& value) - { - object_[sfSignatureReward] = value; - return *this; - } - - /** - * @brief Set sfMinAccountCreateAmount (SoeOptional) - * @return Reference to this builder for method chaining. - */ - XChainCreateBridgeBuilder& - setMinAccountCreateAmount(std::decay_t const& value) - { - object_[sfMinAccountCreateAmount] = value; - return *this; - } - - /** - * @brief Build and return the XChainCreateBridge wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainCreateBridge - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainCreateBridge{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainCreateClaimID.h b/include/xrpl/protocol_autogen/transactions/XChainCreateClaimID.h deleted file mode 100644 index 7c1beb20c7..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainCreateClaimID.h +++ /dev/null @@ -1,177 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainCreateClaimIDBuilder; - -/** - * @brief Transaction: XChainCreateClaimID - * - * Type: ttXCHAIN_CREATE_CLAIM_ID (41) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: NoPriv - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainCreateClaimIDBuilder to construct new transactions. - */ -class XChainCreateClaimID : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_CREATE_CLAIM_ID; - - /** - * @brief Construct a XChainCreateClaimID transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainCreateClaimID(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainCreateClaimID"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfSignatureReward (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_AMOUNT::type::value_type - getSignatureReward() const - { - return this->tx_->at(sfSignatureReward); - } - - /** - * @brief Get sfOtherChainSource (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_ACCOUNT::type::value_type - getOtherChainSource() const - { - return this->tx_->at(sfOtherChainSource); - } -}; - -/** - * @brief Builder for XChainCreateClaimID transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainCreateClaimIDBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainCreateClaimIDBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param signatureReward The sfSignatureReward field value. - * @param otherChainSource The sfOtherChainSource field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainCreateClaimIDBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::decay_t const& signatureReward, std::decay_t const& otherChainSource, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_CREATE_CLAIM_ID, account, sequence, fee) - { - setXChainBridge(xChainBridge); - setSignatureReward(signatureReward); - setOtherChainSource(otherChainSource); - } - - /** - * @brief Construct a XChainCreateClaimIDBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainCreateClaimIDBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_CREATE_CLAIM_ID) - { - throw std::runtime_error("Invalid transaction type for XChainCreateClaimIDBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCreateClaimIDBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfSignatureReward (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCreateClaimIDBuilder& - setSignatureReward(std::decay_t const& value) - { - object_[sfSignatureReward] = value; - return *this; - } - - /** - * @brief Set sfOtherChainSource (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainCreateClaimIDBuilder& - setOtherChainSource(std::decay_t const& value) - { - object_[sfOtherChainSource] = value; - return *this; - } - - /** - * @brief Build and return the XChainCreateClaimID wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainCreateClaimID - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainCreateClaimID{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainModifyBridge.h b/include/xrpl/protocol_autogen/transactions/XChainModifyBridge.h deleted file mode 100644 index 30558ab88c..0000000000 --- a/include/xrpl/protocol_autogen/transactions/XChainModifyBridge.h +++ /dev/null @@ -1,203 +0,0 @@ -// This file is auto-generated. Do not edit. -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::transactions { - -class XChainModifyBridgeBuilder; - -/** - * @brief Transaction: XChainModifyBridge - * - * Type: ttXCHAIN_MODIFY_BRIDGE (47) - * Delegable: Delegation::Delegable - * Amendment: featureXChainBridge - * Privileges: NoPriv - * - * Immutable wrapper around STTx providing type-safe field access. - * Use XChainModifyBridgeBuilder to construct new transactions. - */ -class XChainModifyBridge : public TransactionBase -{ -public: - static constexpr xrpl::TxType txType = ttXCHAIN_MODIFY_BRIDGE; - - /** - * @brief Construct a XChainModifyBridge transaction wrapper from an existing STTx object. - * @throws std::runtime_error if the transaction type doesn't match. - */ - explicit XChainModifyBridge(std::shared_ptr tx) - : TransactionBase(std::move(tx)) - { - // Verify transaction type - if (tx_->getTxnType() != txType) - { - throw std::runtime_error("Invalid transaction type for XChainModifyBridge"); - } - } - - // Transaction-specific field getters - - /** - * @brief Get sfXChainBridge (SoeRequired) - * @return The field value. - */ - [[nodiscard]] - SF_XCHAIN_BRIDGE::type::value_type - getXChainBridge() const - { - return this->tx_->at(sfXChainBridge); - } - - /** - * @brief Get sfSignatureReward (SoeOptional) - * @return The field value, or std::nullopt if not present. - */ - [[nodiscard]] - protocol_autogen::Optional - getSignatureReward() const - { - if (hasSignatureReward()) - { - return this->tx_->at(sfSignatureReward); - } - return std::nullopt; - } - - /** - * @brief Check if sfSignatureReward is present. - * @return True if the field is present, false otherwise. - */ - [[nodiscard]] - bool - hasSignatureReward() const - { - return this->tx_->isFieldPresent(sfSignatureReward); - } - - /** - * @brief Get sfMinAccountCreateAmount (SoeOptional) - * @return The field value, or std::nullopt if not present. - */ - [[nodiscard]] - protocol_autogen::Optional - getMinAccountCreateAmount() const - { - if (hasMinAccountCreateAmount()) - { - return this->tx_->at(sfMinAccountCreateAmount); - } - return std::nullopt; - } - - /** - * @brief Check if sfMinAccountCreateAmount is present. - * @return True if the field is present, false otherwise. - */ - [[nodiscard]] - bool - hasMinAccountCreateAmount() const - { - return this->tx_->isFieldPresent(sfMinAccountCreateAmount); - } -}; - -/** - * @brief Builder for XChainModifyBridge transactions. - * - * Provides a fluent interface for constructing transactions with method chaining. - * Uses STObject internally for flexible transaction construction. - * Inherits common field setters from TransactionBuilderBase. - */ -class XChainModifyBridgeBuilder : public TransactionBuilderBase -{ -public: - /** - * @brief Construct a new XChainModifyBridgeBuilder with required fields. - * @param account The account initiating the transaction. - * @param xChainBridge The sfXChainBridge field value. - * @param sequence Optional sequence number for the transaction. - * @param fee Optional fee for the transaction. - */ - XChainModifyBridgeBuilder(SF_ACCOUNT::type::value_type account, - std::decay_t const& xChainBridge, std::optional sequence = std::nullopt, - std::optional fee = std::nullopt -) - : TransactionBuilderBase(ttXCHAIN_MODIFY_BRIDGE, account, sequence, fee) - { - setXChainBridge(xChainBridge); - } - - /** - * @brief Construct a XChainModifyBridgeBuilder from an existing STTx object. - * @param tx The existing transaction to copy from. - * @throws std::runtime_error if the transaction type doesn't match. - */ - XChainModifyBridgeBuilder(std::shared_ptr tx) - { - if (tx->getTxnType() != ttXCHAIN_MODIFY_BRIDGE) - { - throw std::runtime_error("Invalid transaction type for XChainModifyBridgeBuilder"); - } - object_ = *tx; - } - - /** @brief Transaction-specific field setters */ - - /** - * @brief Set sfXChainBridge (SoeRequired) - * @return Reference to this builder for method chaining. - */ - XChainModifyBridgeBuilder& - setXChainBridge(std::decay_t const& value) - { - object_[sfXChainBridge] = value; - return *this; - } - - /** - * @brief Set sfSignatureReward (SoeOptional) - * @return Reference to this builder for method chaining. - */ - XChainModifyBridgeBuilder& - setSignatureReward(std::decay_t const& value) - { - object_[sfSignatureReward] = value; - return *this; - } - - /** - * @brief Set sfMinAccountCreateAmount (SoeOptional) - * @return Reference to this builder for method chaining. - */ - XChainModifyBridgeBuilder& - setMinAccountCreateAmount(std::decay_t const& value) - { - object_[sfMinAccountCreateAmount] = value; - return *this; - } - - /** - * @brief Build and return the XChainModifyBridge wrapper. - * @param publicKey The public key for signing. - * @param secretKey The secret key for signing. - * @return The constructed transaction wrapper. - */ - XChainModifyBridge - build(PublicKey const& publicKey, SecretKey const& secretKey) - { - sign(publicKey, secretKey); - return XChainModifyBridge{std::make_shared(std::move(object_))}; - } -}; - -} // namespace xrpl::transactions diff --git a/include/xrpl/tx/transactors/bridge/XChainBridge.h b/include/xrpl/tx/transactors/bridge/XChainBridge.h deleted file mode 100644 index 24f49eb340..0000000000 --- a/include/xrpl/tx/transactors/bridge/XChainBridge.h +++ /dev/null @@ -1,336 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl { - -constexpr size_t kXbridgeMaxAccountCreateClaims = 128; - -// Attach a new bridge to a door account. Once this is done, the cross-chain -// transfer transactions may be used to transfer funds from this account. -class XChainCreateBridge : public Transactor -{ -public: - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal; - - explicit XChainCreateBridge(ApplyContext& ctx) : Transactor(ctx) - { - } - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -class BridgeModify : public Transactor -{ -public: - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal; - - explicit BridgeModify(ApplyContext& ctx) : Transactor(ctx) - { - } - - static std::uint32_t - getFlagsMask(PreflightContext const& ctx); - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -using XChainModifyBridge = BridgeModify; - -//------------------------------------------------------------------------------ - -// Claim funds from a `XChainCommit` transaction. This is normally not needed, -// but may be used to handle transaction failures or if the destination account -// was not specified in the `XChainCommit` transaction. It may only be used -// after a quorum of signatures have been sent from the witness servers. -// -// If the transaction succeeds in moving funds, the referenced `XChainClaimID` -// ledger object will be destroyed. This prevents transaction replay. If the -// transaction fails, the `XChainClaimID` will not be destroyed and the -// transaction may be re-run with different parameters. -class XChainClaim : public Transactor -{ -public: - // Blocker since we cannot accurately calculate the consequences - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker; - - explicit XChainClaim(ApplyContext& ctx) : Transactor(ctx) - { - } - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -//------------------------------------------------------------------------------ - -// Put assets into trust on the locking-chain so they may be wrapped on the -// issuing-chain, or return wrapped assets on the issuing-chain so they can be -// unlocked on the locking-chain. The second step in a cross-chain transfer. -class XChainCommit : public Transactor -{ -public: - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Custom; - - static TxConsequences - makeTxConsequences(PreflightContext const& ctx); - - explicit XChainCommit(ApplyContext& ctx) : Transactor(ctx) - { - } - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -//------------------------------------------------------------------------------ - -// Create a new claim id owned by the account. This is the first step in a -// cross-chain transfer. The claim id must be created on the destination chain -// before the `XChainCommit` transaction (which must reference this number) can -// be sent on the source chain. The account that will send the `XChainCommit` on -// the source chain must be specified in this transaction (see note on the -// `SourceAccount` field in the `XChainClaimID` ledger object for -// justification). The actual sequence number must be retrieved from a validated -// ledger. -class XChainCreateClaimID : public Transactor -{ -public: - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal; - - explicit XChainCreateClaimID(ApplyContext& ctx) : Transactor(ctx) - { - } - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -//------------------------------------------------------------------------------ - -// Provide attestations from a witness server attesting to events on -// the other chain. The signatures must be from one of the keys on the door's -// signer's list at the time the signature was provided. However, if the -// signature list changes between the time the signature was submitted and the -// quorum is reached, the new signature set is used and some of the currently -// collected signatures may be removed. Also note the reward is only sent to -// accounts that have keys on the current list. -class XChainAddClaimAttestation : public Transactor -{ -public: - // Blocker since we cannot accurately calculate the consequences - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker; - - explicit XChainAddClaimAttestation(ApplyContext& ctx) : Transactor(ctx) - { - } - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -class XChainAddAccountCreateAttestation : public Transactor -{ -public: - // Blocker since we cannot accurately calculate the consequences - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker; - - explicit XChainAddAccountCreateAttestation(ApplyContext& ctx) : Transactor(ctx) - { - } - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -//------------------------------------------------------------------------------ - -// This is a special transaction used for creating accounts through a -// cross-chain transfer. A normal cross-chain transfer requires a "chain claim -// id" (which requires an existing account on the destination chain). One -// purpose of the "chain claim id" is to prevent transaction replay. For this -// transaction, we use a different mechanism: the accounts must be claimed on -// the destination chain in the same order that the `XChainCreateAccountCommit` -// transactions occurred on the source chain. -// -// This transaction can only be used for XRP to XRP bridges. -// -// IMPORTANT: This transaction should only be enabled if the witness -// attestations will be reliably delivered to the destination chain. If the -// signatures are not delivered (for example, the chain relies on user wallets -// to collect signatures) then account creation would be blocked for all -// transactions that happened after the one waiting on attestations. This could -// be used maliciously. To disable this transaction on XRP to XRP bridges, the -// bridge's `MinAccountCreateAmount` should not be present. -// -// Note: If this account already exists, the XRP is transferred to the existing -// account. However, note that unlike the `XChainCommit` transaction, there is -// no error handling mechanism. If the claim transaction fails, there is no -// mechanism for refunds. The funds are permanently lost. This transaction -// should still only be used for account creation. -class XChainCreateAccountCommit : public Transactor -{ -public: - static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal; - - explicit XChainCreateAccountCommit(ApplyContext& ctx) : Transactor(ctx) - { - } - - static NotTEC - preflight(PreflightContext const& ctx); - - static TER - preclaim(PreclaimContext const& ctx); - - TER - doApply() override; - - void - visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override; - - [[nodiscard]] bool - finalizeInvariants( - STTx const& tx, - TER result, - XRPAmount fee, - ReadView const& view, - beast::Journal const& j) override; -}; - -using XChainAccountCreateCommit = XChainCreateAccountCommit; - -//------------------------------------------------------------------------------ - -} // namespace xrpl diff --git a/src/libxrpl/ledger/ApplyStateTable.cpp b/src/libxrpl/ledger/ApplyStateTable.cpp index abcbaac0aa..2a530c7a4c 100644 --- a/src/libxrpl/ledger/ApplyStateTable.cpp +++ b/src/libxrpl/ledger/ApplyStateTable.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index ced18d4db6..5390f455fb 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -71,9 +70,6 @@ enum class LedgerNameSpace : std::uint16_t { NftokenBuyOffers = 'h', NftokenSellOffers = 'i', Amm = 'A', - Bridge = 'H', - XchainClaimId = 'Q', - XchainCreateAccountClaimId = 'K', Did = 'I', Oracle = 'R', MPTokenIssuance = '~', @@ -482,44 +478,6 @@ delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept return {ltDELEGATE, indexHash(LedgerNameSpace::Delegate, account, authorizedAccount)}; } -Keylet -bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType) -{ - // A door account can support multiple bridges. On the locking chain - // there can only be one bridge per lockingChainCurrency. On the issuing - // chain there can only be one bridge per issuingChainCurrency. - auto const& issue = bridge.issue(chainType); - return {ltBRIDGE, indexHash(LedgerNameSpace::Bridge, bridge.door(chainType), issue.currency)}; -} - -Keylet -xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq) -{ - return { - ltXCHAIN_OWNED_CLAIM_ID, - indexHash( - LedgerNameSpace::XchainClaimId, - bridge.lockingChainDoor(), - bridge.lockingChainIssue(), - bridge.issuingChainDoor(), - bridge.issuingChainIssue(), - seq)}; -} - -Keylet -xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq) -{ - return { - ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, - indexHash( - LedgerNameSpace::XchainCreateAccountClaimId, - bridge.lockingChainDoor(), - bridge.lockingChainIssue(), - bridge.issuingChainDoor(), - bridge.issuingChainIssue(), - seq)}; -} - Keylet did(AccountID const& account) noexcept { diff --git a/src/libxrpl/protocol/InnerObjectFormats.cpp b/src/libxrpl/protocol/InnerObjectFormats.cpp index 0bdb217771..5a4fbbdc0e 100644 --- a/src/libxrpl/protocol/InnerObjectFormats.cpp +++ b/src/libxrpl/protocol/InnerObjectFormats.cpp @@ -63,58 +63,6 @@ InnerObjectFormats::InnerObjectFormats() {sfPrice, SoeRequired}, {sfAuthAccounts, SoeOptional}}); - add(sfXChainClaimAttestationCollectionElement.jsonName, - sfXChainClaimAttestationCollectionElement.getCode(), - { - {sfAttestationSignerAccount, SoeRequired}, - {sfPublicKey, SoeRequired}, - {sfSignature, SoeRequired}, - {sfAmount, SoeRequired}, - {sfAccount, SoeRequired}, - {sfAttestationRewardAccount, SoeRequired}, - {sfWasLockingChainSend, SoeRequired}, - {sfXChainClaimID, SoeRequired}, - {sfDestination, SoeOptional}, - }); - - add(sfXChainCreateAccountAttestationCollectionElement.jsonName, - sfXChainCreateAccountAttestationCollectionElement.getCode(), - { - {sfAttestationSignerAccount, SoeRequired}, - {sfPublicKey, SoeRequired}, - {sfSignature, SoeRequired}, - {sfAmount, SoeRequired}, - {sfAccount, SoeRequired}, - {sfAttestationRewardAccount, SoeRequired}, - {sfWasLockingChainSend, SoeRequired}, - {sfXChainAccountCreateCount, SoeRequired}, - {sfDestination, SoeRequired}, - {sfSignatureReward, SoeRequired}, - }); - - add(sfXChainClaimProofSig.jsonName, - sfXChainClaimProofSig.getCode(), - { - {sfAttestationSignerAccount, SoeRequired}, - {sfPublicKey, SoeRequired}, - {sfAmount, SoeRequired}, - {sfAttestationRewardAccount, SoeRequired}, - {sfWasLockingChainSend, SoeRequired}, - {sfDestination, SoeOptional}, - }); - - add(sfXChainCreateAccountProofSig.jsonName, - sfXChainCreateAccountProofSig.getCode(), - { - {sfAttestationSignerAccount, SoeRequired}, - {sfPublicKey, SoeRequired}, - {sfAmount, SoeRequired}, - {sfSignatureReward, SoeRequired}, - {sfAttestationRewardAccount, SoeRequired}, - {sfWasLockingChainSend, SoeRequired}, - {sfDestination, SoeRequired}, - }); - add(sfAuthAccount.jsonName, sfAuthAccount.getCode(), { diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index 33ca5424d1..8e256cc4ec 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -956,18 +955,6 @@ parseLeaf( } break; - case STI_XCHAIN_BRIDGE: - try - { - ret = detail::makeStvar(STXChainBridge(field, value)); - } - catch (std::exception const&) - { - error = invalidData(jsonName, fieldName); - return ret; - } - break; - case STI_CURRENCY: try { diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index 3d123e6a0e..3eff720113 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -217,9 +216,6 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args) case STI_ISSUE: construct(std::forward(args)...); return; - case STI_XCHAIN_BRIDGE: - construct(std::forward(args)...); - return; case STI_CURRENCY: construct(std::forward(args)...); return; diff --git a/src/libxrpl/protocol/STXChainBridge.cpp b/src/libxrpl/protocol/STXChainBridge.cpp deleted file mode 100644 index 005c9ccbce..0000000000 --- a/src/libxrpl/protocol/STXChainBridge.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -namespace xrpl { - -STXChainBridge::STXChainBridge() : STBase{sfXChainBridge} -{ -} - -STXChainBridge::STXChainBridge(SField const& name) : STBase{name} -{ -} - -STXChainBridge::STXChainBridge( - AccountID const& srcChainDoor, - Issue const& srcChainIssue, - AccountID const& dstChainDoor, - Issue const& dstChainIssue) - : STBase{sfXChainBridge} - , lockingChainDoor_{sfLockingChainDoor, srcChainDoor} - , lockingChainIssue_{sfLockingChainIssue, srcChainIssue} - , issuingChainDoor_{sfIssuingChainDoor, dstChainDoor} - , issuingChainIssue_{sfIssuingChainIssue, dstChainIssue} -{ -} - -STXChainBridge::STXChainBridge(STObject const& o) - : STBase{sfXChainBridge} - , lockingChainDoor_{sfLockingChainDoor, o[sfLockingChainDoor]} - , lockingChainIssue_{sfLockingChainIssue, o[sfLockingChainIssue]} - , issuingChainDoor_{sfIssuingChainDoor, o[sfIssuingChainDoor]} - , issuingChainIssue_{sfIssuingChainIssue, o[sfIssuingChainIssue]} -{ -} - -STXChainBridge::STXChainBridge(json::Value const& v) : STXChainBridge{sfXChainBridge, v} -{ -} - -STXChainBridge::STXChainBridge(SField const& name, json::Value const& v) : STBase{name} -{ - if (!v.isObject()) - { - Throw( - "STXChainBridge can only be specified with a 'object' Json value"); - } - - auto checkExtra = [](json::Value const& v) { - static auto const kBridgeJson = - xrpl::STXChainBridge().getJson(xrpl::JsonOptions::Values::None); - for (auto it = v.begin(); it != v.end(); ++it) - { - std::string const name = it.memberName(); - if (!kBridgeJson.isMember(name)) - { - Throw("STXChainBridge extra field detected: " + name); - } - } - return true; - }; - checkExtra(v); - - json::Value const& lockingChainDoorStr = v[jss::LockingChainDoor]; - json::Value const& lockingChainIssue = v[jss::LockingChainIssue]; - json::Value const& issuingChainDoorStr = v[jss::IssuingChainDoor]; - json::Value const& issuingChainIssue = v[jss::IssuingChainIssue]; - - if (!lockingChainDoorStr.isString()) - { - Throw("STXChainBridge LockingChainDoor must be a string Json value"); - } - if (!issuingChainDoorStr.isString()) - { - Throw("STXChainBridge IssuingChainDoor must be a string Json value"); - } - - auto const lockingChainDoor = parseBase58(lockingChainDoorStr.asString()); - auto const issuingChainDoor = parseBase58(issuingChainDoorStr.asString()); - if (!lockingChainDoor) - { - Throw("STXChainBridge LockingChainDoor must be a valid account"); - } - if (!issuingChainDoor) - { - Throw("STXChainBridge IssuingChainDoor must be a valid account"); - } - - lockingChainDoor_ = STAccount{sfLockingChainDoor, *lockingChainDoor}; - lockingChainIssue_ = STIssue{sfLockingChainIssue, issueFromJson(lockingChainIssue)}; - issuingChainDoor_ = STAccount{sfIssuingChainDoor, *issuingChainDoor}; - issuingChainIssue_ = STIssue{sfIssuingChainIssue, issueFromJson(issuingChainIssue)}; -} - -STXChainBridge::STXChainBridge(SerialIter& sit, SField const& name) - : STBase{name} - , lockingChainDoor_{sit, sfLockingChainDoor} - , lockingChainIssue_{sit, sfLockingChainIssue} - , issuingChainDoor_{sit, sfIssuingChainDoor} - , issuingChainIssue_{sit, sfIssuingChainIssue} -{ -} - -void -STXChainBridge::add(Serializer& s) const -{ - lockingChainDoor_.add(s); - lockingChainIssue_.add(s); - issuingChainDoor_.add(s); - issuingChainIssue_.add(s); -} - -json::Value -STXChainBridge::getJson(JsonOptions jo) const -{ - json::Value v; - v[jss::LockingChainDoor] = lockingChainDoor_.getJson(jo); - v[jss::LockingChainIssue] = lockingChainIssue_.getJson(jo); - v[jss::IssuingChainDoor] = issuingChainDoor_.getJson(jo); - v[jss::IssuingChainIssue] = issuingChainIssue_.getJson(jo); - return v; -} - -std::string -STXChainBridge::getText() const -{ - return str( - boost::format("{ %s = %s, %s = %s, %s = %s, %s = %s }") % sfLockingChainDoor.getName() % - lockingChainDoor_.getText() % sfLockingChainIssue.getName() % lockingChainIssue_.getText() % - sfIssuingChainDoor.getName() % issuingChainDoor_.getText() % sfIssuingChainIssue.getName() % - issuingChainIssue_.getText()); -} - -STObject -STXChainBridge::toSTObject() const -{ - STObject o{sfXChainBridge}; - o[sfLockingChainDoor] = lockingChainDoor_; - o[sfLockingChainIssue] = lockingChainIssue_; - o[sfIssuingChainDoor] = issuingChainDoor_; - o[sfIssuingChainIssue] = issuingChainIssue_; - return o; -} - -SerializedTypeID -STXChainBridge::getSType() const -{ - return STI_XCHAIN_BRIDGE; -} - -bool -STXChainBridge::isEquivalent(STBase const& t) const -{ - auto const* v = dynamic_cast(&t); - return (v != nullptr) && (*v == *this); -} - -bool -STXChainBridge::isDefault() const -{ - return lockingChainDoor_.isDefault() && lockingChainIssue_.isDefault() && - issuingChainDoor_.isDefault() && issuingChainIssue_.isDefault(); -} - -std::unique_ptr -STXChainBridge::construct(SerialIter& sit, SField const& name) -{ - return std::make_unique(sit, name); -} - -STBase* -STXChainBridge::copy(std::size_t n, void* buf) const -{ - return emplace(n, buf, *this); -} - -STBase* -STXChainBridge::move(std::size_t n, void* buf) -{ - return emplace(n, buf, std::move(*this)); -} -} // namespace xrpl diff --git a/src/libxrpl/protocol/XChainAttestations.cpp b/src/libxrpl/protocol/XChainAttestations.cpp deleted file mode 100644 index 792fe5da9d..0000000000 --- a/src/libxrpl/protocol/XChainAttestations.cpp +++ /dev/null @@ -1,706 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace xrpl { -namespace Attestations { - -AttestationBase::AttestationBase( - AccountID attestationSignerAccount, - PublicKey const& publicKey, - Buffer signature, - AccountID const& sendingAccount, - STAmount sendingAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend) - : attestationSignerAccount{attestationSignerAccount} - , publicKey{publicKey} - , signature{std::move(signature)} - , sendingAccount{sendingAccount} - , sendingAmount{std::move(sendingAmount)} - , rewardAccount{rewardAccount} - , wasLockingChainSend{wasLockingChainSend} -{ -} - -bool -AttestationBase::equalHelper(AttestationBase const& lhs, AttestationBase const& rhs) -{ - return std::tie( - lhs.attestationSignerAccount, - lhs.publicKey, - lhs.signature, - lhs.sendingAccount, - lhs.sendingAmount, - lhs.rewardAccount, - lhs.wasLockingChainSend) == - std::tie( - rhs.attestationSignerAccount, - rhs.publicKey, - rhs.signature, - rhs.sendingAccount, - rhs.sendingAmount, - rhs.rewardAccount, - rhs.wasLockingChainSend); -} - -bool -AttestationBase::sameEventHelper(AttestationBase const& lhs, AttestationBase const& rhs) -{ - return std::tie(lhs.sendingAccount, lhs.sendingAmount, lhs.wasLockingChainSend) == - std::tie(rhs.sendingAccount, rhs.sendingAmount, rhs.wasLockingChainSend); -} - -bool -AttestationBase::verify(STXChainBridge const& bridge) const -{ - std::vector const msg = message(bridge); - return xrpl::verify(publicKey, makeSlice(msg), signature); -} - -AttestationBase::AttestationBase(STObject const& o) - : attestationSignerAccount{o[sfAttestationSignerAccount]} - , publicKey{o[sfPublicKey]} - , signature{o[sfSignature]} - , sendingAccount{o[sfAccount]} - , sendingAmount{o[sfAmount]} - , rewardAccount{o[sfAttestationRewardAccount]} - , wasLockingChainSend{bool(o[sfWasLockingChainSend])} -{ -} - -AttestationBase::AttestationBase(json::Value const& v) - : attestationSignerAccount{json::getOrThrow(v, sfAttestationSignerAccount)} - , publicKey{json::getOrThrow(v, sfPublicKey)} - , signature{json::getOrThrow(v, sfSignature)} - , sendingAccount{json::getOrThrow(v, sfAccount)} - , sendingAmount{json::getOrThrow(v, sfAmount)} - , rewardAccount{json::getOrThrow(v, sfAttestationRewardAccount)} - , wasLockingChainSend{json::getOrThrow(v, sfWasLockingChainSend)} -{ -} - -void -AttestationBase::addHelper(STObject& o) const -{ - o[sfAttestationSignerAccount] = attestationSignerAccount; - o[sfPublicKey] = publicKey; - o[sfSignature] = signature; - o[sfAmount] = sendingAmount; - o[sfAccount] = sendingAccount; - o[sfAttestationRewardAccount] = rewardAccount; - o[sfWasLockingChainSend] = wasLockingChainSend; -} - -AttestationClaim::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) - : AttestationBase( - attestationSignerAccount, - publicKey, - std::move(signature), - sendingAccount, - sendingAmount, - rewardAccount, - wasLockingChainSend) - , claimID{claimId} - , dst{dst} -{ -} - -AttestationClaim::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) - : AttestationClaim{ - attestationSignerAccount, - publicKey, - Buffer{}, - sendingAccount, - sendingAmount, - rewardAccount, - wasLockingChainSend, - claimId, - dst} -{ - auto const toSign = message(bridge); - signature = sign(publicKey, secretKey, makeSlice(toSign)); -} - -AttestationClaim::AttestationClaim(STObject const& o) - : AttestationBase(o), claimID{o[sfXChainClaimID]}, dst{o[~sfDestination]} -{ -} - -AttestationClaim::AttestationClaim(json::Value const& v) - : AttestationBase{v}, claimID{json::getOrThrow(v, sfXChainClaimID)} -{ - if (v.isMember(sfDestination.getJsonName())) - dst = json::getOrThrow(v, sfDestination); -} - -STObject -AttestationClaim::toSTObject() const -{ - STObject o = STObject::makeInnerObject(sfXChainClaimAttestationCollectionElement); - addHelper(o); - o[sfXChainClaimID] = claimID; - if (dst) - o[sfDestination] = *dst; - return o; -} - -std::vector -AttestationClaim::message( - STXChainBridge const& bridge, - AccountID const& sendingAccount, - STAmount const& sendingAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t claimID, - std::optional const& dst) -{ - STObject o{sfGeneric}; - // Serialize in SField order to make python serializers easier to write - o[sfXChainClaimID] = claimID; - o[sfAmount] = sendingAmount; - if (dst) - o[sfDestination] = *dst; - o[sfOtherChainSource] = sendingAccount; - o[sfAttestationRewardAccount] = rewardAccount; - o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0; - o[sfXChainBridge] = bridge; - - Serializer s; - o.add(s); - - return std::move(s.modData()); -} - -std::vector -AttestationClaim::message(STXChainBridge const& bridge) const -{ - return AttestationClaim::message( - bridge, sendingAccount, sendingAmount, rewardAccount, wasLockingChainSend, claimID, dst); -} - -bool -AttestationClaim::validAmounts() const -{ - return isLegalNet(sendingAmount); -} - -bool -AttestationClaim::sameEvent(AttestationClaim const& rhs) const -{ - return AttestationClaim::sameEventHelper(*this, rhs) && - tie(claimID, dst) == tie(rhs.claimID, rhs.dst); -} - -bool -operator==(AttestationClaim const& lhs, AttestationClaim const& rhs) -{ - return AttestationClaim::equalHelper(lhs, rhs) && - tie(lhs.claimID, lhs.dst) == tie(rhs.claimID, rhs.dst); -} - -AttestationCreateAccount::AttestationCreateAccount(STObject const& o) - : AttestationBase(o) - , createCount{o[sfXChainAccountCreateCount]} - , toCreate{o[sfDestination]} - , rewardAmount{o[sfSignatureReward]} -{ -} - -AttestationCreateAccount::AttestationCreateAccount(json::Value const& v) - : AttestationBase{v} - , createCount{json::getOrThrow(v, sfXChainAccountCreateCount)} - , toCreate{json::getOrThrow(v, sfDestination)} - , rewardAmount{json::getOrThrow(v, sfSignatureReward)} -{ -} - -AttestationCreateAccount::AttestationCreateAccount( - AccountID attestationSignerAccount, - PublicKey const& publicKey, - Buffer signature, - AccountID const& sendingAccount, - STAmount const& sendingAmount, - STAmount rewardAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t createCount, - AccountID const& toCreate) - : AttestationBase( - attestationSignerAccount, - publicKey, - std::move(signature), - sendingAccount, - sendingAmount, - rewardAccount, - wasLockingChainSend) - , createCount{createCount} - , toCreate{toCreate} - , rewardAmount{std::move(rewardAmount)} -{ -} - -AttestationCreateAccount::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) - : AttestationCreateAccount{ - attestationSignerAccount, - publicKey, - Buffer{}, - sendingAccount, - sendingAmount, - rewardAmount, - rewardAccount, - wasLockingChainSend, - createCount, - toCreate} -{ - auto const toSign = message(bridge); - signature = sign(publicKey, secretKey, makeSlice(toSign)); -} - -STObject -AttestationCreateAccount::toSTObject() const -{ - STObject o = STObject::makeInnerObject(sfXChainCreateAccountAttestationCollectionElement); - addHelper(o); - - o[sfXChainAccountCreateCount] = createCount; - o[sfDestination] = toCreate; - o[sfSignatureReward] = rewardAmount; - - return o; -} - -std::vector -AttestationCreateAccount::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) -{ - STObject o{sfGeneric}; - // Serialize in SField order to make python serializers easier to write - o[sfXChainAccountCreateCount] = createCount; - o[sfAmount] = sendingAmount; - o[sfSignatureReward] = rewardAmount; - o[sfDestination] = dst; - o[sfOtherChainSource] = sendingAccount; - o[sfAttestationRewardAccount] = rewardAccount; - o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0; - o[sfXChainBridge] = bridge; - - Serializer s; - o.add(s); - - return std::move(s.modData()); -} - -std::vector -AttestationCreateAccount::message(STXChainBridge const& bridge) const -{ - return AttestationCreateAccount::message( - bridge, - sendingAccount, - sendingAmount, - rewardAmount, - rewardAccount, - wasLockingChainSend, - createCount, - toCreate); -} - -bool -AttestationCreateAccount::validAmounts() const -{ - return isLegalNet(rewardAmount) && isLegalNet(sendingAmount); -} - -bool -AttestationCreateAccount::sameEvent(AttestationCreateAccount const& rhs) const -{ - return AttestationCreateAccount::sameEventHelper(*this, rhs) && - std::tie(createCount, toCreate, rewardAmount) == - std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount); -} - -bool -operator==(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs) -{ - return AttestationCreateAccount::equalHelper(lhs, rhs) && - std::tie(lhs.createCount, lhs.toCreate, lhs.rewardAmount) == - std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount); -} - -} // namespace Attestations - -SField const& XChainClaimAttestation::arrayFieldName{sfXChainClaimAttestations}; -SField const& XChainCreateAccountAttestation::arrayFieldName{sfXChainCreateAccountAttestations}; - -XChainClaimAttestation::XChainClaimAttestation( - AccountID const& keyAccount, - PublicKey const& publicKey, - STAmount const& amount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - std::optional const& dst) - : keyAccount(keyAccount) - , publicKey(publicKey) - , amount(sfAmount, amount) - , rewardAccount(rewardAccount) - , wasLockingChainSend(wasLockingChainSend) - , dst(dst) -{ -} - -XChainClaimAttestation::XChainClaimAttestation( - STAccount const& keyAccount, - PublicKey const& publicKey, - STAmount const& amount, - STAccount const& rewardAccount, - bool wasLockingChainSend, - std::optional const& dst) - : XChainClaimAttestation{ - keyAccount.value(), - publicKey, - amount, - rewardAccount.value(), - wasLockingChainSend, - dst ? std::optional{dst->value()} : std::nullopt} -{ -} - -XChainClaimAttestation::XChainClaimAttestation(STObject const& o) - : XChainClaimAttestation{ - o[sfAttestationSignerAccount], - PublicKey{o[sfPublicKey]}, - o[sfAmount], - o[sfAttestationRewardAccount], - o[sfWasLockingChainSend] != 0, - o[~sfDestination]} {}; - -XChainClaimAttestation::XChainClaimAttestation(json::Value const& v) - : XChainClaimAttestation{ - json::getOrThrow(v, sfAttestationSignerAccount), - json::getOrThrow(v, sfPublicKey), - json::getOrThrow(v, sfAmount), - json::getOrThrow(v, sfAttestationRewardAccount), - json::getOrThrow(v, sfWasLockingChainSend), - std::nullopt} -{ - if (v.isMember(sfDestination.getJsonName())) - dst = json::getOrThrow(v, sfDestination); -}; - -XChainClaimAttestation::XChainClaimAttestation( - XChainClaimAttestation::TSignedAttestation const& claimAtt) - : XChainClaimAttestation{ - claimAtt.attestationSignerAccount, - claimAtt.publicKey, - claimAtt.sendingAmount, - claimAtt.rewardAccount, - claimAtt.wasLockingChainSend, - claimAtt.dst} -{ -} - -STObject -XChainClaimAttestation::toSTObject() const -{ - STObject o = STObject::makeInnerObject(sfXChainClaimProofSig); - o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; - o[sfPublicKey] = publicKey; - o[sfAmount] = STAmount{sfAmount, amount}; - o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount}; - o[sfWasLockingChainSend] = wasLockingChainSend; - if (dst) - o[sfDestination] = STAccount{sfDestination, *dst}; - return o; -} - -bool -operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs) -{ - return std::tie( - lhs.keyAccount, - lhs.publicKey, - lhs.amount, - lhs.rewardAccount, - lhs.wasLockingChainSend, - lhs.dst) == - std::tie( - rhs.keyAccount, - rhs.publicKey, - rhs.amount, - rhs.rewardAccount, - rhs.wasLockingChainSend, - rhs.dst); -} - -XChainClaimAttestation::MatchFields::MatchFields( - XChainClaimAttestation::TSignedAttestation const& att) - : amount{att.sendingAmount}, wasLockingChainSend{att.wasLockingChainSend}, dst{att.dst} -{ -} - -AttestationMatch -XChainClaimAttestation::match(XChainClaimAttestation::MatchFields const& rhs) const -{ - if (std::tie(amount, wasLockingChainSend) != std::tie(rhs.amount, rhs.wasLockingChainSend)) - return AttestationMatch::NonDstMismatch; - if (dst != rhs.dst) - return AttestationMatch::MatchExceptDst; - return AttestationMatch::Match; -} - -//------------------------------------------------------------------------------ - -XChainCreateAccountAttestation::XChainCreateAccountAttestation( - AccountID const& keyAccount, - PublicKey const& publicKey, - STAmount const& amount, - STAmount const& rewardAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - AccountID const& dst) - : keyAccount(keyAccount) - , publicKey(publicKey) - , amount(sfAmount, amount) - , rewardAmount(sfSignatureReward, rewardAmount) - , rewardAccount(rewardAccount) - , wasLockingChainSend(wasLockingChainSend) - , dst(dst) -{ -} - -XChainCreateAccountAttestation::XChainCreateAccountAttestation(STObject const& o) - : XChainCreateAccountAttestation{ - o[sfAttestationSignerAccount], - PublicKey{o[sfPublicKey]}, - o[sfAmount], - o[sfSignatureReward], - o[sfAttestationRewardAccount], - o[sfWasLockingChainSend] != 0, - o[sfDestination]} {}; - -XChainCreateAccountAttestation ::XChainCreateAccountAttestation(json::Value const& v) - : XChainCreateAccountAttestation{ - json::getOrThrow(v, sfAttestationSignerAccount), - json::getOrThrow(v, sfPublicKey), - json::getOrThrow(v, sfAmount), - json::getOrThrow(v, sfSignatureReward), - json::getOrThrow(v, sfAttestationRewardAccount), - json::getOrThrow(v, sfWasLockingChainSend), - json::getOrThrow(v, sfDestination)} -{ -} - -XChainCreateAccountAttestation::XChainCreateAccountAttestation( - XChainCreateAccountAttestation::TSignedAttestation const& createAtt) - : XChainCreateAccountAttestation{ - createAtt.attestationSignerAccount, - createAtt.publicKey, - createAtt.sendingAmount, - createAtt.rewardAmount, - createAtt.rewardAccount, - createAtt.wasLockingChainSend, - createAtt.toCreate} -{ -} - -STObject -XChainCreateAccountAttestation::toSTObject() const -{ - STObject o = STObject::makeInnerObject(sfXChainCreateAccountProofSig); - - o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; - o[sfPublicKey] = publicKey; - o[sfAmount] = STAmount{sfAmount, amount}; - o[sfSignatureReward] = STAmount{sfSignatureReward, rewardAmount}; - o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount}; - o[sfWasLockingChainSend] = wasLockingChainSend; - o[sfDestination] = STAccount{sfDestination, dst}; - - return o; -} - -XChainCreateAccountAttestation::MatchFields::MatchFields( - XChainCreateAccountAttestation::TSignedAttestation const& att) - : amount{att.sendingAmount} - , rewardAmount(att.rewardAmount) - , wasLockingChainSend{att.wasLockingChainSend} - , dst{att.toCreate} -{ -} - -AttestationMatch -XChainCreateAccountAttestation::match(XChainCreateAccountAttestation::MatchFields const& rhs) const -{ - if (std::tie(amount, rewardAmount, wasLockingChainSend) != - std::tie(rhs.amount, rhs.rewardAmount, rhs.wasLockingChainSend)) - return AttestationMatch::NonDstMismatch; - if (dst != rhs.dst) - return AttestationMatch::MatchExceptDst; - return AttestationMatch::Match; -} - -bool -operator==(XChainCreateAccountAttestation const& lhs, XChainCreateAccountAttestation const& rhs) -{ - return std::tie( - lhs.keyAccount, - lhs.publicKey, - lhs.amount, - lhs.rewardAmount, - lhs.rewardAccount, - lhs.wasLockingChainSend, - lhs.dst) == - std::tie( - rhs.keyAccount, - rhs.publicKey, - rhs.amount, - rhs.rewardAmount, - rhs.rewardAccount, - rhs.wasLockingChainSend, - rhs.dst); -} - -//------------------------------------------------------------------------------ -// -template -XChainAttestationsBase::XChainAttestationsBase( - XChainAttestationsBase::AttCollection&& atts) - : attestations_{std::move(atts)} -{ -} - -template -XChainAttestationsBase::AttCollection::const_iterator -XChainAttestationsBase::begin() const -{ - return attestations_.begin(); -} - -template -XChainAttestationsBase::AttCollection::const_iterator -XChainAttestationsBase::end() const -{ - return attestations_.end(); -} - -template -XChainAttestationsBase::AttCollection::iterator -XChainAttestationsBase::begin() -{ - return attestations_.begin(); -} - -template -XChainAttestationsBase::AttCollection::iterator -XChainAttestationsBase::end() -{ - return attestations_.end(); -} - -template -XChainAttestationsBase::XChainAttestationsBase(json::Value const& v) -{ - if (!v.isObject()) - { - Throw( - "XChainAttestationsBase can only be specified with an 'object' " - "Json value"); - } - - attestations_ = [&] { - auto const jAtts = v[jss::attestations]; - - if (jAtts.size() > kMaxAttestations) - Throw("XChainAttestationsBase exceeded max number of attestations"); - - std::vector r; - r.reserve(jAtts.size()); - for (auto const& a : jAtts) - r.emplace_back(a); - return r; - }(); -} - -template -XChainAttestationsBase::XChainAttestationsBase(STArray const& arr) -{ - if (arr.size() > kMaxAttestations) - Throw("XChainAttestationsBase exceeded max number of attestations"); - - attestations_.reserve(arr.size()); - for (auto const& o : arr) - attestations_.emplace_back(o); -} - -template -STArray -XChainAttestationsBase::toSTArray() const -{ - STArray r{TAttestation::arrayFieldName, attestations_.size()}; - for (auto const& e : attestations_) - r.emplaceBack(e.toSTObject()); - return r; -} - -template class XChainAttestationsBase; -template class XChainAttestationsBase; - -} // namespace xrpl diff --git a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp deleted file mode 100644 index 92a8dccdb9..0000000000 --- a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp +++ /dev/null @@ -1,2366 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace xrpl { - -/* - Bridges connect two independent ledgers: a "locking chain" and an "issuing - chain". An asset can be moved from the locking chain to the issuing chain by - putting it into trust on the locking chain, and issuing a "wrapped asset" - that represents the locked asset on the issuing chain. - - Note that a bridge is not an exchange. There is no exchange rate: one wrapped - asset on the issuing chain always represents one asset in trust on the - locking chain. The bridge also does not exchange an asset on the locking - chain for an asset on the issuing chain. - - A good model for thinking about bridges is a box that contains an infinite - number of "wrapped tokens". When a token from the locking chain - (locking-chain-token) is put into the box, a wrapped token is taken out of - the box and put onto the issuing chain (issuing-chain-token). No one can use - the locking-chain-token while it remains in the box. When an - issuing-chain-token is returned to the box, one locking-chain-token is taken - out of the box and put back onto the locking chain. - - This requires a way to put assets into trust on one chain (put a - locking-chain-token into the box). A regular XRP account is used for this. - This account is called a "door account". Much in the same way that a door is - used to go from one room to another, a door account is used to move from one - chain to another. This account will be jointly controlled by a set of witness - servers by using the ledger's multi-signature support. The master key will be - disabled. These witness servers are trusted in the sense that if a quorum of - them collude, they can steal the funds put into trust. - - This also requires a way to prove that assets were put into the box - either - a locking-chain-token on the locking chain or returning an - issuing-chain-token on the issuing chain. A set of servers called "witness - servers" fill this role. These servers watch the ledger for these - transactions, and attest that the given events happened on the different - chains by signing messages with the event information. - - There needs to be a way to prevent the attestations from the witness - servers from being used more than once. "Claim ids" fill this role. A claim - id must be acquired on the destination chain before the asset is "put into - the box" on the source chain. This claim id has a unique id, and once it is - destroyed it can never exist again (it's a simple counter). The attestations - reference this claim id, and are accumulated on the claim id. Once a quorum - is reached, funds can move. Once the funds move, the claim id is destroyed. - - Finally, a claim id requires that the sender has an account on the - destination chain. For some chains, this can be a problem - especially if - the wrapped asset represents XRP, and XRP is needed to create an account. - There's a bootstrap problem. To address this, there is a special transaction - used to create accounts. This transaction does not require a claim id. - - See the document "docs/bridge/spec.md" for a full description of how - bridges and their transactions work. -*/ - -namespace { - -// Check that the public key is allowed to sign for the given account. If the -// account does not exist on the ledger, then the public key must be the master -// key for the given account if it existed. Otherwise the key must be an enabled -// master key or a regular key for the existing account. -TER -checkAttestationPublicKey( - ReadView const& view, - std::unordered_map const& signersList, - AccountID const& attestationSignerAccount, - PublicKey const& pk, - beast::Journal j) -{ - if (!signersList.contains(attestationSignerAccount)) - { - return tecNO_PERMISSION; - } - - AccountID const accountFromPK = calcAccountID(pk); - - if (auto const sleAttestationSigningAccount = - view.read(keylet::account(attestationSignerAccount))) - { - if (accountFromPK == attestationSignerAccount) - { - // master key - if (sleAttestationSigningAccount->isFlag(lsfDisableMaster)) - { - JLOG(j.trace()) << "Attempt to add an attestation with " - "disabled master key."; - return tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR; - } - } - else - { - // regular key - if (std::optional const regularKey = - (*sleAttestationSigningAccount)[~sfRegularKey]; - regularKey != accountFromPK) - { - if (!regularKey) - { - JLOG(j.trace()) << "Attempt to add an attestation with " - "account present and non-present regular key."; - } - else - { - JLOG(j.trace()) << "Attempt to add an attestation with " - "account present and mismatched " - "regular key/public key."; - } - return tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR; - } - } - } - else - { - // account does not exist. - if (calcAccountID(pk) != attestationSignerAccount) - { - JLOG(j.trace()) << "Attempt to add an attestation with non-existant account " - "and mismatched pk/account pair."; - return tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR; - } - } - - return tesSUCCESS; -} - -// If there is a quorum of attestations for the given parameters, then -// return the reward accounts, otherwise return TER for the error. -// Also removes attestations that are no longer part of the signers list. -// -// Note: the dst parameter is what the attestations are attesting to, which -// is not always used (it is used when automatically triggering a transfer -// from an `addAttestation` transaction, it is not used in a `claim` -// transaction). If the `checkDst` parameter is `check`, the attestations -// must attest to this destination, if it is `ignore` then the `dst` of the -// attestations are not checked (as for a `claim` transaction) - -enum class CheckDst { Check, Ignore }; -template -std::expected, TER> -claimHelper( - XChainAttestationsBase& attestations, - ReadView const& view, - typename TAttestation::MatchFields const& toMatch, - CheckDst checkDst, - std::uint32_t quorum, - std::unordered_map const& signersList, - beast::Journal j) -{ - // Remove attestations that are not valid signers. They may be no longer - // part of the signers list, or their master key may have been disabled, - // or their regular key may have changed - attestations.eraseIf([&](auto const& a) { - return checkAttestationPublicKey(view, signersList, a.keyAccount, a.publicKey, j) != - tesSUCCESS; - }); - - // Check if we have quorum for the amount specified on the new claimAtt - std::vector rewardAccounts; - rewardAccounts.reserve(attestations.size()); - std::uint32_t weight = 0; - for (auto const& a : attestations) - { - auto const matchR = a.match(toMatch); - // The dest must match if claimHelper is being run as a result of an add - // attestation transaction. The dst does not need to match if the - // claimHelper is being run using an explicit claim transaction. - using enum AttestationMatch; - if (matchR == NonDstMismatch || (checkDst == CheckDst::Check && matchR != Match)) - continue; - auto i = signersList.find(a.keyAccount); - if (i == signersList.end()) - { - // LCOV_EXCL_START - UNREACHABLE("xrpl::claimHelper : invalid inputs"); // should have already - // been checked - continue; - // LCOV_EXCL_STOP - } - weight += i->second; - rewardAccounts.push_back(a.rewardAccount); - } - - if (weight >= quorum) - return rewardAccounts; - - return std::unexpected(tecXCHAIN_CLAIM_NO_QUORUM); -} - -/** - Handle a new attestation event. - - Attempt to add the given attestation and reconcile with the current - signer's list. Attestations that are not part of the current signer's - list will be removed. - - @param claimAtt New attestation to add. It will be added if it is not - already part of the collection, or attests to a larger value. - - @param quorum Min weight required for a quorum - - @param signersList Map from signer's account id (derived from public keys) - to the weight of that key. - - @return optional reward accounts. If after handling the new attestation - there is a quorum for the amount specified on the new attestation, then - return the reward accounts for that amount, otherwise return a nullopt. - Note that if the signer's list changes and there have been `commit` - transactions of different amounts then there may be a different subset that - has reached quorum. However, to "trigger" that subset would require adding - (or re-adding) an attestation that supports that subset. - - The reason for using a nullopt instead of an empty vector when a quorum is - not reached is to allow for an interface where a quorum is reached but no - rewards are distributed. - - @note This function is not called `add` because it does more than just - add the new attestation (in fact, it may not add the attestation at - all). Instead, it handles the event of a new attestation. - */ -struct OnNewAttestationResult -{ - std::optional> rewardAccounts; - // `changed` is true if the attestation collection changed in any way - // (added/removed/changed) - bool changed{false}; -}; - -template -[[nodiscard]] OnNewAttestationResult -onNewAttestations( - XChainAttestationsBase& attestations, - ReadView const& view, - typename TAttestation::TSignedAttestation const* attBegin, - typename TAttestation::TSignedAttestation const* attEnd, - std::uint32_t quorum, - std::unordered_map const& signersList, - beast::Journal j) -{ - bool changed = false; - for (auto att = attBegin; att != attEnd; ++att) - { - auto const ter = checkAttestationPublicKey( - view, signersList, att->attestationSignerAccount, att->publicKey, j); - if (!isTesSuccess(ter)) - { - // The checkAttestationPublicKey is not strictly necessary here (it - // should be checked in a preclaim step), but it would be bad to let - // this slip through if that changes, and the check is relatively - // cheap, so we check again - continue; - } - - auto const& claimSigningAccount = att->attestationSignerAccount; - if (auto i = std::ranges::find_if( - attestations, [&](auto const& a) { return a.keyAccount == claimSigningAccount; }); - i != attestations.end()) - { - // existing attestation - // replace old attestation with new attestation - *i = TAttestation{*att}; - changed = true; - } - else - { - attestations.emplaceBack(*att); - changed = true; - } - } - - auto r = claimHelper( - attestations, - view, - typename TAttestation::MatchFields{*attBegin}, - CheckDst::Check, - quorum, - signersList, - j); - - if (!r.has_value()) - return {.rewardAccounts = std::nullopt, .changed = changed}; - - return {std::move(r.value()), changed}; -}; - -// Check if there is a quorum of attestations for the given amount and -// chain. If so return the reward accounts, if not return the tec code (most -// likely tecXCHAIN_CLAIM_NO_QUORUM) -std::expected, TER> -onClaim( - XChainClaimAttestations& attestations, - ReadView const& view, - STAmount const& sendingAmount, - bool wasLockingChainSend, - std::uint32_t quorum, - std::unordered_map const& signersList, - beast::Journal j) -{ - XChainClaimAttestation::MatchFields const toMatch{ - sendingAmount, wasLockingChainSend, std::nullopt}; - return claimHelper(attestations, view, toMatch, CheckDst::Ignore, quorum, signersList, j); -} - -enum class CanCreateDstPolicy { No, Yes }; - -enum class DepositAuthPolicy { Normal, DstCanBypass }; - -// Allow the fee to dip into the reserve. To support this, information about the -// submitting account needs to be fed to the transfer helper. -struct TransferHelperSubmittingAccountInfo -{ - AccountID account; - STAmount preFeeBalance; - STAmount postFeeBalance; -}; - -/** Transfer funds from the src account to the dst account - - @param psb The payment sandbox. - @param src The source of funds. - @param dst The destination for funds. - @param dstTag Integer destination tag. Used to check if funds should be - transferred to an account with a `RequireDstTag` flag set. - @param claimOwner Owner of the claim ledger object. - @param amt Amount to transfer from the src account to the dst account. - @param canCreate Flag to determine if accounts may be created using this - transfer. - @param depositAuthPolicy Flag to determine if dst can bypass deposit auth if - it is also the claim owner. - @param submittingAccountInfo If the transaction is allowed to dip into the - reserve to pay fees, then this optional will be seated ("commit" - transactions support this, other transactions should not). - @param j Log - - @return tesSUCCESS if payment succeeds, otherwise the error code for the - failure reason. - */ - -TER -transferHelper( - PaymentSandbox& psb, - AccountID const& src, - AccountID const& dst, - std::optional const& dstTag, - std::optional const& claimOwner, - STAmount const& amt, - CanCreateDstPolicy canCreate, - DepositAuthPolicy depositAuthPolicy, - std::optional const& submittingAccountInfo, - beast::Journal j) -{ - if (dst == src) - return tesSUCCESS; - - auto const dstK = keylet::account(dst); - if (auto sleDst = psb.read(dstK)) - { - // Check dst tag and deposit auth - - if (sleDst->isFlag(lsfRequireDestTag) && !dstTag) - return tecDST_TAG_NEEDED; - - // If the destination is the claim owner, and this is a claim - // transaction, that's the dst account sending funds to itself. It - // can bypass deposit auth. - bool const canBypassDepositAuth = - dst == claimOwner && depositAuthPolicy == DepositAuthPolicy::DstCanBypass; - - if (!canBypassDepositAuth && sleDst->isFlag(lsfDepositAuth) && - !psb.exists(keylet::depositPreauth(dst, src))) - { - return tecNO_PERMISSION; - } - } - else if (!amt.native() || canCreate == CanCreateDstPolicy::No) - { - return tecNO_DST; - } - - if (amt.native()) - { - auto const sleSrc = psb.peek(keylet::account(src)); - XRPL_ASSERT(sleSrc, "xrpl::transferHelper : non-null source account"); - if (!sleSrc) - return tecINTERNAL; // LCOV_EXCL_LINE - - { - auto const reserve = accountReserve(psb, sleSrc, j); - - auto const availableBalance = [&]() -> STAmount { - STAmount curBal = (*sleSrc)[sfBalance]; - // Checking that account == src and postFeeBalance == curBal is - // not strictly necessary, but helps protect against future - // changes - if (!submittingAccountInfo || submittingAccountInfo->account != src || - submittingAccountInfo->postFeeBalance != curBal) - return curBal; - return submittingAccountInfo->preFeeBalance; - }(); - - if (availableBalance < amt + reserve) - { - return tecUNFUNDED_PAYMENT; - } - } - - auto sleDst = psb.peek(dstK); - if (!sleDst) - { - if (canCreate == CanCreateDstPolicy::No) - { - // Already checked, but OK to check again - return tecNO_DST; - } - if (amt < psb.fees().reserve) - { - JLOG(j.trace()) << "Insufficient payment to create account."; - return tecNO_DST_INSUF_XRP; - } - - // Create the account. - sleDst = std::make_shared(dstK); - sleDst->setAccountID(sfAccount, dst); - sleDst->setFieldU32(sfSequence, psb.seq()); - - psb.insert(sleDst); - } - - (*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt; - (*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt; - psb.update(sleSrc); - psb.update(sleDst); - - return tesSUCCESS; - } - - auto const result = flow( - psb, - amt, - src, - dst, - STPathSet{}, - /*default path*/ true, - /*partial payment*/ false, - /*owner pays transfer fee*/ true, - /*offer crossing*/ OfferCrossing::No, - /*limit quality*/ std::nullopt, - /*sendmax*/ std::nullopt, - /*domain id*/ std::nullopt, - j); - - if (auto const r = result.result(); isTesSuccess(r) || isTecClaim(r) || isTerRetry(r)) - return r; - return tecXCHAIN_PAYMENT_FAILED; -} - -/** Action to take when the transfer from the door account to the dst fails - - @note This is useful to prevent a failed "create account" transaction from - blocking subsequent "create account" transactions. -*/ -enum class OnTransferFail { - /** Remove the claim even if the transfer fails */ - RemoveClaim, - /** Keep the claim if the transfer fails */ - KeepClaim -}; - -struct FinalizeClaimHelperResult -{ - /// TER for transfering the payment funds - std::optional mainFundsTer; - // TER for transfering the reward funds - std::optional rewardTer; - // TER for removing the sle (if is sle is to be removed) - std::optional rmSleTer; - - // Helper to check for overall success. If there wasn't overall success the - // individual ters can be used to decide what needs to be done. - [[nodiscard]] bool - isTesSuccess() const - { - return (!mainFundsTer || xrpl::isTesSuccess(*mainFundsTer)) && - (!rewardTer || xrpl::isTesSuccess(*rewardTer)) && - (!rmSleTer || xrpl::isTesSuccess(*rmSleTer)); - } - - [[nodiscard]] TER - ter() const - { - if (isTesSuccess()) - return tesSUCCESS; - - // if any phase return a tecINTERNAL or a tef, prefer returning those - // codes - if (mainFundsTer && (isTefFailure(*mainFundsTer) || *mainFundsTer == tecINTERNAL)) - return *mainFundsTer; - if (rewardTer && (isTefFailure(*rewardTer) || *rewardTer == tecINTERNAL)) - return *rewardTer; - if (rmSleTer && (isTefFailure(*rmSleTer) || *rmSleTer == tecINTERNAL)) - return *rmSleTer; - - // Only after the tecINTERNAL and tef are checked, return the first - // non-success error code. - if (mainFundsTer && !xrpl::isTesSuccess(*mainFundsTer)) - return *mainFundsTer; - if (rewardTer && !xrpl::isTesSuccess(*rewardTer)) - return *rewardTer; - if (rmSleTer && !xrpl::isTesSuccess(*rmSleTer)) - return *rmSleTer; - return tesSUCCESS; - } -}; - -/** Transfer funds from the door account to the dst and distribute rewards - - @param psb The payment sandbox. - @param bridgeSpc Bridge - @param dst The destination for funds. - @param dstTag Integer destination tag. Used to check if funds should be - transferred to an account with a `RequireDstTag` flag set. - @param claimOwner Owner of the claim ledger object. - @param sendingAmount Amount that was committed on the source chain. - @param rewardPoolSrc Source of the funds for the reward pool (claim owner). - @param rewardPool Amount to split among the rewardAccounts. - @param rewardAccounts Account to receive the reward pool. - @param srcChain Chain where the commit event occurred. - @param sleClaimID sle for the claim id (may be NULL or XChainClaimID or - XChainCreateAccountClaimID). Don't read fields that aren't in common - with those two types and always check for NULL. Remove on success (if - not null). Remove on fail if the onTransferFail flag is removeClaim. - @param onTransferFail Flag to determine if the claim is removed on transfer - failure. This is used for create account transactions where claims - are removed so they don't block future txns. - @param j Log - - @return FinalizeClaimHelperResult. See the comments in this struct for what - the fields mean. The individual ters need to be returned instead of - an overall ter because the caller needs this information if the - attestation list changed or not. -*/ - -FinalizeClaimHelperResult -finalizeClaimHelper( - PaymentSandbox& outerSb, - STXChainBridge const& bridgeSpec, - AccountID const& dst, - std::optional const& dstTag, - AccountID const& claimOwner, - STAmount const& sendingAmount, - AccountID const& rewardPoolSrc, - STAmount const& rewardPool, - std::vector const& rewardAccounts, - STXChainBridge::ChainType const srcChain, - Keylet const& claimIDKeylet, - OnTransferFail onTransferFail, - DepositAuthPolicy depositAuthPolicy, - beast::Journal j) -{ - FinalizeClaimHelperResult result; - - STXChainBridge::ChainType const dstChain = STXChainBridge::otherChain(srcChain); - STAmount const thisChainAmount = [&] { - STAmount r = sendingAmount; - r.setIssue(bridgeSpec.issue(dstChain)); - return r; - }(); - auto const& thisDoor = bridgeSpec.door(dstChain); - - { - PaymentSandbox innerSb{&outerSb}; - // If distributing the reward pool fails, the mainFunds transfer should - // be rolled back - // - // If the claim ID is removed, the rewards should be distributed - // even if the mainFunds fails. - // - // If OnTransferFail::removeClaim, the claim should be removed even if - // the rewards cannot be distributed. - - // transfer funds to the dst - result.mainFundsTer = transferHelper( - innerSb, - thisDoor, - dst, - dstTag, - claimOwner, - thisChainAmount, - CanCreateDstPolicy::Yes, - depositAuthPolicy, - std::nullopt, - j); - - if (!isTesSuccess(*result.mainFundsTer) && onTransferFail == OnTransferFail::KeepClaim) - { - return result; - } - - // handle the reward pool - result.rewardTer = [&]() -> TER { - if (rewardAccounts.empty()) - return tesSUCCESS; - - // distribute the reward pool - // if the transfer failed, distribute the pool for "OnTransferFail" - // cases (the attesters did their job) - STAmount const share = [&] { - auto const roundMode = innerSb.rules().enabled(fixXChainRewardRounding) - ? Number::RoundingMode::Downward - : Number::getround(); - SaveNumberRoundMode const _{Number::setround(roundMode)}; - - STAmount const den{rewardAccounts.size()}; - return divide(rewardPool, den, rewardPool.asset()); - }(); - STAmount distributed = rewardPool.zeroed(); - for (auto const& rewardAccount : rewardAccounts) - { - auto const thTer = transferHelper( - innerSb, - rewardPoolSrc, - rewardAccount, - /*dstTag*/ std::nullopt, - // claim owner is not relevant to distributing rewards - /*claimOwner*/ std::nullopt, - share, - CanCreateDstPolicy::No, - DepositAuthPolicy::Normal, - std::nullopt, - j); - - if (thTer == tecUNFUNDED_PAYMENT || thTer == tecINTERNAL) - return thTer; - - if (isTesSuccess(thTer)) - distributed += share; - - // let txn succeed if error distributing rewards (other than - // inability to pay) - } - - if (distributed > rewardPool) - return tecINTERNAL; // LCOV_EXCL_LINE - - return tesSUCCESS; - }(); - - if (!isTesSuccess(*result.rewardTer) && - (onTransferFail == OnTransferFail::KeepClaim || *result.rewardTer == tecINTERNAL)) - { - return result; - } - - if (!isTesSuccess(*result.mainFundsTer) || isTesSuccess(*result.rewardTer)) - { - // Note: if the mainFunds transfer succeeds and the result transfer - // fails, we don't apply the inner sandbox (i.e. the mainTransfer is - // rolled back) - innerSb.apply(outerSb); - } - } - - if (auto const sleClaimID = outerSb.peek(claimIDKeylet)) - { - auto const cidOwner = (*sleClaimID)[sfAccount]; - { - // Remove the claim id - auto const sleOwner = outerSb.peek(keylet::account(cidOwner)); - auto const page = (*sleClaimID)[sfOwnerNode]; - if (!outerSb.dirRemove(keylet::ownerDir(cidOwner), page, sleClaimID->key(), true)) - { - JLOG(j.fatal()) << "Unable to delete xchain seq number from owner."; - result.rmSleTer = tefBAD_LEDGER; - return result; - } - - // Remove the claim id from the ledger - decreaseOwnerCountForObject(outerSb, sleOwner, sleClaimID, 1, j); - outerSb.erase(sleClaimID); - } - } - - return result; -} - -/** Get signers list corresponding to the account that owns the bridge - - @param view View to read the signer's list from. - @param sleBridge Sle of the bridge. - @param j Log - - @return map of the signer's list (AccountIDs and weights), the quorum, and - error code -*/ -std::tuple, std::uint32_t, TER> -getSignersListAndQuorum(ReadView const& view, SLE const& sleBridge, beast::Journal j) -{ - std::unordered_map r; - std::uint32_t q = std::numeric_limits::max(); - - AccountID const thisDoor = sleBridge[sfAccount]; - auto const sleDoor = [&] { return view.read(keylet::account(thisDoor)); }(); - - if (!sleDoor) - { - return {r, q, tecINTERNAL}; - } - - auto const sleS = view.read(keylet::signerList(sleBridge[sfAccount])); - if (!sleS) - { - return {r, q, tecXCHAIN_NO_SIGNERS_LIST}; - } - q = (*sleS)[sfSignerQuorum]; - - auto const accountSigners = SignerEntries::deserialize(*sleS, j, "ledger"); - - if (!accountSigners) - { - return {r, q, tecINTERNAL}; - } - - for (auto const& as : *accountSigners) - { - r[as.account] = as.weight; - } - - return {std::move(r), q, tesSUCCESS}; -}; - -template -std::shared_ptr -readOrpeekBridge(F&& getter, STXChainBridge const& bridgeSpec) -{ - auto tryGet = [&](STXChainBridge::ChainType ct) -> std::shared_ptr { - if (auto r = getter(bridgeSpec, ct)) - { - if ((*r)[sfXChainBridge] == bridgeSpec) - return r; - } - return nullptr; - }; - if (auto r = tryGet(STXChainBridge::ChainType::Locking)) - return r; - return tryGet(STXChainBridge::ChainType::Issuing); -} - -SLE::pointer -peekBridge(ApplyView& v, STXChainBridge const& bridgeSpec) -{ - return readOrpeekBridge( - [&v](STXChainBridge const& b, STXChainBridge::ChainType ct) -> SLE::pointer { - return v.peek(keylet::bridge(b, ct)); - }, - bridgeSpec); -} - -SLE::const_pointer -readBridge(ReadView const& v, STXChainBridge const& bridgeSpec) -{ - return readOrpeekBridge( - [&v](STXChainBridge const& b, STXChainBridge::ChainType ct) -> SLE::const_pointer { - return v.read(keylet::bridge(b, ct)); - }, - bridgeSpec); -} - -// Precondition: all the claims in the range are consistent. They must sign for -// the same event (amount, sending account, claim id, etc). -template -TER -applyClaimAttestations( - ApplyView& view, - RawView& rawView, - TIter attBegin, - TIter attEnd, - STXChainBridge const& bridgeSpec, - STXChainBridge::ChainType const srcChain, - std::unordered_map const& signersList, - std::uint32_t quorum, - beast::Journal j) -{ - if (attBegin == attEnd) - return tesSUCCESS; - - PaymentSandbox psb(&view); - - auto const claimIDKeylet = keylet::xChainClaimID(bridgeSpec, attBegin->claimID); - - struct ScopeResult - { - OnNewAttestationResult newAttResult; - STAmount rewardAmount; - AccountID cidOwner; - }; - - auto const scopeResult = [&]() -> std::expected { - // This lambda is ugly - admittedly. The purpose of this lambda is to - // limit the scope of sles so they don't overlap with - // `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child - // views, it's important that the sle's lifetime doesn't overlap. - auto const sleClaimID = psb.peek(claimIDKeylet); - if (!sleClaimID) - return std::unexpected(tecXCHAIN_NO_CLAIM_ID); - - // Add claims that are part of the signer's list to the "claims" vector - std::vector atts; - atts.reserve(std::distance(attBegin, attEnd)); - for (auto att = attBegin; att != attEnd; ++att) - { - if (!signersList.contains(att->attestationSignerAccount)) - continue; - atts.push_back(*att); - } - - if (atts.empty()) - { - return std::unexpected(tecXCHAIN_PROOF_UNKNOWN_KEY); - } - - AccountID const otherChainSource = (*sleClaimID)[sfOtherChainSource]; - if (attBegin->sendingAccount != otherChainSource) - { - return std::unexpected(tecXCHAIN_SENDING_ACCOUNT_MISMATCH); - } - - { - STXChainBridge::ChainType const dstChain = STXChainBridge::otherChain(srcChain); - - STXChainBridge::ChainType const attDstChain = - STXChainBridge::dstChain(attBegin->wasLockingChainSend); - - if (attDstChain != dstChain) - { - return std::unexpected(tecXCHAIN_WRONG_CHAIN); - } - } - - XChainClaimAttestations curAtts{sleClaimID->getFieldArray(sfXChainClaimAttestations)}; - - auto const newAttResult = onNewAttestations( - curAtts, - view, - &atts[0], - &atts[0] + atts.size(), // NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object) - quorum, - signersList, - j); - - // update the claim id - sleClaimID->setFieldArray(sfXChainClaimAttestations, curAtts.toSTArray()); - psb.update(sleClaimID); - - return ScopeResult{ - newAttResult, (*sleClaimID)[sfSignatureReward], (*sleClaimID)[sfAccount]}; - }(); - - if (!scopeResult.has_value()) - return scopeResult.error(); - - auto const& [newAttResult, rewardAmount, cidOwner] = scopeResult.value(); - auto const& [rewardAccounts, attListChanged] = newAttResult; - if (rewardAccounts && attBegin->dst) - { - auto const r = finalizeClaimHelper( - psb, - bridgeSpec, - *attBegin->dst, - /*dstTag*/ std::nullopt, - cidOwner, - attBegin->sendingAmount, - cidOwner, - rewardAmount, - *rewardAccounts, - srcChain, - claimIDKeylet, - OnTransferFail::KeepClaim, - DepositAuthPolicy::Normal, - j); - - auto const rTer = r.ter(); - - if (!isTesSuccess(rTer) && - (!attListChanged || rTer == tecINTERNAL || rTer == tefBAD_LEDGER)) - return rTer; - } - - psb.apply(rawView); - - return tesSUCCESS; -} - -template -TER -applyCreateAccountAttestations( - ApplyView& view, - RawView& rawView, - TIter attBegin, - TIter attEnd, - AccountID const& doorAccount, - Keylet const& doorK, - STXChainBridge const& bridgeSpec, - Keylet const& bridgeK, - STXChainBridge::ChainType const srcChain, - std::unordered_map const& signersList, - std::uint32_t quorum, - beast::Journal j) -{ - if (attBegin == attEnd) - return tesSUCCESS; - - PaymentSandbox psb(&view); - - auto const claimCountResult = [&]() -> std::expected { - auto const sleBridge = psb.peek(bridgeK); - if (!sleBridge) - return std::unexpected(tecINTERNAL); - - return (*sleBridge)[sfXChainAccountClaimCount]; - }(); - - if (!claimCountResult.has_value()) - return claimCountResult.error(); - - std::uint64_t const claimCount = claimCountResult.value(); - - if (attBegin->createCount <= claimCount) - { - return tecXCHAIN_ACCOUNT_CREATE_PAST; - } - if (attBegin->createCount >= claimCount + kXbridgeMaxAccountCreateClaims) - { - // Limit the number of claims on the account - return tecXCHAIN_ACCOUNT_CREATE_TOO_MANY; - } - - { - STXChainBridge::ChainType const dstChain = STXChainBridge::otherChain(srcChain); - - STXChainBridge::ChainType const attDstChain = - STXChainBridge::dstChain(attBegin->wasLockingChainSend); - - if (attDstChain != dstChain) - { - return tecXCHAIN_WRONG_CHAIN; - } - } - - auto const claimIDKeylet = - keylet::xChainCreateAccountClaimID(bridgeSpec, attBegin->createCount); - - struct ScopeResult - { - OnNewAttestationResult newAttResult; - bool createCID{}; - XChainCreateAccountAttestations curAtts; - }; - - auto const scopeResult = [&]() -> std::expected { - // This lambda is ugly - admittedly. The purpose of this lambda is to - // limit the scope of sles so they don't overlap with - // `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child - // views, it's important that the sle's lifetime doesn't overlap. - - // sleClaimID may be null. If it's null it isn't created until the end - // of this function (if needed) - auto const sleClaimID = psb.peek(claimIDKeylet); - bool createCID = false; - if (!sleClaimID) - { - createCID = true; - - auto const sleDoor = psb.peek(doorK); - if (!sleDoor) - return std::unexpected(tecINTERNAL); - - // Check reserve - auto const balance = (*sleDoor)[sfBalance]; - auto const reserve = accountReserve(psb, sleDoor, j, {.ownerCountDelta = 1}); - - if (balance < reserve) - return std::unexpected(tecINSUFFICIENT_RESERVE); - } - - std::vector atts; - atts.reserve(std::distance(attBegin, attEnd)); - for (auto att = attBegin; att != attEnd; ++att) - { - if (!signersList.contains(att->attestationSignerAccount)) - continue; - atts.push_back(*att); - } - if (atts.empty()) - { - return std::unexpected(tecXCHAIN_PROOF_UNKNOWN_KEY); - } - - XChainCreateAccountAttestations curAtts = [&] { - if (sleClaimID) - { - return XChainCreateAccountAttestations{ - sleClaimID->getFieldArray(sfXChainCreateAccountAttestations)}; - } - return XChainCreateAccountAttestations{}; - }(); - - auto const newAttResult = onNewAttestations( - curAtts, - view, - &atts[0], - &atts[0] + atts.size(), // NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object) - quorum, - signersList, - j); - - if (!createCID) - { - // Modify the object before it's potentially deleted, so the meta - // data will include the new attestations - if (!sleClaimID) - return std::unexpected(tecINTERNAL); - sleClaimID->setFieldArray(sfXChainCreateAccountAttestations, curAtts.toSTArray()); - psb.update(sleClaimID); - } - return ScopeResult{newAttResult, createCID, curAtts}; - }(); - - if (!scopeResult.has_value()) - return scopeResult.error(); - - auto const& [attResult, createCID, curAtts] = scopeResult.value(); - auto const& [rewardAccounts, attListChanged] = attResult; - - // Account create transactions must happen in order - if (rewardAccounts && claimCount + 1 == attBegin->createCount) - { - auto const r = finalizeClaimHelper( - psb, - bridgeSpec, - attBegin->toCreate, - /*dstTag*/ std::nullopt, - doorAccount, - attBegin->sendingAmount, - /*rewardPoolSrc*/ doorAccount, - attBegin->rewardAmount, - *rewardAccounts, - srcChain, - claimIDKeylet, - OnTransferFail::RemoveClaim, - DepositAuthPolicy::Normal, - j); - - auto const rTer = r.ter(); - - if (!isTesSuccess(rTer)) - { - if (rTer == tecINTERNAL || rTer == tecUNFUNDED_PAYMENT || isTefFailure(rTer)) - return rTer; - } - // Move past this claim id even if it fails, so it doesn't block - // subsequent claim ids - auto const sleBridge = psb.peek(bridgeK); - if (!sleBridge) - return tecINTERNAL; // LCOV_EXCL_LINE - (*sleBridge)[sfXChainAccountClaimCount] = attBegin->createCount; - psb.update(sleBridge); - } - else if (createCID) - { - auto const createdSleClaimID = std::make_shared(claimIDKeylet); - (*createdSleClaimID)[sfAccount] = doorAccount; - (*createdSleClaimID)[sfXChainBridge] = bridgeSpec; - (*createdSleClaimID)[sfXChainAccountCreateCount] = attBegin->createCount; - createdSleClaimID->setFieldArray(sfXChainCreateAccountAttestations, curAtts.toSTArray()); - - // Add to owner directory of the door account - auto const page = psb.dirInsert( - keylet::ownerDir(doorAccount), claimIDKeylet, describeOwnerDir(doorAccount)); - if (!page) - return tecDIR_FULL; // LCOV_EXCL_LINE - (*createdSleClaimID)[sfOwnerNode] = *page; - - auto const sleDoor = psb.peek(doorK); - if (!sleDoor) - return tecINTERNAL; // LCOV_EXCL_LINE - - // Reserve was already checked - increaseOwnerCount(psb, sleDoor, {}, 1, j); - psb.insert(createdSleClaimID); - psb.update(sleDoor); - } - - psb.apply(rawView); - - return tesSUCCESS; -} - -template -std::optional -toClaim(STTx const& tx) -{ - static_assert( - std::is_same_v || - std::is_same_v); - - try - { - // Copy just the field bag out of the transaction (explicitly, via the - // STObject base) so it can be reinterpreted as a cross-chain attestation - // below, with sfAccount replaced by sfOtherChainSource. STTx-specific - // state (txType_, tid_) is intentionally not needed here. - STObject o{static_cast(tx)}; - o.setAccountID(sfAccount, o[sfOtherChainSource]); - return TAttestation(o); - } - catch (...) - { - return std::nullopt; - } -} - -template -NotTEC -attestationPreflight(PreflightContext const& ctx) -{ - if (!publicKeyType(ctx.tx[sfPublicKey])) - return temMALFORMED; - - auto const att = toClaim(ctx.tx); - if (!att) - return temMALFORMED; - - STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; - if (!att->verify(bridgeSpec)) - return temXCHAIN_BAD_PROOF; - if (!att->validAmounts()) - return temXCHAIN_BAD_PROOF; - - if (att->sendingAmount.signum() <= 0) - return temXCHAIN_BAD_PROOF; - auto const expectedIssue = bridgeSpec.issue(STXChainBridge::srcChain(att->wasLockingChainSend)); - if (att->sendingAmount.asset() != expectedIssue) - return temXCHAIN_BAD_PROOF; - - return tesSUCCESS; -} - -template -TER -attestationPreclaim(PreclaimContext const& ctx) -{ - auto const att = toClaim(ctx.tx); - // checked in preflight - if (!att) - return tecINTERNAL; // LCOV_EXCL_LINE - - STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; - auto const sleBridge = readBridge(ctx.view, bridgeSpec); - if (!sleBridge) - { - return tecNO_ENTRY; - } - - AccountID const attestationSignerAccount{ctx.tx[sfAttestationSignerAccount]}; - PublicKey const pk{ctx.tx[sfPublicKey]}; - - // signersList is a map from account id to weights - auto const [signersList, quorum, slTer] = getSignersListAndQuorum(ctx.view, *sleBridge, ctx.j); - - if (!isTesSuccess(slTer)) - return slTer; - - return checkAttestationPublicKey(ctx.view, signersList, attestationSignerAccount, pk, ctx.j); -} - -template -TER -attestationDoApply(ApplyContext& ctx) -{ - auto const att = toClaim(ctx.tx); - if (!att) - { - // Should already be checked in preflight - return tecINTERNAL; // LCOV_EXCL_LINE - } - - STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; - - struct ScopeResult - { - STXChainBridge::ChainType srcChain = STXChainBridge::ChainType::Locking; - std::unordered_map signersList; - std::uint32_t quorum{}; - AccountID thisDoor; - Keylet bridgeK; - }; - - auto const scopeResult = [&]() -> std::expected { - // This lambda is ugly - admittedly. The purpose of this lambda is to - // limit the scope of sles so they don't overlap with - // `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child - // views, it's important that the sle's lifetime doesn't overlap. - auto sleBridge = readBridge(ctx.view(), bridgeSpec); - if (!sleBridge) - { - return std::unexpected(tecNO_ENTRY); - } - Keylet const bridgeK{ltBRIDGE, sleBridge->key()}; - AccountID const thisDoor = (*sleBridge)[sfAccount]; - - STXChainBridge::ChainType dstChain = STXChainBridge::ChainType::Locking; - { - if (thisDoor == bridgeSpec.lockingChainDoor()) - { - dstChain = STXChainBridge::ChainType::Locking; - } - else if (thisDoor == bridgeSpec.issuingChainDoor()) - { - dstChain = STXChainBridge::ChainType::Issuing; - } - else - { - return std::unexpected(tecINTERNAL); - } - } - STXChainBridge::ChainType const srcChain = STXChainBridge::otherChain(dstChain); - - // signersList is a map from account id to weights - auto [signersList, quorum, slTer] = - getSignersListAndQuorum(ctx.view(), *sleBridge, ctx.journal); - - if (!isTesSuccess(slTer)) - return std::unexpected(slTer); - - return ScopeResult{srcChain, std::move(signersList), quorum, thisDoor, bridgeK}; - }(); - - if (!scopeResult.has_value()) - return scopeResult.error(); - - auto const& [srcChain, signersList, quorum, thisDoor, bridgeK] = scopeResult.value(); - - static_assert( - std::is_same_v || - std::is_same_v); - - if constexpr (std::is_same_v) - { - return applyClaimAttestations( - ctx.view(), - ctx.rawView(), - &*att, - &*att + 1, - bridgeSpec, - srcChain, - signersList, - quorum, - ctx.journal); - } - else if constexpr (std::is_same_v) - { - return applyCreateAccountAttestations( - ctx.view(), - ctx.rawView(), - &*att, - &*att + 1, - thisDoor, - keylet::account(thisDoor), - bridgeSpec, - bridgeK, - srcChain, - signersList, - quorum, - ctx.journal); - } -} - -} // namespace -//------------------------------------------------------------------------------ - -NotTEC -XChainCreateBridge::preflight(PreflightContext const& ctx) -{ - auto const account = ctx.tx[sfAccount]; - auto const reward = ctx.tx[sfSignatureReward]; - auto const minAccountCreate = ctx.tx[~sfMinAccountCreateAmount]; - auto const bridgeSpec = ctx.tx[sfXChainBridge]; - // Doors must be distinct to help prevent transaction replay attacks - if (bridgeSpec.lockingChainDoor() == bridgeSpec.issuingChainDoor()) - { - return temXCHAIN_EQUAL_DOOR_ACCOUNTS; - } - - if (bridgeSpec.lockingChainDoor() != account && bridgeSpec.issuingChainDoor() != account) - { - return temXCHAIN_BRIDGE_NONDOOR_OWNER; - } - - if (isXRP(bridgeSpec.lockingChainIssue()) != isXRP(bridgeSpec.issuingChainIssue())) - { - // Because ious and xrp have different numeric ranges, both the src and - // dst issues must be both XRP or both IOU. - return temXCHAIN_BRIDGE_BAD_ISSUES; - } - - if (!isXRP(reward) || reward.signum() < 0) - { - return temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT; - } - - if (minAccountCreate && - ((!isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) || - !isXRP(bridgeSpec.lockingChainIssue()) || !isXRP(bridgeSpec.issuingChainIssue()))) - { - return temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT; - } - - if (isXRP(bridgeSpec.issuingChainIssue())) - { - // Issuing account must be the root account for XRP (which presumably - // owns all the XRP). This is done so the issuing account can't "run - // out" of wrapped tokens. - static auto const kRootAccount = calcAccountID( - generateKeyPair(KeyType::Secp256k1, generateSeed("masterpassphrase")).first); - if (bridgeSpec.issuingChainDoor() != kRootAccount) - { - return temXCHAIN_BRIDGE_BAD_ISSUES; - } - } - else - { - // Issuing account must be the issuer for non-XRP. This is done so the - // issuing account can't "run out" of wrapped tokens. - if (bridgeSpec.issuingChainDoor() != bridgeSpec.issuingChainIssue().account) - { - return temXCHAIN_BRIDGE_BAD_ISSUES; - } - } - - if (bridgeSpec.lockingChainDoor() == bridgeSpec.lockingChainIssue().account) - { - // If the locking chain door is locking their own asset, in some sense - // nothing is being locked. Disallow this. - return temXCHAIN_BRIDGE_BAD_ISSUES; - } - - return tesSUCCESS; -} - -TER -XChainCreateBridge::preclaim(PreclaimContext const& ctx) -{ - auto const account = ctx.tx[sfAccount]; - auto const bridgeSpec = ctx.tx[sfXChainBridge]; - STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); - - { - auto hasBridge = [&](STXChainBridge::ChainType ct) -> bool { - return ctx.view.exists(keylet::bridge(bridgeSpec, ct)); - }; - - if (hasBridge(STXChainBridge::ChainType::Issuing) || - hasBridge(STXChainBridge::ChainType::Locking)) - { - return tecDUPLICATE; - } - } - - if (!isXRP(bridgeSpec.issue(chainType))) - { - auto const sleIssuer = ctx.view.read(keylet::account(bridgeSpec.issue(chainType).account)); - - if (!sleIssuer) - return tecNO_ISSUER; - - // Allowing clawing back funds would break the bridge's invariant that - // wrapped funds are always backed by locked funds - if (sleIssuer->isFlag(lsfAllowTrustLineClawback)) - return tecNO_PERMISSION; - } - - { - // Check reserve - auto const sleAcc = ctx.view.read(keylet::account(account)); - if (!sleAcc) - return terNO_ACCOUNT; - - auto const balance = (*sleAcc)[sfBalance]; - auto const reserve = accountReserve(ctx.view, sleAcc, ctx.j, {.ownerCountDelta = 1}); - - if (balance < reserve) - return tecINSUFFICIENT_RESERVE; - } - - return tesSUCCESS; -} - -TER -XChainCreateBridge::doApply() -{ - auto const account = ctx_.tx[sfAccount]; - auto const bridgeSpec = ctx_.tx[sfXChainBridge]; - auto const reward = ctx_.tx[sfSignatureReward]; - auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount]; - - auto const sleAcct = ctx_.view().peek(keylet::account(account)); - if (!sleAcct) - return tecINTERNAL; // LCOV_EXCL_LINE - - STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); - - Keylet const bridgeKeylet = keylet::bridge(bridgeSpec, chainType); - auto const sleBridge = std::make_shared(bridgeKeylet); - - (*sleBridge)[sfAccount] = account; - (*sleBridge)[sfSignatureReward] = reward; - if (minAccountCreate) - (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate; - (*sleBridge)[sfXChainBridge] = bridgeSpec; - (*sleBridge)[sfXChainClaimID] = 0; - (*sleBridge)[sfXChainAccountCreateCount] = 0; - (*sleBridge)[sfXChainAccountClaimCount] = 0; - - // Add to owner directory - { - auto const page = ctx_.view().dirInsert( - keylet::ownerDir(account), bridgeKeylet, describeOwnerDir(account)); - if (!page) - return tecDIR_FULL; // LCOV_EXCL_LINE - (*sleBridge)[sfOwnerNode] = *page; - } - - increaseOwnerCount(ctx_.view(), sleAcct, {}, 1, ctx_.journal); - - ctx_.view().insert(sleBridge); - ctx_.view().update(sleAcct); - - return tesSUCCESS; -} - -//------------------------------------------------------------------------------ - -std::uint32_t -BridgeModify::getFlagsMask(PreflightContext const& ctx) -{ - return tfXChainModifyBridgeMask; -} - -NotTEC -BridgeModify::preflight(PreflightContext const& ctx) -{ - auto const account = ctx.tx[sfAccount]; - auto const reward = ctx.tx[~sfSignatureReward]; - auto const minAccountCreate = ctx.tx[~sfMinAccountCreateAmount]; - auto const bridgeSpec = ctx.tx[sfXChainBridge]; - bool const clearAccountCreate = ctx.tx.isFlag(tfClearAccountCreateAmount); - - if (!reward && !minAccountCreate && !clearAccountCreate) - { - // Must change something - return temMALFORMED; - } - - if (minAccountCreate && clearAccountCreate) - { - // Can't both clear and set account create in the same txn - return temMALFORMED; - } - - if (bridgeSpec.lockingChainDoor() != account && bridgeSpec.issuingChainDoor() != account) - { - return temXCHAIN_BRIDGE_NONDOOR_OWNER; - } - - if (reward && (!isXRP(*reward) || reward->signum() < 0)) - { - return temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT; - } - - if (minAccountCreate && - ((!isXRP(*minAccountCreate) || minAccountCreate->signum() <= 0) || - !isXRP(bridgeSpec.lockingChainIssue()) || !isXRP(bridgeSpec.issuingChainIssue()))) - { - return temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT; - } - - return tesSUCCESS; -} - -TER -BridgeModify::preclaim(PreclaimContext const& ctx) -{ - auto const account = ctx.tx[sfAccount]; - auto const bridgeSpec = ctx.tx[sfXChainBridge]; - - STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); - - if (!ctx.view.read(keylet::bridge(bridgeSpec, chainType))) - { - return tecNO_ENTRY; - } - - return tesSUCCESS; -} - -TER -BridgeModify::doApply() -{ - auto const account = ctx_.tx[sfAccount]; - auto const bridgeSpec = ctx_.tx[sfXChainBridge]; - auto const reward = ctx_.tx[~sfSignatureReward]; - auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount]; - bool const clearAccountCreate = ctx_.tx.isFlag(tfClearAccountCreateAmount); - - auto const sleAcct = ctx_.view().peek(keylet::account(account)); - if (!sleAcct) - return tecINTERNAL; // LCOV_EXCL_LINE - - STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); - - auto const sleBridge = ctx_.view().peek(keylet::bridge(bridgeSpec, chainType)); - if (!sleBridge) - return tecINTERNAL; // LCOV_EXCL_LINE - - if (reward) - (*sleBridge)[sfSignatureReward] = *reward; - if (minAccountCreate) - { - (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate; - } - if (clearAccountCreate && sleBridge->isFieldPresent(sfMinAccountCreateAmount)) - { - sleBridge->makeFieldAbsent(sfMinAccountCreateAmount); - } - ctx_.view().update(sleBridge); - - return tesSUCCESS; -} - -//------------------------------------------------------------------------------ - -NotTEC -XChainClaim::preflight(PreflightContext const& ctx) -{ - STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; - auto const amount = ctx.tx[sfAmount]; - - if (amount.signum() <= 0 || - (amount.asset() != bridgeSpec.lockingChainIssue() && - amount.asset() != bridgeSpec.issuingChainIssue())) - { - return temBAD_AMOUNT; - } - - return tesSUCCESS; -} - -TER -XChainClaim::preclaim(PreclaimContext const& ctx) -{ - AccountID const account = ctx.tx[sfAccount]; - STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; - STAmount const& thisChainAmount = ctx.tx[sfAmount]; - auto const claimID = ctx.tx[sfXChainClaimID]; - - auto const sleBridge = readBridge(ctx.view, bridgeSpec); - if (!sleBridge) - { - return tecNO_ENTRY; - } - - if (!ctx.view.read(keylet::account(ctx.tx[sfDestination]))) - { - return tecNO_DST; - } - - auto const thisDoor = (*sleBridge)[sfAccount]; - bool isLockingChain = false; - { - if (thisDoor == bridgeSpec.lockingChainDoor()) - { - isLockingChain = true; - } - else if (thisDoor == bridgeSpec.issuingChainDoor()) - { - isLockingChain = false; - } - else - { - return tecINTERNAL; // LCOV_EXCL_LINE - } - } - - { - // Check that the amount specified matches the expected issue - - if (isLockingChain) - { - if (bridgeSpec.lockingChainIssue() != thisChainAmount.asset()) - return tecXCHAIN_BAD_TRANSFER_ISSUE; - } - else - { - if (bridgeSpec.issuingChainIssue() != thisChainAmount.asset()) - return tecXCHAIN_BAD_TRANSFER_ISSUE; - } - } - - if (isXRP(bridgeSpec.lockingChainIssue()) != isXRP(bridgeSpec.issuingChainIssue())) - { - // Should have been caught when creating the bridge - // Detect here so `otherChainAmount` doesn't switch from IOU -> XRP - // and the numeric issues that need to be addressed with that. - return tecINTERNAL; // LCOV_EXCL_LINE - } - - auto const otherChainAmount = [&]() -> STAmount { - STAmount r(thisChainAmount); - if (isLockingChain) - { - r.setIssue(bridgeSpec.issuingChainIssue()); - } - else - { - r.setIssue(bridgeSpec.lockingChainIssue()); - } - return r; - }(); - - auto const sleClaimID = ctx.view.read(keylet::xChainClaimID(bridgeSpec, claimID)); - { - // Check that the sequence number is owned by the sender of this - // transaction - if (!sleClaimID) - { - return tecXCHAIN_NO_CLAIM_ID; - } - - if ((*sleClaimID)[sfAccount] != account) - { - // Sequence number isn't owned by the sender of this transaction - return tecXCHAIN_BAD_CLAIM_ID; - } - } - - // quorum is checked in `doApply` - return tesSUCCESS; -} - -TER -XChainClaim::doApply() -{ - PaymentSandbox psb(&ctx_.view()); - - AccountID const account = ctx_.tx[sfAccount]; - auto const dst = ctx_.tx[sfDestination]; - STXChainBridge const bridgeSpec = ctx_.tx[sfXChainBridge]; - STAmount const& thisChainAmount = ctx_.tx[sfAmount]; - auto const claimID = ctx_.tx[sfXChainClaimID]; - auto const claimIDKeylet = keylet::xChainClaimID(bridgeSpec, claimID); - - struct ScopeResult - { - std::vector rewardAccounts; - AccountID rewardPoolSrc; - STAmount sendingAmount; - STXChainBridge::ChainType srcChain; - STAmount signatureReward; - }; - - auto const scopeResult = [&]() -> std::expected { - // This lambda is ugly - admittedly. The purpose of this lambda is to - // limit the scope of sles so they don't overlap with - // `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child - // views, it's important that the sle's lifetime doesn't overlap. - - auto const sleAcct = psb.peek(keylet::account(account)); - auto const sleBridge = peekBridge(psb, bridgeSpec); - auto const sleClaimID = psb.peek(claimIDKeylet); - - if (!(sleBridge && sleClaimID && sleAcct)) - return std::unexpected(tecINTERNAL); - - AccountID const thisDoor = (*sleBridge)[sfAccount]; - - STXChainBridge::ChainType dstChain = STXChainBridge::ChainType::Locking; - { - if (thisDoor == bridgeSpec.lockingChainDoor()) - { - dstChain = STXChainBridge::ChainType::Locking; - } - else if (thisDoor == bridgeSpec.issuingChainDoor()) - { - dstChain = STXChainBridge::ChainType::Issuing; - } - else - { - return std::unexpected(tecINTERNAL); - } - } - STXChainBridge::ChainType const srcChain = STXChainBridge::otherChain(dstChain); - - auto const sendingAmount = [&]() -> STAmount { - STAmount r(thisChainAmount); - r.setIssue(bridgeSpec.issue(srcChain)); - return r; - }(); - - auto const [signersList, quorum, slTer] = - getSignersListAndQuorum(ctx_.view(), *sleBridge, ctx_.journal); - - if (!isTesSuccess(slTer)) - return std::unexpected(slTer); - - XChainClaimAttestations curAtts{sleClaimID->getFieldArray(sfXChainClaimAttestations)}; - - auto const claimR = onClaim( - curAtts, - psb, - sendingAmount, - /*wasLockingChainSend*/ srcChain == STXChainBridge::ChainType::Locking, - quorum, - signersList, - ctx_.journal); - if (!claimR.has_value()) - return std::unexpected(claimR.error()); - - return ScopeResult{ - .rewardAccounts = claimR.value(), - .rewardPoolSrc = (*sleClaimID)[sfAccount], - .sendingAmount = sendingAmount, - .srcChain = srcChain, - .signatureReward = (*sleClaimID)[sfSignatureReward], - }; - }(); - - if (!scopeResult.has_value()) - return scopeResult.error(); - - auto const& [rewardAccounts, rewardPoolSrc, sendingAmount, srcChain, signatureReward] = - scopeResult.value(); - std::optional const dstTag = ctx_.tx[~sfDestinationTag]; - - auto const r = finalizeClaimHelper( - psb, - bridgeSpec, - dst, - dstTag, - /*claimOwner*/ account, - sendingAmount, - rewardPoolSrc, - signatureReward, - rewardAccounts, - srcChain, - claimIDKeylet, - OnTransferFail::KeepClaim, - DepositAuthPolicy::DstCanBypass, - ctx_.journal); - if (!r.isTesSuccess()) - return r.ter(); - - psb.apply(ctx_.rawView()); - - return tesSUCCESS; -} - -//------------------------------------------------------------------------------ - -TxConsequences -XChainCommit::makeTxConsequences(PreflightContext const& ctx) -{ - auto const maxSpend = [&] { - auto const amount = ctx.tx[sfAmount]; - if (amount.native() && amount.signum() > 0) - return amount.xrp(); - return XRPAmount{beast::kZero}; - }(); - - return TxConsequences{ctx.tx, maxSpend}; -} - -NotTEC -XChainCommit::preflight(PreflightContext const& ctx) -{ - auto const amount = ctx.tx[sfAmount]; - auto const bridgeSpec = ctx.tx[sfXChainBridge]; - - if (amount.signum() <= 0 || !isLegalNet(amount)) - return temBAD_AMOUNT; - - if (amount.asset() != bridgeSpec.lockingChainIssue() && - amount.asset() != bridgeSpec.issuingChainIssue()) - return temBAD_ISSUER; - - return tesSUCCESS; -} - -TER -XChainCommit::preclaim(PreclaimContext const& ctx) -{ - auto const bridgeSpec = ctx.tx[sfXChainBridge]; - auto const amount = ctx.tx[sfAmount]; - - auto const sleBridge = readBridge(ctx.view, bridgeSpec); - if (!sleBridge) - { - return tecNO_ENTRY; - } - - AccountID const thisDoor = (*sleBridge)[sfAccount]; - AccountID const account = ctx.tx[sfAccount]; - - if (thisDoor == account) - { - // Door account can't lock funds onto itself - return tecXCHAIN_SELF_COMMIT; - } - - bool isLockingChain = false; - { - if (thisDoor == bridgeSpec.lockingChainDoor()) - { - isLockingChain = true; - } - else if (thisDoor == bridgeSpec.issuingChainDoor()) - { - isLockingChain = false; - } - else - { - return tecINTERNAL; // LCOV_EXCL_LINE - } - } - - if (isLockingChain) - { - if (bridgeSpec.lockingChainIssue() != ctx.tx[sfAmount].asset()) - return tecXCHAIN_BAD_TRANSFER_ISSUE; - } - else - { - if (bridgeSpec.issuingChainIssue() != ctx.tx[sfAmount].asset()) - return tecXCHAIN_BAD_TRANSFER_ISSUE; - } - - return tesSUCCESS; -} - -TER -XChainCommit::doApply() -{ - PaymentSandbox psb(&ctx_.view()); - - auto const account = ctx_.tx[sfAccount]; - auto const amount = ctx_.tx[sfAmount]; - auto const bridgeSpec = ctx_.tx[sfXChainBridge]; - - auto const sleAccount = psb.read(keylet::account(account)); - if (!sleAccount) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const sleBridge = readBridge(psb, bridgeSpec); - if (!sleBridge) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const dst = (*sleBridge)[sfAccount]; - - // Support dipping into reserves to pay the fee - TransferHelperSubmittingAccountInfo submittingAccountInfo{ - .account = accountID_, - .preFeeBalance = preFeeBalance_, - .postFeeBalance = (*sleAccount)[sfBalance]}; - - auto const thTer = transferHelper( - psb, - account, - dst, - /*dstTag*/ std::nullopt, - /*claimOwner*/ std::nullopt, - amount, - CanCreateDstPolicy::No, - DepositAuthPolicy::Normal, - submittingAccountInfo, - ctx_.journal); - - if (!isTesSuccess(thTer)) - return thTer; - - psb.apply(ctx_.rawView()); - - return tesSUCCESS; -} - -//------------------------------------------------------------------------------ - -NotTEC -XChainCreateClaimID::preflight(PreflightContext const& ctx) -{ - auto const reward = ctx.tx[sfSignatureReward]; - - if (!isXRP(reward) || reward.signum() < 0 || !isLegalNet(reward)) - return temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT; - - return tesSUCCESS; -} - -TER -XChainCreateClaimID::preclaim(PreclaimContext const& ctx) -{ - auto const account = ctx.tx[sfAccount]; - auto const bridgeSpec = ctx.tx[sfXChainBridge]; - auto const sleBridge = readBridge(ctx.view, bridgeSpec); - - if (!sleBridge) - { - return tecNO_ENTRY; - } - - // Check that the reward matches - auto const reward = ctx.tx[sfSignatureReward]; - - if (reward != (*sleBridge)[sfSignatureReward]) - { - return tecXCHAIN_REWARD_MISMATCH; - } - - { - // Check reserve - auto const sleAcc = ctx.view.read(keylet::account(account)); - if (!sleAcc) - return terNO_ACCOUNT; - - auto const balance = (*sleAcc)[sfBalance]; - auto const reserve = accountReserve(ctx.view, sleAcc, ctx.j, {.ownerCountDelta = 1}); - if (balance < reserve) - return tecINSUFFICIENT_RESERVE; - } - - return tesSUCCESS; -} - -TER -XChainCreateClaimID::doApply() -{ - auto const account = ctx_.tx[sfAccount]; - auto const bridgeSpec = ctx_.tx[sfXChainBridge]; - auto const reward = ctx_.tx[sfSignatureReward]; - auto const otherChainSrc = ctx_.tx[sfOtherChainSource]; - - auto const sleAcct = ctx_.view().peek(keylet::account(account)); - if (!sleAcct) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const sleBridge = peekBridge(ctx_.view(), bridgeSpec); - if (!sleBridge) - return tecINTERNAL; // LCOV_EXCL_LINE - - std::uint32_t const claimID = (*sleBridge)[sfXChainClaimID] + 1; - if (claimID == 0) - { - // overflow - return tecINTERNAL; // LCOV_EXCL_LINE - } - - (*sleBridge)[sfXChainClaimID] = claimID; - - Keylet const claimIDKeylet = keylet::xChainClaimID(bridgeSpec, claimID); - if (ctx_.view().exists(claimIDKeylet)) - { - // already checked out!?! - return tecINTERNAL; // LCOV_EXCL_LINE - } - - auto const sleClaimID = std::make_shared(claimIDKeylet); - - (*sleClaimID)[sfAccount] = account; - (*sleClaimID)[sfXChainBridge] = bridgeSpec; - (*sleClaimID)[sfXChainClaimID] = claimID; - (*sleClaimID)[sfOtherChainSource] = otherChainSrc; - (*sleClaimID)[sfSignatureReward] = reward; - sleClaimID->setFieldArray(sfXChainClaimAttestations, STArray{sfXChainClaimAttestations}); - - // Add to owner directory - { - auto const page = ctx_.view().dirInsert( - keylet::ownerDir(account), claimIDKeylet, describeOwnerDir(account)); - if (!page) - return tecDIR_FULL; // LCOV_EXCL_LINE - (*sleClaimID)[sfOwnerNode] = *page; - } - - increaseOwnerCount(ctx_.view(), sleAcct, {}, 1, ctx_.journal); - - ctx_.view().insert(sleClaimID); - ctx_.view().update(sleBridge); - ctx_.view().update(sleAcct); - - return tesSUCCESS; -} - -//------------------------------------------------------------------------------ - -NotTEC -XChainAddClaimAttestation::preflight(PreflightContext const& ctx) -{ - return attestationPreflight(ctx); -} - -TER -XChainAddClaimAttestation::preclaim(PreclaimContext const& ctx) -{ - return attestationPreclaim(ctx); -} - -TER -XChainAddClaimAttestation::doApply() -{ - return attestationDoApply(ctx_); -} - -//------------------------------------------------------------------------------ - -NotTEC -XChainAddAccountCreateAttestation::preflight(PreflightContext const& ctx) -{ - return attestationPreflight(ctx); -} - -TER -XChainAddAccountCreateAttestation::preclaim(PreclaimContext const& ctx) -{ - return attestationPreclaim(ctx); -} - -TER -XChainAddAccountCreateAttestation::doApply() -{ - return attestationDoApply(ctx_); -} - -//------------------------------------------------------------------------------ - -NotTEC -XChainCreateAccountCommit::preflight(PreflightContext const& ctx) -{ - auto const amount = ctx.tx[sfAmount]; - - if (amount.signum() <= 0 || !amount.native()) - return temBAD_AMOUNT; - - auto const reward = ctx.tx[sfSignatureReward]; - if (reward.signum() < 0 || !reward.native()) - return temBAD_AMOUNT; - - if (reward.asset() != amount.asset()) - return temBAD_AMOUNT; - - return tesSUCCESS; -} - -TER -XChainCreateAccountCommit::preclaim(PreclaimContext const& ctx) -{ - STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; - STAmount const amount = ctx.tx[sfAmount]; - STAmount const reward = ctx.tx[sfSignatureReward]; - - auto const sleBridge = readBridge(ctx.view, bridgeSpec); - if (!sleBridge) - { - return tecNO_ENTRY; - } - - if (reward != (*sleBridge)[sfSignatureReward]) - { - return tecXCHAIN_REWARD_MISMATCH; - } - - std::optional const minCreateAmount = (*sleBridge)[~sfMinAccountCreateAmount]; - - if (!minCreateAmount) - return tecXCHAIN_CREATE_ACCOUNT_DISABLED; - - if (amount < *minCreateAmount) - return tecXCHAIN_INSUFF_CREATE_AMOUNT; - - if (minCreateAmount->asset() != amount.asset()) - return tecXCHAIN_BAD_TRANSFER_ISSUE; - - AccountID const thisDoor = (*sleBridge)[sfAccount]; - AccountID const account = ctx.tx[sfAccount]; - if (thisDoor == account) - { - // Door account can't lock funds onto itself - return tecXCHAIN_SELF_COMMIT; - } - - STXChainBridge::ChainType srcChain = STXChainBridge::ChainType::Locking; - { - if (thisDoor == bridgeSpec.lockingChainDoor()) - { - srcChain = STXChainBridge::ChainType::Locking; - } - else if (thisDoor == bridgeSpec.issuingChainDoor()) - { - srcChain = STXChainBridge::ChainType::Issuing; - } - else - { - return tecINTERNAL; // LCOV_EXCL_LINE - } - } - STXChainBridge::ChainType const dstChain = STXChainBridge::otherChain(srcChain); - - if (bridgeSpec.issue(srcChain) != ctx.tx[sfAmount].asset()) - return tecXCHAIN_BAD_TRANSFER_ISSUE; - - if (!isXRP(bridgeSpec.issue(dstChain))) - return tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE; - - return tesSUCCESS; -} - -TER -XChainCreateAccountCommit::doApply() -{ - PaymentSandbox psb(&ctx_.view()); - - AccountID const account = ctx_.tx[sfAccount]; - STAmount const amount = ctx_.tx[sfAmount]; - STAmount const reward = ctx_.tx[sfSignatureReward]; - STXChainBridge const bridge = ctx_.tx[sfXChainBridge]; - - auto const sle = psb.peek(keylet::account(account)); - if (!sle) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const sleBridge = peekBridge(psb, bridge); - if (!sleBridge) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const dst = (*sleBridge)[sfAccount]; - - // Support dipping into reserves to pay the fee - TransferHelperSubmittingAccountInfo submittingAccountInfo{ - .account = accountID_, - .preFeeBalance = preFeeBalance_, - .postFeeBalance = (*sle)[sfBalance]}; - STAmount const toTransfer = amount + reward; - auto const thTer = transferHelper( - psb, - account, - dst, - /*dstTag*/ std::nullopt, - /*claimOwner*/ std::nullopt, - toTransfer, - CanCreateDstPolicy::Yes, - DepositAuthPolicy::Normal, - submittingAccountInfo, - ctx_.journal); - - if (!isTesSuccess(thTer)) - return thTer; - - (*sleBridge)[sfXChainAccountCreateCount] = (*sleBridge)[sfXChainAccountCreateCount] + 1; - psb.update(sleBridge); - - psb.apply(ctx_.rawView()); - - return tesSUCCESS; -} - -void -XChainCreateBridge::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -XChainCreateBridge::finalizeInvariants( - STTx const&, - TER, - XRPAmount, - ReadView const&, - beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -void -BridgeModify::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -BridgeModify::finalizeInvariants( - STTx const&, - TER, - XRPAmount, - ReadView const&, - beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -void -XChainClaim::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -XChainClaim::finalizeInvariants(STTx const&, TER, XRPAmount, ReadView const&, beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -void -XChainCommit::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -XChainCommit::finalizeInvariants( - STTx const&, - TER, - XRPAmount, - ReadView const&, - beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -void -XChainCreateClaimID::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -XChainCreateClaimID::finalizeInvariants( - STTx const&, - TER, - XRPAmount, - ReadView const&, - beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -void -XChainAddClaimAttestation::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -XChainAddClaimAttestation::finalizeInvariants( - STTx const&, - TER, - XRPAmount, - ReadView const&, - beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -void -XChainAddAccountCreateAttestation::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -XChainAddAccountCreateAttestation::finalizeInvariants( - STTx const&, - TER, - XRPAmount, - ReadView const&, - beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -void -XChainCreateAccountCommit::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref) -{ - // No transaction-specific invariants yet (future work). -} - -bool -XChainCreateAccountCommit::finalizeInvariants( - STTx const&, - TER, - XRPAmount, - ReadView const&, - beast::Journal const&) -{ - // No transaction-specific invariants yet (future work). - return true; -} - -} // namespace xrpl diff --git a/src/test/app/Delegate_test.cpp b/src/test/app/Delegate_test.cpp index 257ed33619..7b6c116978 100644 --- a/src/test/app/Delegate_test.cpp +++ b/src/test/app/Delegate_test.cpp @@ -2590,14 +2590,6 @@ class Delegate_test : public beast::unit_test::Suite {"AMMVote", featureAMM}, {"AMMBid", featureAMM}, {"AMMDelete", featureAMM}, - {"XChainCreateClaimID", featureXChainBridge}, - {"XChainCommit", featureXChainBridge}, - {"XChainClaim", featureXChainBridge}, - {"XChainAccountCreateCommit", featureXChainBridge}, - {"XChainAddClaimAttestation", featureXChainBridge}, - {"XChainAddAccountCreateAttestation", featureXChainBridge}, - {"XChainModifyBridge", featureXChainBridge}, - {"XChainCreateBridge", featureXChainBridge}, {"DIDSet", featureDID}, {"DIDDelete", featureDID}, {"OracleSet", featurePriceOracle}, diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 7543db7364..7a22c78c83 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -1898,7 +1897,6 @@ class MPToken_test : public beast::unit_test::Suite Account const carol("carol"); MPTIssue const issue(makeMptID(1, alice)); STAmount mpt{issue, UINT64_C(100)}; - auto const jvb = bridge(alice, usd, alice, usd); for (auto const& feature : {features, features - featureMPTokensV1}) { Env env{*this, feature}; @@ -2044,70 +2042,6 @@ class MPToken_test : public beast::unit_test::Suite }; trustSet(sfLimitAmount); trustSet(sfFee); - // XChainCommit - { - json::Value const jv = xchainCommit(alice, jvb, 1, mpt); - test(jv, jss::Amount.cStr()); - } - // XChainClaim - { - json::Value const jv = xchainClaim(alice, jvb, 1, mpt, alice); - test(jv, jss::Amount.cStr()); - } - // XChainCreateClaimID - { - json::Value const jv = xchainCreateClaimId(alice, jvb, mpt, alice); - test(jv, sfSignatureReward.fieldName); - } - // XChainAddClaimAttestation - { - json::Value const jv = - claimAttestation(alice, jvb, alice, mpt, alice, true, 1, alice, Signer(alice)); - test(jv, jss::Amount.cStr()); - } - // XChainAddAccountCreateAttestation - { - json::Value jv = createAccountAttestation( - alice, jvb, alice, mpt, XRP(10), alice, false, 1, alice, Signer(alice)); - for (auto const& field : {sfAmount.fieldName, sfSignatureReward.fieldName}) - { - jv[field] = mpt.getJson(JsonOptions::Values::None); - test(jv, field); - } - } - // XChainAccountCreateCommit - { - json::Value jv = sidechainXchainAccountCreate(alice, jvb, alice, mpt, XRP(10)); - for (auto const& field : {sfAmount.fieldName, sfSignatureReward.fieldName}) - { - jv[field] = mpt.getJson(JsonOptions::Values::None); - test(jv, field); - } - } - // XChain[Create|Modify]Bridge - auto bridgeTx = [&](json::StaticString const& tt, - STAmount const& rewardAmount, - STAmount const& minAccountAmount, - std::string const& field) { - json::Value jv; - jv[jss::TransactionType] = tt; - jv[jss::Account] = alice.human(); - jv[sfXChainBridge.fieldName] = jvb; - jv[sfSignatureReward.fieldName] = rewardAmount.getJson(JsonOptions::Values::None); - jv[sfMinAccountCreateAmount.fieldName] = - minAccountAmount.getJson(JsonOptions::Values::None); - test(jv, field); - }; - auto reward = STAmount{sfSignatureReward, mpt}; - auto minAmount = STAmount{sfMinAccountCreateAmount, usd(10)}; - for (SField const& field : - {std::ref(sfSignatureReward), std::ref(sfMinAccountCreateAmount)}) - { - bridgeTx(jss::XChainCreateBridge, reward, minAmount, field.fieldName); - bridgeTx(jss::XChainModifyBridge, reward, minAmount, field.fieldName); - reward = STAmount{sfSignatureReward, usd(10)}; - minAmount = STAmount{sfMinAccountCreateAmount, mpt}; - } // SponsorshipSet { json::Value jv; diff --git a/src/test/app/XChain_test.cpp b/src/test/app/XChain_test.cpp deleted file mode 100644 index 4b007eea13..0000000000 --- a/src/test/app/XChain_test.cpp +++ /dev/null @@ -1,4783 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace xrpl::test { - -// SEnv class - encapsulate jtx::Env to make it more user-friendly, -// for example having APIs that return a *this reference so that calls can be -// chained (fluent interface) allowing to create an environment and use it -// without encapsulating it in a curly brace block. -// --------------------------------------------------------------------------- -template -struct SEnv -{ - jtx::Env env; - - SEnv( - T& s, - std::unique_ptr config, - FeatureBitset features, - std::unique_ptr logs = nullptr, - beast::Severity thresh = beast::Severity::Error) - : env(s, std::move(config), features, std::move(logs), thresh) - { - } - - SEnv& - close() - { - env.close(); - return *this; - } - - SEnv& - enableFeature(uint256 const feature) - { - env.enableFeature(feature); - return *this; - } - - SEnv& - disableFeature(uint256 const feature) - { - env.app().config().features.erase(feature); - return *this; - } - - template - SEnv& - fund(STAmount const& amount, Arg const& arg, Args const&... args) - { - env.fund(amount, arg, args...); - return *this; - } - - template - SEnv& - tx(JsonValue&& jv, FN const&... fN) - { - env(std::forward(jv), fN...); - return *this; - } - - template - SEnv& - multiTx(jtx::JValueVec const& jvv, FN const&... fN) - { - for (auto const& jv : jvv) - env(jv, fN...); - return *this; - } - - [[nodiscard]] TER - ter() const - { - return env.ter(); - } - - [[nodiscard]] STAmount - balance(jtx::Account const& account) const - { - return env.balance(account).value(); - } - - [[nodiscard]] STAmount - balance(jtx::Account const& account, Issue const& issue) const - { - return env.balance(account, issue).value(); - } - - XRPAmount - reserve(std::uint32_t count) - { - return env.current()->fees().accountReserve(count, 1); - } - - XRPAmount - txFee() - { - return env.current()->fees().base; - } - - SLE::const_pointer - account(jtx::Account const& account) - { - return env.le(account); - } - - SLE::const_pointer - bridge(json::Value const& jvb) - { - STXChainBridge const b(jvb); - - auto tryGet = [&](STXChainBridge::ChainType ct) -> SLE::const_pointer { - if (auto r = env.le(keylet::bridge(b, ct))) - { - if ((*r)[sfXChainBridge] == b) - return r; - } - return nullptr; - }; - if (auto r = tryGet(STXChainBridge::ChainType::Locking)) - return r; - return tryGet(STXChainBridge::ChainType::Issuing); - } - - std::uint64_t - claimCount(json::Value const& jvb) - { - return (*bridge(jvb))[sfXChainAccountClaimCount]; - } - - std::uint64_t - claimID(json::Value const& jvb) - { - return (*bridge(jvb))[sfXChainClaimID]; - } - - SLE::const_pointer - claimID(json::Value const& jvb, std::uint64_t seq) - { - return env.le(keylet::xChainClaimID(STXChainBridge(jvb), seq)); - } - - SLE::const_pointer - caClaimID(json::Value const& jvb, std::uint64_t seq) - { - return env.le(keylet::xChainCreateAccountClaimID(STXChainBridge(jvb), seq)); - } -}; - -// XEnv class used for XChain tests. The only difference with SEnv is that it -// funds some default accounts, and that it enables `testable_amendments() | -// FeatureBitset{featureXChainBridge}` by default. -// ----------------------------------------------------------------------------- -template -struct XEnv : public jtx::XChainBridgeObjects, public SEnv -{ - XEnv(T& s, bool side = false) : SEnv(s, jtx::envconfig(), features) - { - using namespace jtx; - STAmount const xrpFunds{XRP(10000)}; - - if (!side) - { - this->fund(xrpFunds, mcDoor, mcAlice, mcBob, mcCarol, mcGw); - - // Signer's list must match the attestation signers - // env_(jtx::signers(mcDoor, quorum, signers)); - for (auto& s : signers) - this->fund(xrpFunds, s.account); - } - else - { - this->fund(xrpFunds, scDoor, scAlice, scBob, scCarol, scGw, scAttester, scReward); - - for (auto& ra : payees) - this->fund(xrpFunds, ra); - - for (auto& s : signers) - this->fund(xrpFunds, s.account); - - // Signer's list must match the attestation signers - // env_(jtx::signers(Account::kMaster, quorum, signers)); - } - this->close(); - } -}; - -// Tracks the xrp balance for one account -template -struct Balance -{ - jtx::Account const& account; - T& env; - STAmount startAmount; - - Balance(T& env, jtx::Account const& account) - : account(account), env(env), startAmount(env.balance(account)) - { - } - - [[nodiscard]] STAmount - diff() const - { - return env.balance(account) - startAmount; - } -}; - -// Tracks the xrp balance for multiple accounts involved in a crosss-chain -// transfer -template -struct BalanceTransfer -{ - using balance = Balance; - - balance from; - balance to; - balance payer; // pays the rewards - std::vector rewardAccounts; // receives the reward - XRPAmount txFees; - - BalanceTransfer( - T& env, - jtx::Account const& fromAcct, - jtx::Account const& toAcct, - jtx::Account const& payer, - jtx::Account const* payees, - size_t numPayees, - bool withClaim) - : from(env, fromAcct) - , to(env, toAcct) - , payer(env, payer) - , rewardAccounts([&]() { - std::vector r; - r.reserve(numPayees); - for (size_t i = 0; i < numPayees; ++i) - r.emplace_back(env, payees[i]); - return r; - }()) - , txFees(withClaim ? env.env.current()->fees().base : XRPAmount(0)) - { - } - - BalanceTransfer( - T& env, - jtx::Account const& fromAcct, - jtx::Account const& toAcct, - jtx::Account const& payer, - std::vector const& payees, - bool withClaim) - : BalanceTransfer(env, fromAcct, toAcct, payer, &payees[0], payees.size(), withClaim) - { - } - - [[nodiscard]] bool - payeesReceived(STAmount const& reward) const - { - return std::ranges::all_of( - rewardAccounts, [&](balance const& b) { return b.diff() == reward; }); - } - - bool - checkMostBalances(STAmount const& amt, STAmount const& reward) - { - return from.diff() == -amt && to.diff() == amt && payeesReceived(reward); - } - - bool - hasHappened(STAmount const& amt, STAmount const& reward, bool checkPayer = true) - { - auto rewardCost = multiply(reward, STAmount(rewardAccounts.size()), reward.asset()); - return checkMostBalances(amt, reward) && - (!checkPayer || payer.diff() == -(rewardCost + txFees)); - } - - bool - hasNotHappened() - { - return checkMostBalances(STAmount(0), STAmount(0)) && - payer.diff() <= txFees; // could have paid fee for failed claim - } -}; - -struct BridgeDef -{ - jtx::Account doorA; - Issue issueA; - jtx::Account doorB; - Issue issueB; - STAmount reward; - STAmount minAccountCreate; - uint32_t quorum; - std::vector const& signers; - json::Value jvb; - - template - void - initBridge(ENV& mcEnv, ENV& scEnv) - { - jvb = bridge(doorA, issueA, doorB, issueB); - - auto const optAccountCreate = [&]() -> std::optional { - if (issueA != xrpIssue() || issueB != xrpIssue()) - return {}; - return minAccountCreate; - }(); - mcEnv.tx(bridgeCreate(doorA, jvb, reward, optAccountCreate)) - .tx(jtx::signers(doorA, quorum, signers)) - .close(); - - scEnv.tx(bridgeCreate(doorB, jvb, reward, optAccountCreate)) - .tx(jtx::signers(doorB, quorum, signers)) - .close(); - } -}; - -struct XChain_test : public beast::unit_test::Suite, public jtx::XChainBridgeObjects -{ - XRPAmount - reserve(std::uint32_t count) - { - return XEnv(*this).env.current()->fees().accountReserve(count, 1); - } - - XRPAmount - txFee() - { - return XEnv(*this).env.current()->fees().base; - } - - void - testXChainBridgeExtraFields() - { - auto jBridge = createBridge(mcDoor)[sfXChainBridge.jsonName]; - bool exceptionPresent = false; - try - { - exceptionPresent = false; - [[maybe_unused]] STXChainBridge const testBridge1(jBridge); - } - catch (std::exception& ec) - { - exceptionPresent = true; - } - - BEAST_EXPECT(!exceptionPresent); - - try - { - exceptionPresent = false; - jBridge["Extra"] = 1; - [[maybe_unused]] STXChainBridge const testBridge2(jBridge); - } - catch ([[maybe_unused]] std::exception& ec) - { - exceptionPresent = true; - } - - BEAST_EXPECT(exceptionPresent); - } - - void - testXChainCreateBridge() - { - XRPAmount const res1 = reserve(1); - - using namespace jtx; - testcase("Create Bridge"); - - // Normal create_bridge => should succeed - XEnv(*this).tx(createBridge(mcDoor)).close(); - - // Bridge not owned by one of the door account. - XEnv(*this).tx(createBridge(mcBob), Ter(temXCHAIN_BRIDGE_NONDOOR_OWNER)); - - // Create twice on the same account - XEnv(*this).tx(createBridge(mcDoor)).close().tx(createBridge(mcDoor), Ter(tecDUPLICATE)); - - // Create USD bridge Alice -> Bob ... should succeed - XEnv(*this).tx( - createBridge(mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])), - Ter(tesSUCCESS)); - - // Create USD bridge, Alice is both the locking door and locking issue, - // ... should fail. - XEnv(*this).tx( - createBridge(mcAlice, bridge(mcAlice, mcAlice["USD"], mcBob, mcBob["USD"])), - Ter(temXCHAIN_BRIDGE_BAD_ISSUES)); - - // Bridge where the two door accounts are equal. - XEnv(*this).tx( - createBridge(mcBob, bridge(mcBob, mcGw["USD"], mcBob, mcGw["USD"])), - Ter(temXCHAIN_EQUAL_DOOR_ACCOUNTS)); - - // Both door accounts are on the same chain. This is not allowed. - // Although it doesn't violate any invariants, it's not a useful thing - // to do and it complicates the "add claim" transactions. - XEnv(*this) - .tx(createBridge(mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"]))) - .close() - .tx(createBridge(mcBob, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"])), - Ter(tecDUPLICATE)) - .close(); - - // Create a bridge on an account with exactly enough balance to - // meet the new reserve should succeed - XEnv(*this) - .fund(res1, mcuDoor) // exact reserve for account + 1 object - .close() - .tx(createBridge(mcuDoor, jvub), Ter(tesSUCCESS)); - - // Create a bridge on an account with no enough balance to meet the - // new reserve - XEnv(*this) - .fund(res1 - 1, mcuDoor) // just short of required reserve - .close() - .tx(createBridge(mcuDoor, jvub), Ter(tecINSUFFICIENT_RESERVE)); - - // Reward amount is non-xrp - XEnv(*this).tx( - createBridge(mcDoor, jvb, mcUSD(1)), Ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); - - // Reward amount is XRP and negative - XEnv(*this).tx(createBridge(mcDoor, jvb, XRP(-1)), Ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); - - // Reward amount is 1 xrp => should succeed - XEnv(*this).tx(createBridge(mcDoor, jvb, XRP(1)), Ter(tesSUCCESS)); - - // Min create amount is 1 xrp, mincreate is 1 xrp => should succeed - XEnv(*this).tx(createBridge(mcDoor, jvb, XRP(1), XRP(1)), Ter(tesSUCCESS)); - - // Min create amount is non-xrp - XEnv(*this).tx( - createBridge(mcDoor, jvb, XRP(1), mcUSD(100)), - Ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); - - // Min create amount is zero (should fail, currently succeeds) - XEnv(*this).tx( - createBridge(mcDoor, jvb, XRP(1), XRP(0)), - Ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); - - // Min create amount is negative - XEnv(*this).tx( - createBridge(mcDoor, jvb, XRP(1), XRP(-1)), - Ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); - - // coverage test: BridgeCreate::preflight() - create bridge when feature - // disabled. - { - Env env(*this, testableAmendments() - featureXChainBridge); - env(createBridge(Account::kMaster, jvb), Ter(temDISABLED)); - } - - // coverage test: BridgeCreate::preclaim() returns tecNO_ISSUER. - XEnv(*this).tx( - createBridge(mcAlice, bridge(mcAlice, mcuAlice["USD"], mcBob, mcBob["USD"])), - Ter(tecNO_ISSUER)); - - // coverage test: create_bridge transaction with incorrect flag - XEnv(*this).tx(createBridge(mcAlice, jvb), Txflags(tfFillOrKill), Ter(temINVALID_FLAG)); - - // coverage test: create_bridge transaction with xchain feature disabled - XEnv(*this) - .disableFeature(featureXChainBridge) - .tx(createBridge(mcAlice, jvb), Ter(temDISABLED)); - } - - void - testXChainBridgeCreateConstraints() - { - /** - * Bridge create constraints tests. - * - * Define the door's bridge asset collection as the collection of all - * the issuing assets for which the door account is on the issuing chain - * and all the locking assets for which the door account is on the - * locking chain. (note: a door account can simultaneously be on an - * issuing and locking chain). A new bridge is not a duplicate as long - * as the new bridge asset collection does not contain any duplicate - * currencies (even if the issuers differ). - * - * Create bridges: - * - *| Owner | Locking | Issuing | Comment | - *| a1 | a1 USD/GW | USD/B | | - *| a2 | a2 USD/GW | USD/B | Same locking & issuing assets | - *| | | | | - *| a3 | a3 USD/GW | USD/a4 | | - *| a4 | a4 USD/GW | USD/a4 | Same bridge, different accounts | - *| | | | | - *| B | A USD/GW | USD/B | | - *| B | A EUR/GW | USD/B | Fail: Same issuing asset | - *| | | | | - *| A | A USD/B | USD/C | | - *| A | A USD/B | EUR/B | Fail: Same locking asset | - *| A | A USD/C | EUR/B | Fail: Same locking asset currency | - *| | | | | - *| A | A USD/GW | USD/B | Fail: Same bridge not allowed | - *| A | B USD/GW | USD/A | Fail: "A" has USD already | - *| B | A EUR/GW | USD/B | Fail: | - * - * Note that, now from sidechain's point of view, A is both - * a local locking door and a foreign locking door on different - * bridges. Txns such as commits specify bridge spec, but not the - * local door account. So we test the transactors can figure out - * the correct local door account from bridge spec. - * - * Commit to sidechain door accounts: - * | bridge spec | result - * case 6 | A -> B | B's balance increase - * case 7 | C <- A | A's balance increase - * - * We also test ModifyBridge txns modify correct bridges. - */ - - using namespace jtx; - testcase("Bridge create constraints"); - XEnv env(*this, true); - auto& a = scAlice; - auto& b = scBob; - auto& c = scCarol; - auto ausd = a["USD"]; - auto busd = b["USD"]; - auto cusd = c["USD"]; - auto gusd = scGw["USD"]; - auto aeur = a["EUR"]; - auto beur = b["EUR"]; - auto ceur = c["EUR"]; - auto geur = scGw["EUR"]; - - // Accounts to own single bridges - Account const a1("a1"); - Account const a2("a2"); - Account const a3("a3"); - Account const a4("a4"); - Account const a5("a5"); - Account const a6("a6"); - - env.fund(XRP(10000), a1, a2, a3, a4, a5, a6); - env.close(); - - // Add a bridge on two different accounts with the same locking and - // issuing assets - env.tx(createBridge(a1, bridge(a1, gusd, b, busd))).close(); - env.tx(createBridge(a2, bridge(a2, gusd, b, busd))).close(); - - // Add the exact same bridge to two different accounts (one locking - // account and one issuing) - env.tx(createBridge(a3, bridge(a3, gusd, a4, a4["USD"]))).close(); - env.tx(createBridge(a4, bridge(a3, gusd, a4, a4["USD"])), Ter(tecDUPLICATE)).close(); - - // Add the exact same bridge to two different accounts (one issuing - // account and one locking - opposite order from the test above) - env.tx(createBridge(a5, bridge(a6, gusd, a5, a5["USD"]))).close(); - env.tx(createBridge(a6, bridge(a6, gusd, a5, a5["USD"])), Ter(tecDUPLICATE)).close(); - - // Test case 1 ~ 5, create bridges - auto const goodBridge1 = bridge(a, gusd, b, busd); - auto const goodBridge2 = bridge(a, busd, c, cusd); - env.tx(createBridge(b, goodBridge1)).close(); - // Issuing asset is the same, this is a duplicate - env.tx(createBridge(b, bridge(a, geur, b, busd)), Ter(tecDUPLICATE)).close(); - env.tx(createBridge(a, goodBridge2), Ter(tesSUCCESS)).close(); - // Locking asset is the same - this is a duplicate - env.tx(createBridge(a, bridge(a, busd, b, beur)), Ter(tecDUPLICATE)).close(); - // Locking asset is USD - this is a duplicate even tho it has a - // different issuer - env.tx(createBridge(a, bridge(a, cusd, b, beur)), Ter(tecDUPLICATE)).close(); - - // Test case 6 and 7, commits - env.tx(trust(c, busd(1000))) - .tx(trust(a, busd(1000))) - .close() - .tx(pay(b, c, busd(1000))) - .close(); - auto const aBalanceStart = env.balance(a, busd); - auto const cBalanceStart = env.balance(c, busd); - env.tx(xchainCommit(c, goodBridge1, 1, busd(50))).close(); - BEAST_EXPECT(env.balance(a, busd) - aBalanceStart == busd(0)); - BEAST_EXPECT(env.balance(c, busd) - cBalanceStart == busd(-50)); - env.tx(xchainCommit(c, goodBridge2, 1, busd(60))).close(); - BEAST_EXPECT(env.balance(a, busd) - aBalanceStart == busd(60)); - BEAST_EXPECT(env.balance(c, busd) - cBalanceStart == busd(-50 - 60)); - - // bridge modify test cases - env.tx(bridgeModify(b, goodBridge1, XRP(33), std::nullopt)).close(); - BEAST_EXPECT((*env.bridge(goodBridge1))[sfSignatureReward] == XRP(33)); - env.tx(bridgeModify(a, goodBridge2, XRP(44), std::nullopt)).close(); - BEAST_EXPECT((*env.bridge(goodBridge2))[sfSignatureReward] == XRP(44)); - } - - void - testXChainCreateBridgeMatrix() - { - using namespace jtx; - testcase("Create Bridge Matrix"); - - // Test all combinations of the following:` - // -------------------------------------- - // - Locking chain is IOU with locking chain door account as issuer - // - Locking chain is IOU with issuing chain door account that - // exists on the locking chain as issuer - // - Locking chain is IOU with issuing chain door account that does - // not exists on the locking chain as issuer - // - Locking chain is IOU with non-door account (that exists on the - // locking chain ledger) as issuer - // - Locking chain is IOU with non-door account (that does not exist - // exists on the locking chain ledger) as issuer - // - Locking chain is XRP - // --------------------------------------------------------------------- - // - Issuing chain is IOU with issuing chain door account as the - // issuer - // - Issuing chain is IOU with locking chain door account (that - // exists on the issuing chain ledger) as the issuer - // - Issuing chain is IOU with locking chain door account (that does - // not exist on the issuing chain ledger) as the issuer - // - Issuing chain is IOU with non-door account (that exists on the - // issuing chain ledger) as the issuer - // - Issuing chain is IOU with non-door account (that does not - // exists on the issuing chain ledger) as the issuer - // - Issuing chain is XRP and issuing chain door account is not the - // root account - // - Issuing chain is XRP and issuing chain door account is the root - // account - // --------------------------------------------------------------------- - // That's 42 combinations. The only combinations that should succeed - // are: - // - Locking chain is any IOU, - // - Issuing chain is IOU with issuing chain door account as the - // issuer - // Locking chain is XRP, - // - Issuing chain is XRP with issuing chain is the root account. - // --------------------------------------------------------------------- - Account a("a"), b("b"); - Issue ia, ib; - - std::tuple lcs{ - std::make_pair( - "Locking chain is IOU(locking chain door)", - [&](auto& env, bool) { - a = mcDoor; - ia = mcDoor["USD"]; - }), - std::make_pair( - "Locking chain is IOU(issuing chain door funded on locking " - "chain)", - [&](auto& env, bool shouldFund) { - a = mcDoor; - ia = scDoor["USD"]; - if (shouldFund) - env.fund(XRP(10000), scDoor); - }), - std::make_pair( - "Locking chain is IOU(issuing chain door account unfunded " - "on locking chain)", - [&](auto& env, bool) { - a = mcDoor; - ia = scDoor["USD"]; - }), - std::make_pair( - "Locking chain is IOU(bob funded on locking chain)", - [&](auto& env, bool) { - a = mcDoor; - ia = mcGw["USD"]; - }), - std::make_pair( - "Locking chain is IOU(bob unfunded on locking chain)", - [&](auto& env, bool) { - a = mcDoor; - ia = mcuGw["USD"]; - }), - std::make_pair("Locking chain is XRP", [&](auto& env, bool) { - a = mcDoor; - ia = xrpIssue(); - })}; - - std::tuple ics{ - std::make_pair( - "Issuing chain is IOU(issuing chain door account)", - [&](auto& env, bool) { - b = scDoor; - ib = scDoor["USD"]; - }), - std::make_pair( - "Issuing chain is IOU(locking chain door funded on issuing " - "chain)", - [&](auto& env, bool shouldFund) { - b = scDoor; - ib = mcDoor["USD"]; - if (shouldFund) - env.fund(XRP(10000), mcDoor); - }), - std::make_pair( - "Issuing chain is IOU(locking chain door unfunded on " - "issuing chain)", - [&](auto& env, bool) { - b = scDoor; - ib = mcDoor["USD"]; - }), - std::make_pair( - "Issuing chain is IOU(bob funded on issuing chain)", - [&](auto& env, bool) { - b = scDoor; - ib = mcGw["USD"]; - }), - std::make_pair( - "Issuing chain is IOU(bob unfunded on issuing chain)", - [&](auto& env, bool) { - b = scDoor; - ib = mcuGw["USD"]; - }), - std::make_pair( - "Issuing chain is XRP and issuing chain door account is " - "not the root account", - [&](auto& env, bool) { - b = scDoor; - ib = xrpIssue(); - }), - std::make_pair( - "Issuing chain is XRP and issuing chain door account is " - "the root account ", - [&](auto& env, bool) { - b = Account::kMaster; - ib = xrpIssue(); - })}; - - std::vector> expectedResult{ - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {tesSUCCESS, tesSUCCESS}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {tecNO_ISSUER, tesSUCCESS}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {tesSUCCESS, tesSUCCESS}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {tecNO_ISSUER, tesSUCCESS}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {temXCHAIN_BRIDGE_BAD_ISSUES, temXCHAIN_BRIDGE_BAD_ISSUES}, - {tesSUCCESS, tesSUCCESS}}; - - std::vector> testResult; - - auto testcase = [&](auto const& lc, auto const& ic) { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - lc.second(mcEnv, true); - lc.second(scEnv, false); - - ic.second(mcEnv, false); - ic.second(scEnv, true); - - auto const& expected = expectedResult[testResult.size()]; - - mcEnv.tx(createBridge(a, bridge(a, ia, b, ib)), Ter(TER::fromInt(expected.first))); - TER const mcTER = mcEnv.env.ter(); - - scEnv.tx(createBridge(b, bridge(a, ia, b, ib)), Ter(TER::fromInt(expected.second))); - TER const scTER = scEnv.env.ter(); - - bool const pass = isTesSuccess(mcTER) && isTesSuccess(scTER); - - testResult.emplace_back(mcTER, scTER, pass); - }; - - auto applyIcs = [&](auto const& lc, auto const& ics) { - std::apply([&](auto const&... ic) { (testcase(lc, ic), ...); }, ics); - }; - - std::apply([&](auto const&... lc) { (applyIcs(lc, ics), ...); }, lcs); - -#if GENERATE_MTX_OUTPUT - // optional output of matrix results in markdown format - // ---------------------------------------------------- - std::string fname{std::tmpnam(nullptr)}; - fname += ".md"; - std::cout << "Markdown output for matrix test: " << fname << "\n"; - - auto print_res = [](auto tup) -> std::string { - std::string status = - std::string(transToken(std::get<0>(tup))) + " / " + transToken(std::get<1>(tup)); - - if (std::get<2>(tup)) - return status; - else - { - // red - return std::string("`") + status + "`"; - } - }; - - auto output_table = [&](auto print_res) { - size_t test_idx = 0; - std::string res; - res.reserve(10000); // should be enough :-) - - // first two header lines - res += "| `issuing ->` | "; - std::apply([&](auto const&... ic) { ((res += ic.first, res += " | "), ...); }, ics); - res += "\n"; - - res += "| :--- | "; - std::apply( - [&](auto const&... ic) { (((void)ic.first, res += ":---: | "), ...); }, ics); - res += "\n"; - - auto output = [&](auto const& lc, auto const& ic) { - res += print_res(test_result[test_idx]); - res += " | "; - ++test_idx; - }; - - auto output_ics = [&](auto const& lc, auto const& ics) { - res += "| "; - res += lc.first; - res += " | "; - std::apply([&](auto const&... ic) { (output(lc, ic), ...); }, ics); - res += "\n"; - }; - - std::apply([&](auto const&... lc) { (output_ics(lc, ics), ...); }, lcs); - - return res; - }; - - std::ofstream(fname) << output_table(print_res); - - std::string ter_fname{std::tmpnam(nullptr)}; - std::cout << "ter output for matrix test: " << ter_fname << "\n"; - - std::ofstream ofs(ter_fname); - for (auto& t : test_result) - { - ofs << "{ " << std::string(transToken(std::get<0>(t))) << ", " - << std::string(transToken(std::get<1>(t))) << "}\n,"; - } -#endif - } - - void - testXChainModifyBridge() - { - using namespace jtx; - testcase("Modify Bridge"); - - // Changing a non-existent bridge should fail - XEnv(*this).tx( - bridgeModify( - mcAlice, bridge(mcAlice, mcGw["USD"], mcBob, mcBob["USD"]), XRP(2), std::nullopt), - Ter(tecNO_ENTRY)); - - // must change something - // XEnv(*this) - // .tx(create_bridge(mcDoor, jvb, XRP(1), XRP(1))) - // .tx(bridge_modify(mcDoor, jvb, XRP(1), XRP(1)), - // Ter(temMALFORMED)); - - // must change something - XEnv(*this) - .tx(createBridge(mcDoor, jvb, XRP(1), XRP(1))) - .close() - .tx(bridgeModify(mcDoor, jvb, {}, {}), Ter(temMALFORMED)); - - // Reward amount is non-xrp - XEnv(*this).tx( - bridgeModify(mcDoor, jvb, mcUSD(2), XRP(10)), Ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); - - // Reward amount is XRP and negative - XEnv(*this).tx( - bridgeModify(mcDoor, jvb, XRP(-2), XRP(10)), Ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)); - - // Min create amount is non-xrp - XEnv(*this).tx( - bridgeModify(mcDoor, jvb, XRP(2), mcUSD(10)), - Ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); - - // Min create amount is zero - XEnv(*this).tx( - bridgeModify(mcDoor, jvb, XRP(2), XRP(0)), - Ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); - - // Min create amount is negative - XEnv(*this).tx( - bridgeModify(mcDoor, jvb, XRP(2), XRP(-10)), - Ter(temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT)); - - // First check the regular claim process (without bridge_modify) - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum)); - } - - // Check that the reward paid from a claim Id was the reward when - // the claim id was created, not the reward since the bridge was - // modified. - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - // Now modify the reward on the bridge - mcEnv.tx(bridgeModify(mcDoor, jvb, XRP(2), XRP(10))).close(); - scEnv.tx(bridgeModify(Account::kMaster, jvb, XRP(2), XRP(10))).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - // make sure the reward accounts indeed received the original - // split reward (1 split 5 ways) instead of the updated 2 XRP. - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum)); - } - - // Check that the signatures used to verify attestations and decide - // if there is a quorum are the current signer's list on the door - // account, not the signer's list that was in effect when the claim - // id was created. - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - // change signers - claim should not be processed is the batch - // is signed by original signers - scEnv.tx(jtx::signers(Account::kMaster, quorum, altSigners)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - // submit claim using outdated signers - should fail - scEnv - .multiTx( - claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers), - Ter(tecNO_PERMISSION)) - .close(); - if (withClaim) - { - // need to submit a claim transactions - scEnv - .tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), - Ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); - } - - // make sure transfer has not happened as we sent attestations - // using outdated signers - BEAST_EXPECT(transfer.hasNotHappened()); - - // submit claim using current signers - should succeed - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, altSigners)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - // make sure the transfer went through as we sent attestations - // using new signers - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum, false)); - } - - // coverage test: bridge_modify transaction with incorrect flag - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .close() - .tx(bridgeModify(mcDoor, jvb, XRP(1), XRP(2)), - Txflags(tfFillOrKill), - Ter(temINVALID_FLAG)); - - // coverage test: bridge_modify transaction with xchain feature - // disabled - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .disableFeature(featureXChainBridge) - .close() - .tx(bridgeModify(mcDoor, jvb, XRP(1), XRP(2)), Ter(temDISABLED)); - - // coverage test: bridge_modify return temSIDECHAIN_NONDOOR_OWNER; - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .close() - .tx(bridgeModify(mcAlice, jvb, XRP(1), XRP(2)), Ter(temXCHAIN_BRIDGE_NONDOOR_OWNER)); - - /** - * test tfClearAccountCreateAmount flag in BridgeModify tx - * -- tx has both minAccountCreateAmount and the flag, temMALFORMED - * -- tx has the flag and also modifies signature reward, tesSUCCESS - * -- XChainCreateAccountCommit tx fail after previous step - */ - XEnv(*this) - .tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))) - .close() - .tx(sidechainXchainAccountCreate(mcAlice, jvb, scuAlice, XRP(100), reward)) - .close() - .tx(bridgeModify(mcDoor, jvb, {}, XRP(2)), - Txflags(tfClearAccountCreateAmount), - Ter(temMALFORMED)) - .close() - .tx(bridgeModify(mcDoor, jvb, XRP(3), {}), Txflags(tfClearAccountCreateAmount)) - .close() - .tx(sidechainXchainAccountCreate(mcAlice, jvb, scuBob, XRP(100), XRP(3)), - Ter(tecXCHAIN_CREATE_ACCOUNT_DISABLED)) - .close(); - } - - void - testXChainCreateClaimID() - { - using namespace jtx; - XRPAmount const res1 = reserve(1); - XRPAmount const fee = txFee(); - - testcase("Create ClaimID"); - - // normal bridge create for sanity check with the exact necessary - // account balance - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .fund(res1, scuAlice) // acct reserve + 1 object - .close() - .tx(xchainCreateClaimId(scuAlice, jvb, reward, mcAlice)) - .close(); - - // check reward not deducted when claim id is created - { - XEnv xenv(*this, true); - - test::Balance const scAliceBal(xenv, scAlice); - - xenv.tx(createBridge(Account::kMaster, jvb)) - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - BEAST_EXPECT(scAliceBal.diff() == -fee); - } - - // Non-existent bridge - XEnv(*this, true) - .tx(xchainCreateClaimId( - scAlice, bridge(mcAlice, mcAlice["USD"], scBob, scBob["USD"]), reward, mcAlice), - Ter(tecNO_ENTRY)) - .close(); - - // Creating the new object would put the account below the reserve - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .fund(res1 - xrpDust, scuAlice) // barely not enough - .close() - .tx(xchainCreateClaimId(scuAlice, jvb, reward, mcAlice), Ter(tecINSUFFICIENT_RESERVE)) - .close(); - - // The specified reward doesn't match the reward on the bridge (test - // by giving the reward amount for the other side, as well as a - // completely non-matching reward) - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, splitRewardQuorum, mcAlice), - Ter(tecXCHAIN_REWARD_MISMATCH)) - .close(); - - // A reward amount that isn't XRP - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, mcUSD(1), mcAlice), - Ter(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT)) - .close(); - - // coverage test: xchain_create_claim_id transaction with incorrect - // flag - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice), - Txflags(tfFillOrKill), - Ter(temINVALID_FLAG)) - .close(); - - // coverage test: xchain_create_claim_id transaction with xchain - // feature disabled - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .disableFeature(featureXChainBridge) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice), Ter(temDISABLED)) - .close(); - } - - void - testXChainCommit() - { - using namespace jtx; - XRPAmount const res0 = reserve(0); - XRPAmount const fee = txFee(); - - testcase("Commit"); - - // Commit to a non-existent bridge - XEnv(*this).tx(xchainCommit(mcAlice, jvb, 1, oneXrp, scBob), Ter(tecNO_ENTRY)); - - // check that reward not deducted when doing the commit - { - XEnv xenv(*this); - - test::Balance const aliceBal(xenv, mcAlice); - auto const amt = XRP(1000); - - xenv.tx(createBridge(mcDoor, jvb)) - .close() - .tx(xchainCommit(mcAlice, jvb, 1, amt, scBob)) - .close(); - - STAmount const claimCost = amt; - BEAST_EXPECT(aliceBal.diff() == -(claimCost + fee)); - } - - // Commit a negative amount - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .close() - .tx(xchainCommit(mcAlice, jvb, 1, XRP(-1), scBob), Ter(temBAD_AMOUNT)); - - // Commit an amount whose issue that does not match the expected - // issue on the bridge (either LockingChainIssue or - // IssuingChainIssue, depending on the chain). - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .close() - .tx(xchainCommit(mcAlice, jvb, 1, mcUSD(100), scBob), Ter(temBAD_ISSUER)); - - // Commit an amount that would put the sender below the required - // reserve (if XRP) - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .fund(res0 + oneXrp - xrpDust, mcuAlice) // barely not enough - .close() - .tx(xchainCommit(mcuAlice, jvb, 1, oneXrp, scBob), Ter(tecUNFUNDED_PAYMENT)); - - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .fund( - res0 + oneXrp + xrpDust, // "xrp_dust" for tx fees - mcuAlice) // exactly enough => should succeed - .close() - .tx(xchainCommit(mcuAlice, jvb, 1, oneXrp, scBob)); - - // Commit an amount above the account's balance (for both XRP and - // IOUs) - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .fund(res0, mcuAlice) // barely not enough - .close() - .tx(xchainCommit(mcuAlice, jvb, 1, res0 + oneXrp, scBob), Ter(tecUNFUNDED_PAYMENT)); - - auto jvbUsd = bridge(mcDoor, mcUSD, scGw, scUSD); - - // commit sent from iou issuer (mcGw) succeeds - should it? - XEnv(*this) - .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline - .tx(createBridge(mcDoor, jvbUsd)) - .close() - .tx(xchainCommit(mcGw, jvbUsd, 1, mcUSD(1), scBob)); - - // commit to a door account from the door account. This should fail. - XEnv(*this) - .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline - .tx(createBridge(mcDoor, jvbUsd)) - .close() - .tx(xchainCommit(mcDoor, jvbUsd, 1, mcUSD(1), scBob), Ter(tecXCHAIN_SELF_COMMIT)); - - // commit sent from mcAlice which has no IOU balance => should fail - XEnv(*this) - .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline - .tx(createBridge(mcDoor, jvbUsd)) - .close() - .tx(xchainCommit(mcAlice, jvbUsd, 1, mcUSD(1), scBob), Ter(terNO_LINE)); - - // commit sent from mcAlice which has no IOU balance => should fail - // just changed the destination to scGw (which is the door account - // and may not make much sense) - XEnv(*this) - .tx(trust(mcDoor, mcUSD(10000))) // door needs to have a trustline - .tx(createBridge(mcDoor, jvbUsd)) - .close() - .tx(xchainCommit(mcAlice, jvbUsd, 1, mcUSD(1), scGw), Ter(terNO_LINE)); - - // commit sent from mcAlice which has a IOU balance => should - // succeed - XEnv(*this) - .tx(trust(mcDoor, mcUSD(10000))) - .tx(trust(mcAlice, mcUSD(10000))) - .close() - .tx(pay(mcGw, mcAlice, mcUSD(10))) - .tx(createBridge(mcDoor, jvbUsd)) - .close() - //.tx(pay(mcAlice, mcDoor, mcUSD(10))); - .tx(xchainCommit(mcAlice, jvbUsd, 1, mcUSD(10), scAlice)); - - // coverage test: xchain_commit transaction with incorrect flag - XEnv(*this) - .tx(createBridge(mcDoor)) - .close() - .tx(xchainCommit(mcAlice, jvb, 1, oneXrp, scBob), - Txflags(tfFillOrKill), - Ter(temINVALID_FLAG)); - - // coverage test: xchain_commit transaction with xchain feature - // disabled - XEnv(*this) - .tx(createBridge(mcDoor)) - .disableFeature(featureXChainBridge) - .close() - .tx(xchainCommit(mcAlice, jvb, 1, oneXrp, scBob), Ter(temDISABLED)); - } - - void - testXChainAddAttestation() - { - using namespace jtx; - - testcase("Add Attestation"); - XRPAmount const res0 = reserve(0); - XRPAmount fee = txFee(); - - auto multiTtxFee = [&](std::uint32_t m) -> STAmount { - return multiply(fee, STAmount(m), xrpIssue()); - }; - - // Add an attestation to a claim id that has already reached quorum. - // This should succeed and share in the reward. - // note: this is true only when either: - // 1. dest account is not specified, so transfer requires a claim - // 2. or the extra attestation is sent in the same batch as the - // one reaching quorum - for (auto withClaim : {true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - std::uint32_t const claimID = 1; - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer(scEnv, Account::kMaster, scBob, scAlice, payees, withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, - jvb, - mcAlice, - amt, - payees, - true, - claimID, - dst, - signers, - kUtXchainDefaultQuorum)) - .close(); - scEnv - .tx(claimAttestation( - scAttester, - jvb, - mcAlice, - amt, - payees[kUtXchainDefaultQuorum], - true, - claimID, - dst, - signers[kUtXchainDefaultQuorum])) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - BEAST_EXPECT(!scEnv.claimID(jvb, claimID)); // claim id deleted - BEAST_EXPECT(scEnv.claimID(jvb) == claimID); - } - - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardEveryone)); - } - - // Test that signature weights are correctly handled. Assign - // signature weights of 1,2,4,4 and a quorum of 7. Check that the - // 4,4 signatures reach a quorum, the 1,2,4, reach a quorum, but the - // 4,2, 4,1 and 1,2 do not. - - // 1,2,4 => should succeed - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - std::uint32_t const quorum7 = 7; - std::vector const signers = [] { - static constexpr int kNumSigners = 4; - std::uint32_t const weights[] = {1, 2, 4, 4}; - - std::vector result; - result.reserve(kNumSigners); - for (int i = 0; i < kNumSigners; ++i) - { - using namespace std::literals; - auto const a = Account("signer_"s + std::to_string(i)); - result.emplace_back(a, weights[i]); - } - return result; - }(); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum7, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - std::uint32_t const claimID = 1; - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, Account::kMaster, scBob, scAlice, &payees[0], 3, withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers, 3)) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - BEAST_EXPECT(!scEnv.claimID(jvb, 1)); // claim id deleted - - BEAST_EXPECT(transfer.hasHappened(amt, divide(reward, STAmount(3), reward.asset()))); - } - - // 4,4 => should succeed - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - std::uint32_t const quorum7 = 7; - std::vector const signers = [] { - static constexpr int kNumSigners = 4; - std::uint32_t const weights[] = {1, 2, 4, 4}; - - std::vector result; - result.reserve(kNumSigners); - for (int i = 0; i < kNumSigners; ++i) - { - using namespace std::literals; - auto const a = Account("signer_"s + std::to_string(i)); - result.emplace_back(a, weights[i]); - } - return result; - }(); - STAmount const splitReward = divide(reward, STAmount(signers.size()), reward.asset()); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum7, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - std::uint32_t const claimID = 1; - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, Account::kMaster, scBob, scAlice, &payees[2], 2, withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers, 2, 2)) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - BEAST_EXPECT(!scEnv.claimID(jvb, claimID)); // claim id deleted - - BEAST_EXPECT(transfer.hasHappened(amt, divide(reward, STAmount(2), reward.asset()))); - } - - // 1,2 => should fail - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - std::uint32_t const quorum7 = 7; - std::vector const signers = [] { - static constexpr int kNumSigners = 4; - std::uint32_t const weights[] = {1, 2, 4, 4}; - - std::vector result; - result.reserve(kNumSigners); - for (int i = 0; i < kNumSigners; ++i) - { - using namespace std::literals; - auto const a = Account("signer_"s + std::to_string(i)); - result.emplace_back(a, weights[i]); - } - return result; - }(); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum7, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - std::uint32_t const claimID = 1; - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, Account::kMaster, scBob, scAlice, &payees[0], 2, withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers, 2)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv - .tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), - Ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); - } - - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id still present - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // 2,4 => should fail - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - std::uint32_t const quorum7 = 7; - std::vector const signers = [] { - static constexpr int kNumSigners = 4; - std::uint32_t const weights[] = {1, 2, 4, 4}; - - std::vector result; - result.reserve(kNumSigners); - for (int i = 0; i < kNumSigners; ++i) - { - using namespace std::literals; - auto const a = Account("signer_"s + std::to_string(i)); - result.emplace_back(a, weights[i]); - } - return result; - }(); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum7, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - std::uint32_t const claimID = 1; - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, Account::kMaster, scBob, scAlice, &payees[1], 2, withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers, 2, 1)) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv - .tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), - Ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); - } - - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id still present - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Confirm that account create transactions happen in the correct - // order. If they reach quorum out of order they should not execute - // until all the previous created transactions have occurred. - // Re-adding an attestation should move funds. - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - auto const amt = XRP(1000); - auto const amtPlusReward = amt + reward; - - { - test::Balance const door(mcEnv, mcDoor); - test::Balance const carol(mcEnv, mcCarol); - - mcEnv.tx(createBridge(mcDoor, jvb, reward, XRP(20))) - .close() - .tx(sidechainXchainAccountCreate(mcAlice, jvb, scuAlice, amt, reward)) - .tx(sidechainXchainAccountCreate(mcBob, jvb, scuBob, amt, reward)) - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuCarol, amt, reward)) - .close(); - - BEAST_EXPECT( - door.diff() == (multiply(amtPlusReward, STAmount(3), xrpIssue()) - fee)); - BEAST_EXPECT(carol.diff() == -(amt + reward + fee)); - } - - scEnv.tx(createBridge(Account::kMaster, jvb, reward, XRP(20))) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close(); - - { - // send first batch of account create attest for all 3 - // account create - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(1, amt, scuAlice, 2)) - .multiTx(attCreateAcctVec(3, amt, scuCarol, 2)) - .multiTx(attCreateAcctVec(2, amt, scuBob, 2)) - .close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - // att_create_acct_vec return vectors of size 2, so 2*3 txns - BEAST_EXPECT(attester.diff() == -multiTtxFee(6)); - - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // ca claim id present - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present - BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count still 0 - } - - { - // complete attestations for 2nd account create => should - // not complete - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(2, amt, scuBob, 3, 2)).close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - // att_create_acct_vec return vectors of size 3, so 3 txns - BEAST_EXPECT(attester.diff() == -multiTtxFee(3)); - - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // ca claim id present - BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count still 0 - } - - { - // complete attestations for 3rd account create => should - // not complete - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(3, amt, scuCarol, 3, 2)).close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - // att_create_acct_vec return vectors of size 3, so 3 txns - BEAST_EXPECT(attester.diff() == -multiTtxFee(3)); - - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // ca claim id present - BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count still 0 - } - - { - // complete attestations for 1st account create => account - // should be created - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(1, amt, scuAlice, 3, 1)).close(); - - BEAST_EXPECT(door.diff() == -amtPlusReward); - // att_create_acct_vec return vectors of size 3, so 3 txns - BEAST_EXPECT(attester.diff() == -multiTtxFee(3)); - BEAST_EXPECT(scEnv.balance(scuAlice) == amt); - - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id 1 deleted - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // claim id 2 present - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present - BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count now 1 - } - - { - // resend attestations for 3rd account create => still - // should not complete - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(3, amt, scuCarol, 3, 2)).close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - // att_create_acct_vec return vectors of size 3, so 3 txns - BEAST_EXPECT(attester.diff() == -multiTtxFee(3)); - - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 2)); // claim id 2 present - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present - BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count still 1 - } - - { - // resend attestations for 2nd account create => account - // should be created - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(2, amt, scuBob, 1)).close(); - - BEAST_EXPECT(door.diff() == -amtPlusReward); - BEAST_EXPECT(attester.diff() == -fee); - BEAST_EXPECT(scEnv.balance(scuBob) == amt); - - BEAST_EXPECT(!scEnv.caClaimID(jvb, 2)); // claim id 2 deleted - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 3)); // claim id 3 present - BEAST_EXPECT(scEnv.claimCount(jvb) == 2); // claim count now 2 - } - { - // resend attestations for 3rc account create => account - // should be created - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(3, amt, scuCarol, 1)).close(); - - BEAST_EXPECT(door.diff() == -amtPlusReward); - BEAST_EXPECT(attester.diff() == -fee); - BEAST_EXPECT(scEnv.balance(scuCarol) == amt); - - BEAST_EXPECT(!scEnv.caClaimID(jvb, 3)); // claim id 3 deleted - BEAST_EXPECT(scEnv.claimCount(jvb) == 3); // claim count now 3 - } - } - - // Check that creating an account with less than the minimum reserve - // fails. - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - auto const amt = res0 - XRP(1); - auto const amtPlusReward = amt + reward; - - mcEnv.tx(createBridge(mcDoor, jvb, reward, XRP(20))).close(); - - { - test::Balance const door(mcEnv, mcDoor); - test::Balance const carol(mcEnv, mcCarol); - - mcEnv.tx(sidechainXchainAccountCreate(mcCarol, jvb, scuAlice, amt, reward)).close(); - - BEAST_EXPECT(door.diff() == amtPlusReward); - BEAST_EXPECT(carol.diff() == -(amtPlusReward + fee)); - } - - scEnv.tx(createBridge(Account::kMaster, jvb, reward, XRP(20))) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close(); - - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - - scEnv.multiTx(attCreateAcctVec(1, amt, scuAlice, 2)).close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less - - scEnv.multiTx(attCreateAcctVec(1, amt, scuAlice, 2, 2)).close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented - - BEAST_EXPECT(attester.diff() == -multiTtxFee(4)); - BEAST_EXPECT(door.diff() == -reward); - BEAST_EXPECT(!scEnv.account(scuAlice)); - } - - // Check that sending funds with an account create txn to an - // existing account works. - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - auto const amt = XRP(111); - auto const amtPlusReward = amt + reward; - - mcEnv.tx(createBridge(mcDoor, jvb, reward, XRP(20))).close(); - - { - test::Balance const door(mcEnv, mcDoor); - test::Balance const carol(mcEnv, mcCarol); - - mcEnv.tx(sidechainXchainAccountCreate(mcCarol, jvb, scAlice, amt, reward)).close(); - - BEAST_EXPECT(door.diff() == amtPlusReward); - BEAST_EXPECT(carol.diff() == -(amtPlusReward + fee)); - } - - scEnv.tx(createBridge(Account::kMaster, jvb, reward, XRP(20))) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close(); - - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - test::Balance const alice(scEnv, scAlice); - - scEnv.multiTx(attCreateAcctVec(1, amt, scAlice, 2)).close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less - - scEnv.multiTx(attCreateAcctVec(1, amt, scAlice, 2, 2)).close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented - - BEAST_EXPECT(door.diff() == -amtPlusReward); - BEAST_EXPECT(attester.diff() == -multiTtxFee(4)); - BEAST_EXPECT(alice.diff() == amt); - } - - // Check that sending funds to an existing account with deposit auth - // set fails for account create transactions. - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - auto const amt = XRP(1000); - auto const amtPlusReward = amt + reward; - - mcEnv.tx(createBridge(mcDoor, jvb, reward, XRP(20))).close(); - - { - test::Balance const door(mcEnv, mcDoor); - test::Balance const carol(mcEnv, mcCarol); - - mcEnv.tx(sidechainXchainAccountCreate(mcCarol, jvb, scAlice, amt, reward)).close(); - - BEAST_EXPECT(door.diff() == amtPlusReward); - BEAST_EXPECT(carol.diff() == -(amtPlusReward + fee)); - } - - scEnv.tx(createBridge(Account::kMaster, jvb, reward, XRP(20))) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .tx(fset("scAlice", asfDepositAuth)) // set deposit auth - .close(); - - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - test::Balance const alice(scEnv, scAlice); - - scEnv.multiTx(attCreateAcctVec(1, amt, scAlice, 2)).close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less - - scEnv.multiTx(attCreateAcctVec(1, amt, scAlice, 2, 2)).close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented - - BEAST_EXPECT(door.diff() == -reward); - BEAST_EXPECT(attester.diff() == -multiTtxFee(4)); - BEAST_EXPECT(alice.diff() == STAmount(0)); - } - - // If an account is unable to pay the reserve, check that it fails. - // [greg todo] I don't know what this should test?? - - // If an attestation already exists for that server and claim id, - // the new attestation should replace the old attestation - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - auto const amt = XRP(1000); - auto const amtPlusReward = amt + reward; - - { - test::Balance const door(mcEnv, mcDoor); - test::Balance const carol(mcEnv, mcCarol); - - mcEnv.tx(createBridge(mcDoor, jvb, reward, XRP(20))) - .close() - .tx(sidechainXchainAccountCreate(mcAlice, jvb, scuAlice, amt, reward)) - .close() // make sure Alice gets claim #1 - .tx(sidechainXchainAccountCreate(mcBob, jvb, scuBob, amt, reward)) - .close() // make sure Bob gets claim #2 - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuCarol, amt, reward)) - .close(); // and Carol will get claim #3 - - BEAST_EXPECT( - door.diff() == (multiply(amtPlusReward, STAmount(3), xrpIssue()) - fee)); - BEAST_EXPECT(carol.diff() == -(amt + reward + fee)); - } - - std::uint32_t const redQuorum = 2; - scEnv.tx(createBridge(Account::kMaster, jvb, reward, XRP(20))) - .tx(jtx::signers(Account::kMaster, redQuorum, signers)) - .close(); - - { - test::Balance const attester(scEnv, scAttester); - test::Balance const door(scEnv, Account::kMaster); - auto const badAmt = XRP(10); - std::uint32_t txCount = 0; - - // send attestations with incorrect amounts to for all 3 - // AccountCreate. They will be replaced later - scEnv.multiTx(attCreateAcctVec(1, badAmt, scuAlice, 1)) - .multiTx(attCreateAcctVec(2, badAmt, scuBob, 1, 2)) - .multiTx(attCreateAcctVec(3, badAmt, scuCarol, 1, 1)) - .close(); - txCount += 3; - - BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 1), "claim id 1 created"); - BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 2), "claim id 2 created"); - BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 3), "claim id 3 created"); - - // note: if we send inconsistent attestations in the same - // batch, the transaction errors. - - // from now on we send correct attestations - scEnv.multiTx(attCreateAcctVec(1, amt, scuAlice, 1, 0)) - .multiTx(attCreateAcctVec(2, amt, scuBob, 1, 2)) - .multiTx(attCreateAcctVec(3, amt, scuCarol, 1, 4)) - .close(); - txCount += 3; - - BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 1), "claim id 1 still there"); - BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 2), "claim id 2 still there"); - BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 3), "claim id 3 still there"); - BEAST_EXPECTS(scEnv.claimCount(jvb) == 0, "No account created yet"); - - scEnv.multiTx(attCreateAcctVec(3, amt, scuCarol, 1, 1)).close(); - txCount += 1; - - BEAST_EXPECTS(!!scEnv.caClaimID(jvb, 3), "claim id 3 still there"); - BEAST_EXPECTS(scEnv.claimCount(jvb) == 0, "No account created yet"); - - scEnv.multiTx(attCreateAcctVec(1, amt, scuAlice, 1, 2)).close(); - txCount += 1; - - BEAST_EXPECTS(!scEnv.caClaimID(jvb, 1), "claim id 1 deleted"); - BEAST_EXPECTS(scEnv.claimCount(jvb) == 1, "scuAlice created"); - - scEnv.multiTx(attCreateAcctVec(2, amt, scuBob, 1, 3)) - .multiTx( - attCreateAcctVec(1, amt, scuAlice, 1, 3), - Ter(tecXCHAIN_ACCOUNT_CREATE_PAST)) - .close(); - txCount += 2; - - BEAST_EXPECTS(!scEnv.caClaimID(jvb, 2), "claim id 2 deleted"); - BEAST_EXPECTS(!scEnv.caClaimID(jvb, 1), "claim id 1 not added"); - BEAST_EXPECTS(scEnv.claimCount(jvb) == 2, "scuAlice & scuBob created"); - - scEnv.multiTx(attCreateAcctVec(3, amt, scuCarol, 1, 0)).close(); - txCount += 1; - - BEAST_EXPECTS(!scEnv.caClaimID(jvb, 3), "claim id 3 deleted"); - BEAST_EXPECTS(scEnv.claimCount(jvb) == 3, "All 3 accounts created"); - - // because of the division of the rewards among attesters, - // sometimes a couple drops are left over unspent in the - // door account (here 2 drops) - BEAST_EXPECT( - multiply(amtPlusReward, STAmount(3), xrpIssue()) + door.diff() < drops(3)); - BEAST_EXPECT(attester.diff() == -multiTtxFee(txCount)); - BEAST_EXPECT(scEnv.balance(scuAlice) == amt); - BEAST_EXPECT(scEnv.balance(scuBob) == amt); - BEAST_EXPECT(scEnv.balance(scuCarol) == amt); - } - } - - // If attestation moves funds, confirm the claim ledger objects are - // removed (for both account create and "regular" transactions) - // [greg] we do this in all attestation tests - - // coverage test: add_attestation transaction with incorrect flag - { - XEnv scEnv(*this, true); - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(claimAttestation( - scAttester, jvb, mcAlice, XRP(1000), payees[0], true, 1, {}, signers[0]), - Txflags(tfFillOrKill), - Ter(temINVALID_FLAG)) - .close(); - } - - // coverage test: add_attestation with xchain feature - // disabled - { - XEnv scEnv(*this, true); - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .disableFeature(featureXChainBridge) - .close() - .tx(claimAttestation( - scAttester, jvb, mcAlice, XRP(1000), payees[0], true, 1, {}, signers[0]), - Ter(temDISABLED)) - .close(); - } - } - - void - testXChainAddClaimNonBatchAttestation() - { - using namespace jtx; - - testcase("Add Non Batch Claim Attestation"); - - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - std::uint32_t const claimID = 1; - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - BEAST_EXPECT(!!scEnv.claimID(jvb, claimID)); // claim id present - - Account const dst{scBob}; - auto const amt = XRP(1000); - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - auto const dstStartBalance = scEnv.env.balance(dst); - - for (int i = 0; i < signers.size(); ++i) - { - auto const att = claimAttestation( - scAttester, jvb, mcAlice, amt, payees[i], true, claimID, dst, signers[i]); - - TER const expectedTER = i < quorum ? tesSUCCESS : TER{tecXCHAIN_NO_CLAIM_ID}; - scEnv.tx(att, Ter(expectedTER)).close(); - - if (i + 1 < quorum) - { - BEAST_EXPECT(dstStartBalance == scEnv.env.balance(dst)); - } - else - { - BEAST_EXPECT(dstStartBalance + amt == scEnv.env.balance(dst)); - } - } - BEAST_EXPECT(dstStartBalance + amt == scEnv.env.balance(dst)); - } - - { - /** - * sfAttestationSignerAccount related cases. - * - * Good cases: - * --G1: master key - * --G2: regular key - * --G3: public key and non-exist (unfunded) account match - * - * Bad cases: - * --B1: disabled master key - * --B2: single item signer list - * --B3: public key and non-exist (unfunded) account mismatch - * --B4: not on signer list - * --B5: missing sfAttestationSignerAccount field - */ - - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - - for (auto i = 0; i < kUtXchainDefaultNumSigners - 2; ++i) - scEnv.fund(amt, altSigners[i].account); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, altSigners)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - Account const dst{scBob}; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - auto const dstStartBalance = scEnv.env.balance(dst); - - { - // G1: master key - auto att = claimAttestation( - scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, altSigners[0]); - scEnv.tx(att).close(); - } - { - // G2: regular key - // alt_signers[0] is the regular key of alt_signers[1] - // There should be 2 attestations after the transaction - scEnv.tx(jtx::regkey(altSigners[1].account, altSigners[0].account)).close(); - auto att = claimAttestation( - scAttester, jvb, mcAlice, amt, payees[1], true, claimID, dst, altSigners[0]); - att[sfAttestationSignerAccount.getJsonName()] = altSigners[1].account.human(); - scEnv.tx(att).close(); - } - { - // B3: public key and non-exist (unfunded) account mismatch - // G3: public key and non-exist (unfunded) account match - auto const unfundedSigner1 = altSigners[kUtXchainDefaultNumSigners - 1]; - auto const unfundedSigner2 = altSigners[kUtXchainDefaultNumSigners - 2]; - auto att = claimAttestation( - scAttester, - jvb, - mcAlice, - amt, - payees[kUtXchainDefaultNumSigners - 1], - true, - claimID, - dst, - unfundedSigner1); - att[sfAttestationSignerAccount.getJsonName()] = unfundedSigner2.account.human(); - scEnv.tx(att, Ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)).close(); - att[sfAttestationSignerAccount.getJsonName()] = unfundedSigner1.account.human(); - scEnv.tx(att).close(); - } - { - // B2: single item signer list - std::vector tempSignerList = {signers[0]}; - scEnv.tx(jtx::signers(altSigners[2].account, 1, tempSignerList)); - auto att = claimAttestation( - scAttester, - jvb, - mcAlice, - amt, - payees[2], - true, - claimID, - dst, - tempSignerList.front()); - att[sfAttestationSignerAccount.getJsonName()] = altSigners[2].account.human(); - scEnv.tx(att, Ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)).close(); - } - { - // B1: disabled master key - scEnv.tx(fset(altSigners[2].account, asfDisableMaster, 0)).close(); - auto att = claimAttestation( - scAttester, jvb, mcAlice, amt, payees[2], true, claimID, dst, altSigners[2]); - scEnv.tx(att, Ter(tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR)).close(); - } - { - // --B4: not on signer list - auto att = claimAttestation( - scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, signers[0]); - scEnv.tx(att, Ter(tecNO_PERMISSION)).close(); - } - { - // --B5: missing sfAttestationSignerAccount field - // Then submit the one with the field. Should reach quorum. - auto att = claimAttestation( - scAttester, jvb, mcAlice, amt, payees[3], true, claimID, dst, altSigners[3]); - att.removeMember(sfAttestationSignerAccount.getJsonName()); - scEnv.tx(att, Ter(temMALFORMED)).close(); - BEAST_EXPECT(dstStartBalance == scEnv.env.balance(dst)); - att[sfAttestationSignerAccount.getJsonName()] = altSigners[3].account.human(); - scEnv.tx(att).close(); - BEAST_EXPECT(dstStartBalance + amt == scEnv.env.balance(dst)); - } - } - } - - void - testXChainAddAccountCreateNonBatchAttestation() // cspell: disable-line - { - using namespace jtx; - - testcase("Add Non Batch Account Create Attestation"); - - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - XRPAmount const txFee = mcEnv.txFee(); - - Account const a{"a"}; - Account const doorA{"doorA"}; - - STAmount const funds{XRP(10000)}; - mcEnv.fund(funds, a); - mcEnv.fund(funds, doorA); - - Account const ua{"ua"}; // unfunded account we want to create - - BridgeDef xrpB{ - .doorA = doorA, - .issueA = xrpIssue(), - .doorB = Account::kMaster, - .issueB = xrpIssue(), - .reward = XRP(1), // reward - .minAccountCreate = XRP(20), // minAccountCreate - .quorum = 4, // quorum - .signers = signers, - .jvb = json::ValueType::Null}; - - xrpB.initBridge(mcEnv, scEnv); - - auto const amt = XRP(777); - auto const amtPlusReward = amt + xrpB.reward; - { - test::Balance const balDoorA(mcEnv, doorA); - test::Balance const balA(mcEnv, a); - - mcEnv.tx(sidechainXchainAccountCreate(a, xrpB.jvb, ua, amt, xrpB.reward)).close(); - - BEAST_EXPECT(balDoorA.diff() == amtPlusReward); - BEAST_EXPECT(balA.diff() == -(amtPlusReward + txFee)); - } - - for (int i = 0; i < signers.size(); ++i) - { - auto const att = createAccountAttestation( - signers[0].account, - xrpB.jvb, - a, - amt, - xrpB.reward, - signers[i].account, - true, - 1, - ua, - signers[i]); - TER const expectedTER = - i < xrpB.quorum ? tesSUCCESS : TER{tecXCHAIN_ACCOUNT_CREATE_PAST}; - - scEnv.tx(att, Ter(expectedTER)).close(); - if (i + 1 < xrpB.quorum) - { - BEAST_EXPECT(!scEnv.env.le(ua)); - } - else - { - BEAST_EXPECT(scEnv.env.le(ua)); - } - } - BEAST_EXPECT(scEnv.env.le(ua)); - } - - void - testXChainClaim() - { - using namespace jtx; - - XRPAmount const res0 = reserve(0); - XRPAmount const fee = txFee(); - - testcase("Claim"); - - // Claim where the amount matches what is attested to, to an account - // that exists, and there are enough attestations to reach a quorum - // => should succeed - // ----------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum)); - } - - // Claim with just one attestation signed by the Master key - // => should not succeed - // ----------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv - .tx(createBridge(Account::kMaster, jvb)) - //.tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, Account::kMaster, scBob, scAlice, &payees[0], 1, withClaim); - - jtx::Signer const masterSigner(Account::kMaster); - scEnv - .tx(claimAttestation( - scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, masterSigner), - Ter(tecXCHAIN_NO_SIGNERS_LIST)) - .close(); - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim with just one attestation signed by a regular key - // associated to the master account - // => should not succeed - // ----------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv - .tx(createBridge(Account::kMaster, jvb)) - //.tx(jtx::signers(Account::kMaster, quorum, signers)) - .tx(jtx::regkey(Account::kMaster, payees[0])) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, Account::kMaster, scBob, scAlice, &payees[0], 1, withClaim); - - jtx::Signer const masterSigner(payees[0]); - scEnv - .tx(claimAttestation( - scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, masterSigner), - Ter(tecXCHAIN_NO_SIGNERS_LIST)) - .close(); - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim against non-existent bridge - // --------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - auto jvbUnknown = bridge(mcBob, xrpIssue(), Account::kMaster, xrpIssue()); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvbUnknown, reward, mcAlice), Ter(tecNO_ENTRY)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvbUnknown, claimID, amt, dst), Ter(tecNO_ENTRY)) - .close(); - - BalanceTransfer transfer(scEnv, Account::kMaster, scBob, scAlice, payees, withClaim); - scEnv - .tx(claimAttestation( - scAttester, - jvbUnknown, - mcAlice, - amt, - payees[0], - true, - claimID, - dst, - signers[0]), - Ter(tecNO_ENTRY)) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvbUnknown, claimID, amt, scBob), Ter(tecNO_ENTRY)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim against non-existent claim id - // ----------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer(scEnv, Account::kMaster, scBob, scAlice, payees, withClaim); - - // attest using non-existent claim id - scEnv - .tx(claimAttestation( - scAttester, jvb, mcAlice, amt, payees[0], true, 999, dst, signers[0]), - Ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // claim using non-existent claim id - scEnv.tx(xchainClaim(scAlice, jvb, 999, amt, scBob), Ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim against a claim id owned by another account - // ------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // submit a claim transaction with the wrong account (scGw - // instead of scAlice) - scEnv.tx(xchainClaim(scGw, jvb, claimID, amt, scBob), Ter(tecXCHAIN_BAD_CLAIM_ID)) - .close(); - BEAST_EXPECT(transfer.hasNotHappened()); - } - else - { - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum)); - } - } - - // Claim against a claim id with no attestations - // --------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer(scEnv, Account::kMaster, scBob, scAlice, payees, withClaim); - - // don't send any attestations - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv - .tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), - Ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim against a claim id with attestations, but not enough to - // make a quorum - // -------------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer(scEnv, Account::kMaster, scBob, scAlice, payees, withClaim); - - auto tooFew = quorum - 1; - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers, tooFew)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv - .tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), - Ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim id of zero - // ---------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer(scEnv, Account::kMaster, scBob, scAlice, payees, withClaim); - - scEnv - .multiTx( - claimAttestations(scAttester, jvb, mcAlice, amt, payees, true, 0, dst, signers), - Ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, 0, amt, scBob), Ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim issue that does not match the expected issue on the bridge - // (either LockingChainIssue or IssuingChainIssue, depending on the - // chain). The claim id should already have enough attestations to - // reach a quorum for this amount (for a different issuer). - // --------------------------------------------------------------------- - for (auto withClaim : {true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) - .close(); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, scUSD(1000), scBob), Ter(temBAD_AMOUNT)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim to a destination that does not already exist on the chain - // ----------------------------------------------------------------- - for (auto withClaim : {true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scuBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scuBob), Ter(tecNO_DST)).close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim where the claim id owner does not have enough XRP to pay - // the reward - // ------------------------------------------------------------------ - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - STAmount const hugeReward{XRP(20000)}; - BEAST_EXPECT(hugeReward > scEnv.balance(scAlice)); - - scEnv.tx(createBridge(Account::kMaster, jvb, hugeReward)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, hugeReward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - - if (withClaim) - { - scEnv - .multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)) - .close(); - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), Ter(tecUNFUNDED_PAYMENT)) - .close(); - } - else - { - auto txns = claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers); - for (int i = 0; i < kUtXchainDefaultQuorum - 1; ++i) - { - scEnv.tx(txns[i]).close(); - } - scEnv.tx(txns.back()); - scEnv.close(); - // The attestation should succeed, because it adds an - // attestation, but the claim should fail with insufficient - // funds - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), Ter(tecUNFUNDED_PAYMENT)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Claim where the claim id owner has enough XRP to pay the reward, - // but it would put his balance below the reserve - // -------------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .fund( - res0 + reward, - scuAlice) // just not enough because of fees - .close() - .tx(xchainCreateClaimId(scuAlice, jvb, reward, mcAlice), - Ter(tecINSUFFICIENT_RESERVE)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer(scEnv, Account::kMaster, scBob, scuAlice, payees, withClaim); - - scEnv - .tx(claimAttestation( - scAttester, jvb, mcAlice, amt, payees[0], true, claimID, dst, signers[0]), - Ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv - .tx(xchainClaim(scuAlice, jvb, claimID, amt, scBob), Ter(tecXCHAIN_NO_CLAIM_ID)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Pay to an account with deposit auth set - // --------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .tx(fset("scBob", asfDepositAuth)) // set deposit auth - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - auto txns = claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers); - for (int i = 0; i < kUtXchainDefaultQuorum - 1; ++i) - { - scEnv.tx(txns[i]).close(); - } - if (withClaim) - { - scEnv.tx(txns.back()).close(); - - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), Ter(tecNO_PERMISSION)) - .close(); - - // the transfer failed, but check that we can still use the - // claimID with a different account - test::Balance const scCarolBal(scEnv, scCarol); - - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scCarol)).close(); - BEAST_EXPECT(scCarolBal.diff() == amt); - } - else - { - scEnv.tx(txns.back()).close(); - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), Ter(tecNO_PERMISSION)) - .close(); - // A way would be to remove deposit auth and resubmit the - // attestations (even though the witness servers won't do - // it) - scEnv - .tx(fset("scBob", 0, asfDepositAuth)) // clear deposit auth - .close(); - - test::Balance const scBobBal(scEnv, scBob); - scEnv.tx(txns.back()).close(); - BEAST_EXPECT(scBobBal.diff() == amt); - } - } - - // Pay to an account with Destination Tag set - // ------------------------------------------ - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .tx(fset("scBob", asfRequireDest)) // set dest tag - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - auto txns = claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers); - for (int i = 0; i < kUtXchainDefaultQuorum - 1; ++i) - { - scEnv.tx(txns[i]).close(); - } - if (withClaim) - { - scEnv.tx(txns.back()).close(); - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), Ter(tecDST_TAG_NEEDED)) - .close(); - - // the transfer failed, but check that we can still use the - // claimID with a different account - test::Balance const scCarolBal(scEnv, scCarol); - - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scCarol)).close(); - BEAST_EXPECT(scCarolBal.diff() == amt); - } - else - { - scEnv.tx(txns.back()).close(); - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob), Ter(tecDST_TAG_NEEDED)) - .close(); - // A way would be to remove the destination tag requirement - // and resubmit the attestations (even though the witness - // servers won't do it) - scEnv - .tx(fset("scBob", 0, asfRequireDest)) // clear dest tag - .close(); - - test::Balance const scBobBal(scEnv, scBob); - - scEnv.tx(txns.back()).close(); - BEAST_EXPECT(scBobBal.diff() == amt); - } - } - - // Pay to an account with deposit auth set. Check that the attestations - // are still validated and that we can used the claimID to transfer the - // funds to a different account (which doesn't have deposit auth set) - // -------------------------------------------------------------------- - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .tx(fset("scBob", asfDepositAuth)) // set deposit auth - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - // we should be able to submit the attestations, but the transfer - // should not occur because dest account has deposit auth set - test::Balance const scBobBal(scEnv, scBob); - - scEnv.multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); - BEAST_EXPECT(scBobBal.diff() == STAmount(0)); - - // Check that check that we still can use the claimID to transfer - // the amount to a different account - test::Balance const scCarolBal(scEnv, scCarol); - - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scCarol)).close(); - BEAST_EXPECT(scCarolBal.diff() == amt); - } - - // Claim where the amount different from what is attested to - // --------------------------------------------------------- - for (auto withClaim : {true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - scEnv.multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // claim wrong amount - scEnv - .tx(xchainClaim(scAlice, jvb, claimID, oneXrp, scBob), - Ter(tecXCHAIN_CLAIM_NO_QUORUM)) - .close(); - } - - BEAST_EXPECT(transfer.hasNotHappened()); - } - - // Verify that rewards are paid from the account that owns the claim - // id - // -------------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - test::Balance const scAliceBal(scEnv, scAlice); - scEnv.multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); - - STAmount claimCost = reward; - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - claimCost += fee; - } - - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum)); - BEAST_EXPECT(scAliceBal.diff() == -claimCost); // because reward % 4 == 0 - } - - // Verify that if a reward is not evenly divisible among the reward - // accounts, the remaining amount goes to the claim id owner. - // ---------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb, tinyReward)).close(); - - scEnv.tx(createBridge(Account::kMaster, jvb, tinyReward)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, tinyReward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum, - withClaim); - test::Balance const scAliceBal(scEnv, scAlice); - scEnv.multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); - STAmount claimCost = tinyReward; - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - claimCost += fee; - } - - BEAST_EXPECT(transfer.hasHappened(amt, tinyRewardSplit)); - BEAST_EXPECT(scAliceBal.diff() == -(claimCost - tinyRewardRemainder)); - } - - // If a reward distribution fails for one of the reward accounts - // (the reward account doesn't exist or has deposit auth set), then - // the txn should still succeed, but that portion should go to the - // claim id owner. - // ------------------------------------------------------------------- - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - - std::vector altPayees{payees.begin(), payees.end() - 1}; - altPayees.back() = Account("inexistent"); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum - 1, - withClaim); - scEnv.multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, altPayees, true, claimID, dst, signers)); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - // this also checks that only 3 * split_reward was deducted from - // scAlice (the payer account), since we passed alt_payees to - // BalanceTransfer - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum)); - } - - for (auto withClaim : {false, true}) - { - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - mcEnv.tx(createBridge(mcDoor, jvb)).close(); - auto& unpaid = payees[kUtXchainDefaultQuorum - 1]; - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .tx(fset(unpaid, asfDepositAuth)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - auto dst(withClaim ? std::nullopt : std::optional{scBob}); - auto const amt = XRP(1000); - std::uint32_t const claimID = 1; - mcEnv.tx(xchainCommit(mcAlice, jvb, claimID, amt, dst)).close(); - - // balance of last signer should not change (has deposit auth) - test::Balance const lastSigner(scEnv, unpaid); - - // make sure all signers except the last one get the - // split_reward - - BalanceTransfer transfer( - scEnv, - Account::kMaster, - scBob, - scAlice, - &payees[0], - kUtXchainDefaultQuorum - 1, - withClaim); - scEnv.multiTx(claimAttestations( - scAttester, jvb, mcAlice, amt, payees, true, claimID, dst, signers)); - - if (withClaim) - { - BEAST_EXPECT(transfer.hasNotHappened()); - - // need to submit a claim transactions - scEnv.tx(xchainClaim(scAlice, jvb, claimID, amt, scBob)).close(); - } - - // this also checks that only 3 * split_reward was deducted from - // scAlice (the payer account), since we passed payees.size() - - // 1 to BalanceTransfer - BEAST_EXPECT(transfer.hasHappened(amt, splitRewardQuorum)); - - // and make sure the account with deposit auth received nothing - BEAST_EXPECT(lastSigner.diff() == STAmount(0)); - } - - // coverage test: xchain_claim transaction with incorrect flag - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .close() - .tx(xchainClaim(scAlice, jvb, 1, XRP(1000), scBob), - Txflags(tfFillOrKill), - Ter(temINVALID_FLAG)) - .close(); - - // coverage test: xchain_claim transaction with xchain feature - // disabled - XEnv(*this, true) - .tx(createBridge(Account::kMaster, jvb)) - .disableFeature(featureXChainBridge) - .close() - .tx(xchainClaim(scAlice, jvb, 1, XRP(1000), scBob), Ter(temDISABLED)) - .close(); - - // coverage test: XChainClaim::preclaim - isLockingChain = true; - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .close() - .tx(xchainClaim(mcAlice, jvb, 1, XRP(1000), mcBob), Ter(tecXCHAIN_NO_CLAIM_ID)); - } - - void - testXChainCreateAccount() - { - using namespace jtx; - - testcase("Bridge Create Account"); - XRPAmount const fee = txFee(); - - // coverage test: transferHelper() - dst == src - { - XEnv scEnv(*this, true); - - auto const amt = XRP(111); - auto const amtPlusReward = amt + reward; - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close(); - - test::Balance const door(scEnv, Account::kMaster); - - // scEnv.tx(att_create_acct_batch1(1, amt, - // Account::kMaster)).close(); - scEnv.multiTx(attCreateAcctVec(1, amt, Account::kMaster, 2)).close(); - BEAST_EXPECT(!!scEnv.caClaimID(jvb, 1)); // claim id present - BEAST_EXPECT(scEnv.claimCount(jvb) == 0); // claim count is one less - - // scEnv.tx(att_create_acct_batch2(1, amt, - // Account::kMaster)).close(); - scEnv.multiTx(attCreateAcctVec(1, amt, Account::kMaster, 2, 2)).close(); - BEAST_EXPECT(!scEnv.caClaimID(jvb, 1)); // claim id deleted - BEAST_EXPECT(scEnv.claimCount(jvb) == 1); // claim count was incremented - - BEAST_EXPECT(door.diff() == -reward); - } - - // Check that creating an account with less than the minimum create - // amount fails. - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))).close(); - - test::Balance const door(mcEnv, mcDoor); - test::Balance const carol(mcEnv, mcCarol); - - mcEnv - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuAlice, XRP(19), reward), - Ter(tecXCHAIN_INSUFF_CREATE_AMOUNT)) - .close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - BEAST_EXPECT(carol.diff() == -fee); - } - - // Check that creating an account with invalid flags fails. - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))).close(); - - test::Balance const door(mcEnv, mcDoor); - - mcEnv - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuAlice, XRP(20), reward), - Txflags(tfFillOrKill), - Ter(temINVALID_FLAG)) - .close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - } - - // Check that creating an account with the XChainBridge feature - // disabled fails. - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))).close(); - - test::Balance const door(mcEnv, mcDoor); - - mcEnv.disableFeature(featureXChainBridge) - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuAlice, XRP(20), reward), - Ter(temDISABLED)) - .close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - } - - // Check that creating an account with a negative amount fails - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))).close(); - - test::Balance const door(mcEnv, mcDoor); - - mcEnv - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuAlice, XRP(-20), reward), - Ter(temBAD_AMOUNT)) - .close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - } - - // Check that creating an account with a negative reward fails - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))).close(); - - test::Balance const door(mcEnv, mcDoor); - - mcEnv - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuAlice, XRP(20), XRP(-1)), - Ter(temBAD_AMOUNT)) - .close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - } - - // Check that door account can't lock funds onto itself - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))).close(); - - test::Balance const door(mcEnv, mcDoor); - - mcEnv - .tx(sidechainXchainAccountCreate(mcDoor, jvb, scuAlice, XRP(20), XRP(1)), - Ter(tecXCHAIN_SELF_COMMIT)) - .close(); - - BEAST_EXPECT(door.diff() == -fee); - } - - // Check that reward matches the amount specified in bridge - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(20))).close(); - - test::Balance const door(mcEnv, mcDoor); - - mcEnv - .tx(sidechainXchainAccountCreate(mcCarol, jvb, scuAlice, XRP(20), XRP(2)), - Ter(tecXCHAIN_REWARD_MISMATCH)) - .close(); - - BEAST_EXPECT(door.diff() == STAmount(0)); - } - } - - void - testFeeDipsIntoReserve() - { - using namespace jtx; - XRPAmount const res0 = reserve(0); - XRPAmount const fee = txFee(); - - testcase("Fee dips into reserve"); - - // commit where the fee dips into the reserve, this should succeed - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .fund(res0 + oneXrp + fee - drops(1), mcuAlice) - .close() - .tx(xchainCommit(mcuAlice, jvb, 1, oneXrp, scBob), Ter(tesSUCCESS)); - - // commit where the commit amount drips into the reserve, this should - // fail - XEnv(*this) - .tx(createBridge(mcDoor, jvb)) - .fund(res0 + oneXrp - drops(1), mcuAlice) - .close() - .tx(xchainCommit(mcuAlice, jvb, 1, oneXrp, scBob), Ter(tecUNFUNDED_PAYMENT)); - - auto const minAccountCreate = XRP(20); - - // account create commit where the fee dips into the reserve, - // this should succeed - XEnv(*this) - .tx(createBridge(mcDoor, jvb, reward, minAccountCreate)) - .fund(res0 + fee + minAccountCreate + reward - drops(1), mcuAlice) - .close() - .tx(sidechainXchainAccountCreate(mcuAlice, jvb, scuAlice, minAccountCreate, reward), - Ter(tesSUCCESS)); - - // account create commit where the commit dips into the reserve, - // this should fail - XEnv(*this) - .tx(createBridge(mcDoor, jvb, reward, minAccountCreate)) - .fund(res0 + minAccountCreate + reward - drops(1), mcuAlice) - .close() - .tx(sidechainXchainAccountCreate(mcuAlice, jvb, scuAlice, minAccountCreate, reward), - Ter(tecUNFUNDED_PAYMENT)); - } - - void - testXChainDeleteDoor() - { - using namespace jtx; - - testcase("Bridge Delete Door Account"); - - auto const acctDelFee{drops(XEnv(*this).env.current()->fees().increment)}; - - // Deleting an account that owns bridge should fail - { - XEnv mcEnv(*this); - - mcEnv.tx(createBridge(mcDoor, jvb, XRP(1), XRP(1))).close(); - - // We don't allow an account to be deleted if its sequence - // number is within 256 of the current ledger. - for (size_t i = 0; i < 256; ++i) - mcEnv.close(); - - // try to delete mcDoor, send funds to mcAlice - mcEnv.tx(acctdelete(mcDoor, mcAlice), Fee(acctDelFee), Ter(tecHAS_OBLIGATIONS)); - } - - // Deleting an account that owns a claim id should fail - { - XEnv scEnv(*this, true); - - scEnv.tx(createBridge(Account::kMaster, jvb)) - .close() - .tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)) - .close(); - - // We don't allow an account to be deleted if its sequence - // number is within 256 of the current ledger. - for (size_t i = 0; i < 256; ++i) - scEnv.close(); - - // try to delete scAlice, send funds to scBob - scEnv.tx(acctdelete(scAlice, scBob), Fee(acctDelFee), Ter(tecHAS_OBLIGATIONS)); - } - } - - void - testBadPublicKey() - { - using namespace jtx; - - testcase("Bad attestations"); - { - // Create a bridge and add an attestation with a bad public key - XEnv scEnv(*this, true); - std::uint32_t const claimID = 1; - std::optional const dst{scBob}; - auto const amt = XRP(1000); - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close(); - scEnv.tx(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)).close(); - auto jvAtt = claimAttestation( - scAttester, - jvb, - mcAlice, - amt, - payees[kUtXchainDefaultQuorum], - true, - claimID, - dst, - signers[kUtXchainDefaultQuorum]); - { - // Change to an invalid keytype - auto k = jvAtt["PublicKey"].asString(); - k.at(1) = '9'; - jvAtt["PublicKey"] = k; - } - scEnv.tx(jvAtt, Ter(temMALFORMED)).close(); - } - { - // Create a bridge and add an create account attestation with a bad - // public key - XEnv scEnv(*this, true); - std::uint32_t const createCount = 1; - Account const dst{scBob}; - auto const amt = XRP(1000); - auto const rewardAmt = XRP(1); - scEnv.tx(createBridge(Account::kMaster, jvb)) - .tx(jtx::signers(Account::kMaster, quorum, signers)) - .close(); - auto jvAtt = createAccountAttestation( - scAttester, - jvb, - mcAlice, - amt, - rewardAmt, - payees[kUtXchainDefaultQuorum], - true, - createCount, - dst, - signers[kUtXchainDefaultQuorum]); - { - // Change to an invalid keytype - auto k = jvAtt["PublicKey"].asString(); - k.at(1) = '9'; - jvAtt["PublicKey"] = k; - } - scEnv.tx(jvAtt, Ter(temMALFORMED)).close(); - } - } - - void - run() override - { - testXChainBridgeExtraFields(); - testXChainCreateBridge(); - testXChainBridgeCreateConstraints(); - testXChainCreateBridgeMatrix(); - testXChainModifyBridge(); - testXChainCreateClaimID(); - testXChainCommit(); - testXChainAddAttestation(); - testXChainAddClaimNonBatchAttestation(); - testXChainAddAccountCreateNonBatchAttestation(); // cspell: disable-line - testXChainClaim(); - testXChainCreateAccount(); - testFeeDipsIntoReserve(); - testXChainDeleteDoor(); - testBadPublicKey(); - } -}; - -// ----------------------------------------------------------- -// ----------------------------------------------------------- -struct XChainSim_test : public beast::unit_test::Suite, public jtx::XChainBridgeObjects -{ -private: - static constexpr size_t kNumSigners = 5; - - // -------------------------------------------------- - enum class WithClaim { No, Yes }; - struct Transfer - { - jtx::Account from; - jtx::Account to; - jtx::Account finaldest; - STAmount amt; - bool a2b; // direction of transfer - WithClaim withClaim{WithClaim::No}; - uint32_t claimId{0}; - std::array attested{}; - }; - - struct AccountCreate - { - jtx::Account from; - jtx::Account to; - STAmount amt; - STAmount reward; - bool a2b; - uint32_t claimId{0}; - std::array attested{}; - }; - - using ENV = XEnv; - using BridgeID = BridgeDef const*; - - // tracking chain state - // -------------------- - struct AccountStateTrack - { - STAmount startAmount{0}; - STAmount expectedDiff{0}; - - void - init(ENV& env, jtx::Account const& acct) - { - startAmount = env.balance(acct); - expectedDiff = STAmount(0); - } - - bool - verify(ENV& env, jtx::Account const& acct) const - { - STAmount const diff{env.balance(acct) - startAmount}; - bool const check = diff == expectedDiff; - return check; - } - }; - - // -------------------------------------------------- - struct ChainStateTrack - { - using ClaimVec = jtx::JValueVec; - using CreateClaimVec = jtx::JValueVec; - using CreateClaimMap = std::map; - - ChainStateTrack(ENV& env) : env(env), txFee(env.env.current()->fees().base) - { - } - - void - sendAttestations(size_t signerIdx, BridgeID bridge, ClaimVec& claims) - { - for (auto const& c : claims) - { - env.tx(c).close(); - spendFee(bridge->signers[signerIdx].account); - } - claims.clear(); - } - - uint32_t - sendCreateAttestations(size_t signerIdx, BridgeID bridge, CreateClaimVec& claims) - { - size_t numSuccessful = 0; - for (auto const& c : claims) - { - env.tx(c).close(); - if (env.ter() == tesSUCCESS) - { - counters[bridge].signers.push_back(signerIdx); - numSuccessful++; - } - spendFee(bridge->signers[signerIdx].account); - } - claims.clear(); - return numSuccessful; - } - - void - sendAttestations() - { - bool callbackCalled = false; - - // we have this "do {} while" loop because we want to process - // all the account create which can reach quorum at this time - // stamp. - do - { - callbackCalled = false; - // cspell: ignore attns - for (size_t i = 0; i < signersAttns.size(); ++i) - { - for (auto& [bridge, claims] : signersAttns[i]) - { - sendAttestations(i, bridge, claims.xferClaims); - - auto& c = counters[bridge]; - auto& createClaims = claims.createClaims[c.claimCount]; - auto numAttns = createClaims.size(); - if (numAttns != 0u) - { - c.numCreateAttnSent += sendCreateAttestations(i, bridge, createClaims); - } - assert(claims.createClaims[c.claimCount].empty()); - } - } - for (auto& [bridge, c] : counters) - { - if (c.numCreateAttnSent >= bridge->quorum) - { - callbackCalled = true; - c.createCallbacks[c.claimCount](c.signers); - ++c.claimCount; - c.numCreateAttnSent = 0; - c.signers.clear(); - } - } - } while (callbackCalled); - } - - void - init(jtx::Account const& acct) - { - accounts[acct].init(env, acct); - } - - void - receive(jtx::Account const& acct, STAmount amt, std::uint64_t divisor = 1) - { - if (amt.asset() != xrpIssue()) - return; - auto it = accounts.find(acct); - if (it == accounts.end()) - { - accounts[acct].init(env, acct); - // we just looked up the account, so expectedDiff == 0 - } - else - { - it->second.expectedDiff += - (divisor == 1 ? amt : divide(amt, STAmount(amt.asset(), divisor), amt.asset())); - } - } - - void - spend(jtx::Account const& acct, STAmount amt, std::uint64_t times = 1) - { - if (amt.asset() != xrpIssue()) - return; - receive( - acct, - times == 1 ? -amt : -multiply(amt, STAmount(amt.asset(), times), amt.asset())); - } - - void - transfer(jtx::Account const& from, jtx::Account const& to, STAmount amt) - { - spend(from, amt); - receive(to, amt); - } - - void - spendFee(jtx::Account const& acct, size_t times = 1) - { - spend(acct, txFee, times); - } - - [[nodiscard]] bool - verify() const - { - for (auto const& [acct, state] : accounts) - { - if (!state.verify(env, acct)) - return false; - } - return true; - } - - struct BridgeCounters - { - using complete_cb = std::function const& signers)>; - - uint32_t claimId{0}; - uint32_t createCount{0}; // for account create. First should be 1 - uint32_t claimCount{0}; // for account create. Increments after quorum for - // current createCount (starts at 1) is reached. - - uint32_t numCreateAttnSent{0}; // for current claimCount - std::vector signers; - std::vector createCallbacks; - }; - - struct Claims - { - ClaimVec xferClaims; - CreateClaimMap createClaims; - }; - - using SignerAttns = std::unordered_map; - using SignersAttns = std::array; - - ENV& env; - std::map accounts; - SignersAttns signersAttns; - std::map counters; - STAmount txFee; - }; - - struct ChainStateTracker - { - ChainStateTracker(ENV& aEnv, ENV& bEnv) : a(aEnv), b(bEnv) - { - } - - [[nodiscard]] bool - verify() const - { - return a.verify() && b.verify(); - } - - void - sendAttestations() - { - a.sendAttestations(); - b.sendAttestations(); - } - - void - init(jtx::Account const& acct) - { - a.init(acct); - b.init(acct); - } - - ChainStateTrack a; - ChainStateTrack b; - }; - - enum class SmState { - Initial, - ClaimIdCreated, - Attesting, - Attested, - Completed, - Closed, - }; - - enum class ActFlags { A2b = 1 << 0 }; - - // -------------------------------------------------- - template - class SmBase - { - SmBase(std::shared_ptr const& chainstate, BridgeDef const& bridge) - : bridge_(bridge), st_(chainstate) - { - } - - public: - ChainStateTrack& - srcState() - { - return static_cast(*this).a2b() ? st_->a : st_->b; - } - - ChainStateTrack& - destState() - { - return static_cast(*this).a2b() ? st_->b : st_->a; - } - - jtx::Account const& - srcDoor() - { - return static_cast(*this).a2b() ? bridge_.doorA : bridge_.doorB; - } - - jtx::Account const& - dstDoor() - { - return static_cast(*this).a2b() ? bridge_.doorB : bridge_.doorA; - } - - protected: - BridgeDef const& bridge_; - std::shared_ptr st_; - - friend T; - }; - - // -------------------------------------------------- - class SmCreateAccount : public SmBase - { - public: - using Base = SmBase; - - SmCreateAccount( - std::shared_ptr const& chainstate, - BridgeDef const& bridge, - AccountCreate create) - : Base(chainstate, bridge), cr_(std::move(create)) - { - } - - [[nodiscard]] bool - a2b() const - { - return cr_.a2b; - } - - uint32_t - issueAccountCreate() - { - ChainStateTrack& st = srcState(); - jtx::Account const& srcdoor = srcDoor(); - - st.env - .tx(sidechainXchainAccountCreate( - cr_.from, bridge_.jvb, cr_.to, cr_.amt, cr_.reward)) - .close(); // needed for claim_id sequence to be correct' - st.spendFee(cr_.from); - st.transfer(cr_.from, srcdoor, cr_.amt); - st.transfer(cr_.from, srcdoor, cr_.reward); - - return ++st.counters[&bridge_].createCount; - } - - void - attest(uint64_t time, uint32_t rnd) - { - ChainStateTrack& st = destState(); - - // check all signers, but start at a random one - size_t i = 0; - for (i = 0; i < kNumSigners; ++i) - { - size_t const signerIdx = (rnd + i) % kNumSigners; - - if (!(cr_.attested[signerIdx])) - { - // enqueue one attestation for this signer - cr_.attested[signerIdx] = true; - - st.signersAttns[signerIdx][&bridge_].createClaims[cr_.claimId - 1].emplace_back( - createAccountAttestation( - bridge_.signers[signerIdx].account, - bridge_.jvb, - cr_.from, - cr_.amt, - cr_.reward, - bridge_.signers[signerIdx].account, - cr_.a2b, - cr_.claimId, - cr_.to, - bridge_.signers[signerIdx])); - break; - } - } - - if (i == kNumSigners) - return; // did not attest - - auto& counters = st.counters[&bridge_]; - if (counters.createCallbacks.size() < cr_.claimId) - counters.createCallbacks.resize(cr_.claimId); - - auto completeCb = [&](std::vector const& signers) { - auto numAttestors = signers.size(); - st.env.close(); - assert(numAttestors <= std::count(cr_.attested.begin(), cr_.attested.end(), true)); - assert(numAttestors >= bridge_.quorum); - assert(cr_.claimId - 1 == counters.claimCount); - - auto r = cr_.reward; - auto reward = divide(r, STAmount(numAttestors), r.asset()); - - for (auto i : signers) - st.receive(bridge_.signers[i].account, reward); - - st.spend(dstDoor(), reward, numAttestors); - st.transfer(dstDoor(), cr_.to, cr_.amt); - st.env.env.memoize(cr_.to); - smState_ = SmState::Completed; - }; - - counters.createCallbacks[cr_.claimId - 1] = std::move(completeCb); - } - - SmState - advance(uint64_t time, uint32_t rnd) - { - switch (smState_) - { - case SmState::Initial: - cr_.claimId = issueAccountCreate(); - smState_ = SmState::Attesting; - break; - - case SmState::Attesting: - attest(time, rnd); - break; - - default: - assert(0); - break; - - case SmState::Completed: - break; // will get this once - } - return smState_; - } - - private: - SmState smState_{SmState::Initial}; - AccountCreate cr_; - }; - - // -------------------------------------------------- - class SmTransfer : public SmBase - { - public: - using Base = SmBase; - - SmTransfer( - std::shared_ptr const& chainstate, - BridgeDef const& bridge, - Transfer xfer) - : Base(chainstate, bridge), xfer_(std::move(xfer)) - { - } - - [[nodiscard]] bool - a2b() const - { - return xfer_.a2b; - } - - uint32_t - createClaimId() - { - ChainStateTrack& st = destState(); - - st.env.tx(xchainCreateClaimId(xfer_.to, bridge_.jvb, bridge_.reward, xfer_.from)) - .close(); // needed for claim_id sequence to be - // correct' - st.spendFee(xfer_.to); - return ++st.counters[&bridge_].claimId; - } - - void - commit() - { - ChainStateTrack& st = srcState(); - jtx::Account const& srcdoor = srcDoor(); - - if (xfer_.amt.asset() != xrpIssue()) - { - st.env.tx(pay(srcdoor, xfer_.from, xfer_.amt)); - st.spendFee(srcdoor); - } - st.env.tx(xchainCommit( - xfer_.from, - bridge_.jvb, - xfer_.claimId, - xfer_.amt, - xfer_.withClaim == WithClaim::Yes ? std::nullopt - : std::optional(xfer_.finaldest))); - st.spendFee(xfer_.from); - st.transfer(xfer_.from, srcdoor, xfer_.amt); - } - - void - distributeReward(ChainStateTrack& st) - { - auto r = bridge_.reward; - auto reward = divide(r, STAmount(bridge_.quorum), r.asset()); - - for (size_t i = 0; i < kNumSigners; ++i) - { - if (xfer_.attested[i]) - st.receive(bridge_.signers[i].account, reward); - } - st.spend(xfer_.to, reward, bridge_.quorum); - } - - bool - attest(uint64_t time, uint32_t rnd) - { - ChainStateTrack& st = destState(); - - // check all signers, but start at a random one - for (size_t i = 0; i < kNumSigners; ++i) - { - size_t const signerIdx = (rnd + i) % kNumSigners; - if (!(xfer_.attested[signerIdx])) - { - // enqueue one attestation for this signer - xfer_.attested[signerIdx] = true; - - st.signersAttns[signerIdx][&bridge_].xferClaims.emplace_back(claimAttestation( - bridge_.signers[signerIdx].account, - bridge_.jvb, - xfer_.from, - xfer_.amt, - bridge_.signers[signerIdx].account, - xfer_.a2b, - xfer_.claimId, - xfer_.withClaim == WithClaim::Yes - ? std::nullopt - : std::optional(xfer_.finaldest), - bridge_.signers[signerIdx])); - break; - } - } - - // return true if quorum was reached, false otherwise - bool const quorum = - std::count(xfer_.attested.begin(), xfer_.attested.end(), true) >= bridge_.quorum; - if (quorum && xfer_.withClaim == WithClaim::No) - { - distributeReward(st); - st.transfer(dstDoor(), xfer_.finaldest, xfer_.amt); - } - return quorum; - } - - void - claim() - { - ChainStateTrack& st = destState(); - st.env.tx( - xchainClaim(xfer_.to, bridge_.jvb, xfer_.claimId, xfer_.amt, xfer_.finaldest)); - distributeReward(st); - st.transfer(dstDoor(), xfer_.finaldest, xfer_.amt); - st.spendFee(xfer_.to); - } - - SmState - advance(uint64_t time, uint32_t rnd) - { - switch (smState_) - { - case SmState::Initial: - xfer_.claimId = createClaimId(); - smState_ = SmState::ClaimIdCreated; - break; - - case SmState::ClaimIdCreated: - commit(); - smState_ = SmState::Attesting; - break; - - case SmState::Attesting: - if (attest(time, rnd)) - { - smState_ = xfer_.withClaim == WithClaim::Yes ? SmState::Attested - : SmState::Completed; - } - else - { - smState_ = SmState::Attesting; - } - break; - - case SmState::Attested: - assert(xfer_.withClaim == WithClaim::Yes); - claim(); - smState_ = SmState::Completed; - break; - - default: - case SmState::Completed: - assert(0); // should have been removed - break; - } - return smState_; - } - - private: - Transfer xfer_; - SmState smState_{SmState::Initial}; - }; - - // -------------------------------------------------- - using Sm = std::variant; - using SmCont = std::list>; - - SmCont sm_; - - void - xfer( - uint64_t time, - std::shared_ptr const& chainstate, - BridgeDef const& bridge, - Transfer transfer) - { - sm_.emplace_back(time, SmTransfer(chainstate, bridge, std::move(transfer))); - } - - void - ac(uint64_t time, - std::shared_ptr const& chainstate, - BridgeDef const& bridge, - AccountCreate ac) - { - sm_.emplace_back(time, SmCreateAccount(chainstate, bridge, std::move(ac))); - } - -public: - void - runSimulation(std::shared_ptr const& st, bool verifyBalances = true) - { - using namespace jtx; - uint64_t time = 0; - // NOLINTNEXTLINE(bugprone-random-generator-seed): fixed seed for reproducible test - std::mt19937 gen(27); // Standard mersenne_twister_engine - std::uniform_int_distribution distrib(0, 9); - - while (!sm_.empty()) - { - ++time; - for (auto it = sm_.begin(); it != sm_.end();) - { - auto vis = [&](auto& sm) { - uint32_t const rnd = distrib(gen); - return sm.advance(time, rnd); - }; - auto& [t, sm] = *it; - if (t <= time && std::visit(vis, sm) == SmState::Completed) - { - it = sm_.erase(it); - } - else - { - ++it; - } - } - - // send attestations - st->sendAttestations(); - - // make sure all transactions have been applied - st->a.env.close(); - st->b.env.close(); - - if (verifyBalances) - { - BEAST_EXPECT(st->verify()); - } - } - } - - void - testXChainSimulation() - { - using namespace jtx; - - testcase("Bridge usage simulation"); - - XEnv mcEnv(*this); - XEnv scEnv(*this, true); - - auto st = std::make_shared(mcEnv, scEnv); - - // create 10 accounts + door funded on both chains, and store - // in ChainStateTracker the initial amount of these accounts - Account doorXRPLocking("doorXRPLocking"), doorUSDLocking("doorUSDLocking"), - doorUSDIssuing("doorUSDIssuing"); - - static constexpr size_t kNumAcct = 10; - auto a = [&doorXRPLocking, &doorUSDLocking, &doorUSDIssuing]() { - using namespace std::literals; - std::vector result; - result.reserve(kNumAcct); - for (int i = 0; i < kNumAcct; ++i) - { - result.emplace_back( - "a"s + std::to_string(i), (i % 2) ? KeyType::Ed25519 : KeyType::Secp256k1); - } - result.emplace_back("doorXRPLocking"); - doorXRPLocking = result.back(); - result.emplace_back("doorUSDLocking"); - doorUSDLocking = result.back(); - result.emplace_back("doorUSDIssuing"); - doorUSDIssuing = result.back(); - return result; - }(); - - for (auto& acct : a) - { - STAmount const amt{XRP(100000)}; - - mcEnv.fund(amt, acct); - scEnv.fund(amt, acct); - } - Account const usdLockingAcc{"USDLocking"}; - IOU const usdLocking{usdLockingAcc["USD"]}; - IOU const usdIssuing{doorUSDIssuing["USD"]}; - - mcEnv.fund(XRP(100000), usdLockingAcc); - mcEnv.close(); - mcEnv.tx(trust(doorUSDLocking, usdLocking(100000))); - mcEnv.close(); - mcEnv.tx(pay(usdLockingAcc, doorUSDLocking, usdLocking(50000))); - - for (int i = 0; i < a.size(); ++i) - { - auto& acct{a[i]}; - if (i < kNumAcct) - { - mcEnv.tx(trust(acct, usdLocking(100000))); - scEnv.tx(trust(acct, usdIssuing(100000))); - } - st->init(acct); - } - for (auto& s : signers) - st->init(s.account); - - st->b.init(Account::kMaster); - - // also create some unfunded accounts - static constexpr size_t kNumUa = 20; - auto ua = []() { - using namespace std::literals; - std::vector result; - result.reserve(kNumUa); - for (int i = 0; i < kNumUa; ++i) - { - result.emplace_back( - "ua"s + std::to_string(i), (i % 2) ? KeyType::Ed25519 : KeyType::Secp256k1); - } - return result; - }(); - - // initialize a bridge from a BridgeDef - auto initBridge = [&mcEnv, &scEnv, &st](BridgeDef& bd) { - bd.initBridge(mcEnv, scEnv); - st->a.spendFee(bd.doorA, 2); - st->b.spendFee(bd.doorB, 2); - }; - - // create XRP -> XRP bridge - // ------------------------ - BridgeDef xrpB{ - .doorA = doorXRPLocking, - .issueA = xrpIssue(), - .doorB = Account::kMaster, - .issueB = xrpIssue(), - .reward = XRP(1), - .minAccountCreate = XRP(20), - .quorum = quorum, - .signers = signers, - .jvb = json::ValueType::Null}; - - initBridge(xrpB); - - // create USD -> USD bridge - // ------------------------ - BridgeDef usdB{ - .doorA = doorUSDLocking, - .issueA = usdLocking, - .doorB = doorUSDIssuing, - .issueB = usdIssuing, - .reward = XRP(1), - .minAccountCreate = XRP(20), - .quorum = quorum, - .signers = signers, - .jvb = json::ValueType::Null}; - - initBridge(usdB); - - // try a single account create + transfer to validate the simulation - // engine. Do the transfer 8 time steps after the account create, to - // give time enough for ua[0] to be funded now so it can reserve - // the claimID - // ----------------------------------------------------------------- - ac(0, - st, - xrpB, - {.from = a[0], .to = ua[0], .amt = XRP(777), .reward = xrpB.reward, .a2b = true}); - xfer( - 8, - st, - xrpB, - {.from = a[0], .to = ua[0], .finaldest = a[2], .amt = XRP(3), .a2b = true}); - runSimulation(st); - - // try the same thing in the other direction - // ----------------------------------------- - ac(0, - st, - xrpB, - {.from = a[0], .to = ua[0], .amt = XRP(777), .reward = xrpB.reward, .a2b = false}); - xfer( - 8, - st, - xrpB, - {.from = a[0], .to = ua[0], .finaldest = a[2], .amt = XRP(3), .a2b = false}); - runSimulation(st); - - // run multiple XRP transfers - // -------------------------- - xfer( - 0, - st, - xrpB, - {.from = a[0], - .to = a[0], - .finaldest = a[1], - .amt = XRP(6), - .a2b = true, - .withClaim = WithClaim::No}); - xfer( - 1, - st, - xrpB, - {.from = a[0], - .to = a[0], - .finaldest = a[1], - .amt = XRP(8), - .a2b = false, - .withClaim = WithClaim::No}); - xfer( - 1, st, xrpB, {.from = a[1], .to = a[1], .finaldest = a[1], .amt = XRP(1), .a2b = true}); - xfer( - 2, - st, - xrpB, - {.from = a[0], .to = a[0], .finaldest = a[1], .amt = XRP(3), .a2b = false}); - xfer( - 2, - st, - xrpB, - {.from = a[1], .to = a[1], .finaldest = a[1], .amt = XRP(5), .a2b = false}); - xfer( - 2, - st, - xrpB, - {.from = a[0], - .to = a[0], - .finaldest = a[1], - .amt = XRP(7), - .a2b = false, - .withClaim = WithClaim::No}); - xfer( - 2, st, xrpB, {.from = a[1], .to = a[1], .finaldest = a[1], .amt = XRP(9), .a2b = true}); - runSimulation(st); - - // run one USD transfer - // -------------------- - xfer( - 0, - st, - usdB, - {.from = a[0], .to = a[1], .finaldest = a[2], .amt = usdLocking(3), .a2b = true}); - runSimulation(st); - - // run multiple USD transfers - // -------------------------- - xfer( - 0, - st, - usdB, - {.from = a[0], .to = a[0], .finaldest = a[1], .amt = usdLocking(6), .a2b = true}); - xfer( - 1, - st, - usdB, - {.from = a[0], .to = a[0], .finaldest = a[1], .amt = usdIssuing(8), .a2b = false}); - xfer( - 1, - st, - usdB, - {.from = a[1], .to = a[1], .finaldest = a[1], .amt = usdLocking(1), .a2b = true}); - xfer( - 2, - st, - usdB, - {.from = a[0], .to = a[0], .finaldest = a[1], .amt = usdIssuing(3), .a2b = false}); - xfer( - 2, - st, - usdB, - {.from = a[1], .to = a[1], .finaldest = a[1], .amt = usdIssuing(5), .a2b = false}); - xfer( - 2, - st, - usdB, - {.from = a[0], .to = a[0], .finaldest = a[1], .amt = usdIssuing(7), .a2b = false}); - xfer( - 2, - st, - usdB, - {.from = a[1], .to = a[1], .finaldest = a[1], .amt = usdLocking(9), .a2b = true}); - runSimulation(st); - - // run mixed transfers - // ------------------- - xfer( - 0, st, xrpB, {.from = a[0], .to = a[0], .finaldest = a[0], .amt = XRP(1), .a2b = true}); - xfer( - 0, - st, - usdB, - {.from = a[1], .to = a[3], .finaldest = a[3], .amt = usdIssuing(3), .a2b = false}); - xfer( - 0, - st, - usdB, - {.from = a[3], .to = a[2], .finaldest = a[1], .amt = usdIssuing(5), .a2b = false}); - - xfer( - 1, - st, - xrpB, - {.from = a[0], .to = a[0], .finaldest = a[0], .amt = XRP(4), .a2b = false}); - xfer( - 1, st, xrpB, {.from = a[1], .to = a[1], .finaldest = a[0], .amt = XRP(8), .a2b = true}); - xfer( - 1, - st, - usdB, - {.from = a[4], .to = a[1], .finaldest = a[1], .amt = usdLocking(7), .a2b = true}); - - xfer( - 3, st, xrpB, {.from = a[1], .to = a[1], .finaldest = a[0], .amt = XRP(7), .a2b = true}); - xfer( - 3, - st, - xrpB, - {.from = a[0], .to = a[4], .finaldest = a[3], .amt = XRP(2), .a2b = false}); - xfer( - 3, st, xrpB, {.from = a[1], .to = a[1], .finaldest = a[0], .amt = XRP(9), .a2b = true}); - xfer( - 3, - st, - usdB, - {.from = a[3], .to = a[1], .finaldest = a[1], .amt = usdIssuing(11), .a2b = false}); - runSimulation(st); - - // run multiple account create to stress attestation batching - // ---------------------------------------------------------- - ac(0, - st, - xrpB, - {.from = a[0], .to = ua[1], .amt = XRP(301), .reward = xrpB.reward, .a2b = true}); - ac(0, - st, - xrpB, - {.from = a[1], .to = ua[2], .amt = XRP(302), .reward = xrpB.reward, .a2b = true}); - ac(1, - st, - xrpB, - {.from = a[0], .to = ua[3], .amt = XRP(303), .reward = xrpB.reward, .a2b = true}); - ac(2, - st, - xrpB, - {.from = a[1], .to = ua[4], .amt = XRP(304), .reward = xrpB.reward, .a2b = true}); - ac(3, - st, - xrpB, - {.from = a[0], .to = ua[5], .amt = XRP(305), .reward = xrpB.reward, .a2b = true}); - ac(4, - st, - xrpB, - {.from = a[1], .to = ua[6], .amt = XRP(306), .reward = xrpB.reward, .a2b = true}); - ac(6, - st, - xrpB, - {.from = a[0], .to = ua[7], .amt = XRP(307), .reward = xrpB.reward, .a2b = true}); - ac(7, - st, - xrpB, - {.from = a[2], .to = ua[8], .amt = XRP(308), .reward = xrpB.reward, .a2b = true}); - ac(9, - st, - xrpB, - {.from = a[0], .to = ua[9], .amt = XRP(309), .reward = xrpB.reward, .a2b = true}); - ac(9, - st, - xrpB, - {.from = a[0], .to = ua[9], .amt = XRP(309), .reward = xrpB.reward, .a2b = true}); - ac(10, - st, - xrpB, - {.from = a[0], .to = ua[10], .amt = XRP(310), .reward = xrpB.reward, .a2b = true}); - ac(12, - st, - xrpB, - {.from = a[0], .to = ua[11], .amt = XRP(311), .reward = xrpB.reward, .a2b = true}); - ac(12, - st, - xrpB, - {.from = a[3], .to = ua[12], .amt = XRP(312), .reward = xrpB.reward, .a2b = true}); - ac(12, - st, - xrpB, - {.from = a[4], .to = ua[13], .amt = XRP(313), .reward = xrpB.reward, .a2b = true}); - ac(12, - st, - xrpB, - {.from = a[3], .to = ua[14], .amt = XRP(314), .reward = xrpB.reward, .a2b = true}); - ac(12, - st, - xrpB, - {.from = a[6], .to = ua[15], .amt = XRP(315), .reward = xrpB.reward, .a2b = true}); - ac(13, - st, - xrpB, - {.from = a[7], .to = ua[16], .amt = XRP(316), .reward = xrpB.reward, .a2b = true}); - ac(15, - st, - xrpB, - {.from = a[3], .to = ua[17], .amt = XRP(317), .reward = xrpB.reward, .a2b = true}); - runSimulation(st, true); // balances verification working now. - } - - void - run() override - { - testXChainSimulation(); - } -}; - -BEAST_DEFINE_TESTSUITE(XChain, app, xrpl); -BEAST_DEFINE_TESTSUITE(XChainSim, app, xrpl); - -} // namespace xrpl::test diff --git a/src/test/jtx/attester.h b/src/test/jtx/attester.h deleted file mode 100644 index e288629cbd..0000000000 --- a/src/test/jtx/attester.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -namespace xrpl { - -class PublicKey; -class SecretKey; -class STXChainBridge; -class STAmount; - -namespace test::jtx { - -Buffer -signClaimAttestation( - PublicKey const& pk, - SecretKey const& sk, - STXChainBridge const& bridge, - AccountID const& sendingAccount, - STAmount const& sendingAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t claimID, - std::optional const& dst); - -Buffer -signCreateAccountAttestation( - PublicKey const& pk, - SecretKey const& sk, - STXChainBridge const& bridge, - AccountID const& sendingAccount, - STAmount const& sendingAmount, - STAmount const& rewardAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t createCount, - AccountID const& dst); -} // namespace test::jtx - -} // namespace xrpl diff --git a/src/test/jtx/impl/attester.cpp b/src/test/jtx/impl/attester.cpp deleted file mode 100644 index ac946a1bf3..0000000000 --- a/src/test/jtx/impl/attester.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace xrpl::test::jtx { - -Buffer -signClaimAttestation( - PublicKey const& pk, - SecretKey const& sk, - STXChainBridge const& bridge, - AccountID const& sendingAccount, - STAmount const& sendingAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t claimID, - std::optional const& dst) -{ - auto const toSign = Attestations::AttestationClaim::message( - bridge, sendingAccount, sendingAmount, rewardAccount, wasLockingChainSend, claimID, dst); - return sign(pk, sk, makeSlice(toSign)); -} - -Buffer -signCreateAccountAttestation( - PublicKey const& pk, - SecretKey const& sk, - STXChainBridge const& bridge, - AccountID const& sendingAccount, - STAmount const& sendingAmount, - STAmount const& rewardAmount, - AccountID const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t createCount, - AccountID const& dst) -{ - auto const toSign = Attestations::AttestationCreateAccount::message( - bridge, - sendingAccount, - sendingAmount, - rewardAmount, - rewardAccount, - wasLockingChainSend, - createCount, - dst); - return sign(pk, sk, makeSlice(toSign)); -} - -} // namespace xrpl::test::jtx diff --git a/src/test/jtx/impl/xchain_bridge.cpp b/src/test/jtx/impl/xchain_bridge.cpp deleted file mode 100644 index 24669e6d4f..0000000000 --- a/src/test/jtx/impl/xchain_bridge.cpp +++ /dev/null @@ -1,487 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace xrpl::test::jtx { - -// use this for creating a bridge for a transaction -json::Value -bridge( - Account const& lockingChainDoor, - Issue const& lockingChainIssue, - Account const& issuingChainDoor, - Issue const& issuingChainIssue) -{ - json::Value jv; - jv[jss::LockingChainDoor] = lockingChainDoor.human(); - jv[jss::LockingChainIssue] = toJson(lockingChainIssue); - jv[jss::IssuingChainDoor] = issuingChainDoor.human(); - jv[jss::IssuingChainIssue] = toJson(issuingChainIssue); - return jv; -} - -// use this for creating a bridge for a rpc query -json::Value -bridgeRpc( - Account const& lockingChainDoor, - Issue const& lockingChainIssue, - Account const& issuingChainDoor, - Issue const& issuingChainIssue) -{ - json::Value jv; - jv[jss::LockingChainDoor] = lockingChainDoor.human(); - jv[jss::LockingChainIssue] = toJson(lockingChainIssue); - jv[jss::IssuingChainDoor] = issuingChainDoor.human(); - jv[jss::IssuingChainIssue] = toJson(issuingChainIssue); - return jv; -} - -json::Value -bridgeCreate( - Account const& acc, - json::Value const& bridge, - STAmount const& reward, - std::optional const& minAccountCreate) -{ - json::Value jv; - - jv[jss::Account] = acc.human(); - jv[sfXChainBridge.getJsonName()] = bridge; - jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::Values::None); - if (minAccountCreate) - { - jv[sfMinAccountCreateAmount.getJsonName()] = - minAccountCreate->getJson(JsonOptions::Values::None); - } - - jv[jss::TransactionType] = jss::XChainCreateBridge; - return jv; -} - -json::Value -bridgeModify( - Account const& acc, - json::Value const& bridge, - std::optional const& reward, - std::optional const& minAccountCreate) -{ - json::Value jv; - - jv[jss::Account] = acc.human(); - jv[sfXChainBridge.getJsonName()] = bridge; - if (reward) - jv[sfSignatureReward.getJsonName()] = reward->getJson(JsonOptions::Values::None); - if (minAccountCreate) - { - jv[sfMinAccountCreateAmount.getJsonName()] = - minAccountCreate->getJson(JsonOptions::Values::None); - } - - jv[jss::TransactionType] = jss::XChainModifyBridge; - return jv; -} - -json::Value -xchainCreateClaimId( - Account const& acc, - json::Value const& bridge, - STAmount const& reward, - Account const& otherChainSource) -{ - json::Value jv; - - jv[jss::Account] = acc.human(); - jv[sfXChainBridge.getJsonName()] = bridge; - jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::Values::None); - jv[sfOtherChainSource.getJsonName()] = otherChainSource.human(); - - jv[jss::TransactionType] = jss::XChainCreateClaimID; - return jv; -} - -json::Value -xchainCommit( - Account const& acc, - json::Value const& bridge, - std::uint32_t claimID, - AnyAmount const& amt, - std::optional const& dst) -{ - json::Value jv; - - jv[jss::Account] = acc.human(); - jv[sfXChainBridge.getJsonName()] = bridge; - jv[sfXChainClaimID.getJsonName()] = claimID; - jv[jss::Amount] = amt.value.getJson(JsonOptions::Values::None); - if (dst) - jv[sfOtherChainDestination.getJsonName()] = dst->human(); - - jv[jss::TransactionType] = jss::XChainCommit; - return jv; -} - -json::Value -xchainClaim( - Account const& acc, - json::Value const& bridge, - std::uint32_t claimID, - AnyAmount const& amt, - Account const& dst) -{ - json::Value jv; - - jv[sfAccount.getJsonName()] = acc.human(); - jv[sfXChainBridge.getJsonName()] = bridge; - jv[sfXChainClaimID.getJsonName()] = claimID; - jv[sfDestination.getJsonName()] = dst.human(); - jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::Values::None); - - jv[jss::TransactionType] = jss::XChainClaim; - return jv; -} - -json::Value -sidechainXchainAccountCreate( - Account const& acc, - json::Value const& bridge, - Account const& dst, - AnyAmount const& amt, - AnyAmount const& reward) -{ - json::Value jv; - - jv[sfAccount.getJsonName()] = acc.human(); - jv[sfXChainBridge.getJsonName()] = bridge; - jv[sfDestination.getJsonName()] = dst.human(); - jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::Values::None); - jv[sfSignatureReward.getJsonName()] = reward.value.getJson(JsonOptions::Values::None); - - jv[jss::TransactionType] = jss::XChainAccountCreateCommit; - return jv; -} - -json::Value -claimAttestation( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - jtx::Account const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t claimID, - std::optional const& dst, - jtx::Signer const& signer) -{ - STXChainBridge const stBridge(jvBridge); - - auto const& pk = signer.account.pk(); - auto const& sk = signer.account.sk(); - auto const sig = signClaimAttestation( - pk, - sk, - stBridge, - sendingAccount, - sendingAmount.value, - rewardAccount, - wasLockingChainSend, - claimID, - dst); - - json::Value result; - - result[sfAccount.getJsonName()] = submittingAccount.human(); - result[sfXChainBridge.getJsonName()] = jvBridge; - - result[sfAttestationSignerAccount.getJsonName()] = signer.account.human(); - result[sfPublicKey.getJsonName()] = strHex(pk.slice()); - result[sfSignature.getJsonName()] = strHex(sig); - result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount); - result[sfAmount.getJsonName()] = sendingAmount.value.getJson(JsonOptions::Values::None); - result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount); - result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0; - - result[sfXChainClaimID.getJsonName()] = STUInt64{claimID}.getJson(JsonOptions::Values::None); - if (dst) - result[sfDestination.getJsonName()] = toBase58(*dst); - - result[jss::TransactionType] = jss::XChainAddClaimAttestation; - - return result; -} - -json::Value -createAccountAttestation( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - jtx::AnyAmount const& rewardAmount, - jtx::Account const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t createCount, - jtx::Account const& dst, - jtx::Signer const& signer) -{ - STXChainBridge const stBridge(jvBridge); - - auto const& pk = signer.account.pk(); - auto const& sk = signer.account.sk(); - auto const sig = jtx::signCreateAccountAttestation( - pk, - sk, - stBridge, - sendingAccount, - sendingAmount.value, - rewardAmount.value, - rewardAccount, - wasLockingChainSend, - createCount, - dst); - - json::Value result; - - result[sfAccount.getJsonName()] = submittingAccount.human(); - result[sfXChainBridge.getJsonName()] = jvBridge; - - result[sfAttestationSignerAccount.getJsonName()] = signer.account.human(); - result[sfPublicKey.getJsonName()] = strHex(pk.slice()); - result[sfSignature.getJsonName()] = strHex(sig); - result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount); - result[sfAmount.getJsonName()] = sendingAmount.value.getJson(JsonOptions::Values::None); - result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount); - result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0; - - result[sfXChainAccountCreateCount.getJsonName()] = - STUInt64{createCount}.getJson(JsonOptions::Values::None); - result[sfDestination.getJsonName()] = toBase58(dst); - result[sfSignatureReward.getJsonName()] = rewardAmount.value.getJson(JsonOptions::Values::None); - - result[jss::TransactionType] = jss::XChainAddAccountCreateAttestation; - - return result; -} - -JValueVec -claimAttestations( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - std::vector const& rewardAccounts, - bool wasLockingChainSend, - std::uint64_t claimID, - std::optional const& dst, - std::vector const& signers, - std::size_t const numAtts, - std::size_t const fromIdx) -{ - assert(fromIdx + numAtts <= rewardAccounts.size()); - assert(fromIdx + numAtts <= signers.size()); - JValueVec vec; - vec.reserve(numAtts); - for (auto i = fromIdx; i < fromIdx + numAtts; ++i) - { - vec.emplace_back(claimAttestation( - submittingAccount, - jvBridge, - sendingAccount, - sendingAmount, - rewardAccounts[i], - wasLockingChainSend, - claimID, - dst, - signers[i])); - } - return vec; -} - -JValueVec -createAccountAttestations( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - jtx::AnyAmount const& rewardAmount, - std::vector const& rewardAccounts, - bool wasLockingChainSend, - std::uint64_t createCount, - jtx::Account const& dst, - std::vector const& signers, - std::size_t const numAtts, - std::size_t const fromIdx) -{ - assert(fromIdx + numAtts <= rewardAccounts.size()); - assert(fromIdx + numAtts <= signers.size()); - JValueVec vec; - vec.reserve(numAtts); - for (auto i = fromIdx; i < fromIdx + numAtts; ++i) - { - vec.emplace_back(createAccountAttestation( - submittingAccount, - jvBridge, - sendingAccount, - sendingAmount, - rewardAmount, - rewardAccounts[i], - wasLockingChainSend, - createCount, - dst, - signers[i])); - } - return vec; -} - -XChainBridgeObjects::XChainBridgeObjects() - : mcDoor("mcDoor") - , mcAlice("mcAlice") - , mcBob("mcBob") - , mcCarol("mcCarol") - , mcGw("mcGw") - , scDoor("scDoor") - , scAlice("scAlice") - , scBob("scBob") - , scCarol("scCarol") - , scGw("scGw") - , scAttester("scAttester") - , scReward("scReward") - , mcuDoor("mcuDoor") - , mcuAlice("mcuAlice") - , mcuBob("mcuBob") - , mcuCarol("mcuCarol") - , mcuGw("mcuGw") - , scuDoor("scuDoor") - , scuAlice("scuAlice") - , scuBob("scuBob") - , scuCarol("scuCarol") - , scuGw("scuGw") - , mcUSD(mcGw["USD"]) - , scUSD(scGw["USD"]) - , jvXRPBridgeRPC(bridgeRpc(mcDoor, xrpIssue(), Account::kMaster, xrpIssue())) - , jvb(bridge(mcDoor, xrpIssue(), Account::kMaster, xrpIssue())) - , jvub(bridge(mcuDoor, xrpIssue(), Account::kMaster, xrpIssue())) - , features(testableAmendments() | FeatureBitset{featureXChainBridge}) - , signers([] { - static constexpr int kNumSigners = kUtXchainDefaultNumSigners; - std::vector result; - result.reserve(kNumSigners); - for (int i = 0; i < kNumSigners; ++i) - { - using namespace std::literals; - auto const a = Account( - "signer_"s + std::to_string(i), (i % 2) ? KeyType::Ed25519 : KeyType::Secp256k1); - result.emplace_back(a); - } - return result; - }()) - , altSigners([] { - static constexpr int kNumSigners = kUtXchainDefaultNumSigners; - std::vector result; - result.reserve(kNumSigners); - for (int i = 0; i < kNumSigners; ++i) - { - using namespace std::literals; - auto const a = Account( - "alt_signer_"s + std::to_string(i), - (i % 2) ? KeyType::Ed25519 : KeyType::Secp256k1); - result.emplace_back(a); - } - return result; - }()) - , payee([&] { - std::vector r; - r.reserve(signers.size()); - for (int i = 0, e = signers.size(); i != e; ++i) - { - r.push_back(scReward); - } - return r; - }()) - , payees([&] { - std::vector r; - r.reserve(signers.size()); - for (int i = 0, e = signers.size(); i != e; ++i) - { - using namespace std::literals; - auto const a = Account("reward_"s + std::to_string(i)); - r.push_back(a); - } - return r; - }()) - , reward(XRP(1)) - , splitRewardQuorum(divide(reward, STAmount(kUtXchainDefaultQuorum), reward.get())) - , splitRewardEveryone(divide(reward, STAmount(kUtXchainDefaultNumSigners), reward.get())) - , tinyReward(drops(37)) - , tinyRewardSplit( - (divide(tinyReward, STAmount(kUtXchainDefaultQuorum), tinyReward.get()))) - , tinyRewardRemainder( - tinyReward - - multiply(tinyRewardSplit, STAmount(kUtXchainDefaultQuorum), tinyReward.get())) - , oneXrp(XRP(1)) - , xrpDust(divide(oneXrp, STAmount(10000), oneXrp.get())) -{ -} - -void -XChainBridgeObjects::createMcBridgeObjects(Env& mcEnv) -{ - STAmount const xrpFunds{XRP(10000)}; - mcEnv.fund(xrpFunds, mcDoor, mcAlice, mcBob, mcCarol, mcGw); - - // Signer's list must match the attestation signers - mcEnv(jtx::signers(mcDoor, signers.size(), signers)); - - // create XRP bridges in both direction - auto const reward = XRP(1); - STAmount const minCreate = XRP(20); - - mcEnv(bridgeCreate(mcDoor, jvb, reward, minCreate)); - mcEnv.close(); -} - -void -XChainBridgeObjects::createScBridgeObjects(Env& scEnv) -{ - STAmount const xrpFunds{XRP(10000)}; - scEnv.fund(xrpFunds, scDoor, scAlice, scBob, scCarol, scGw, scAttester, scReward); - - // Signer's list must match the attestation signers - scEnv(jtx::signers(Account::kMaster, signers.size(), signers)); - - // create XRP bridges in both direction - auto const reward = XRP(1); - STAmount const minCreate = XRP(20); - - scEnv(bridgeCreate(Account::kMaster, jvb, reward, minCreate)); - scEnv.close(); -} - -void -XChainBridgeObjects::createBridgeObjects(Env& mcEnv, Env& scEnv) -{ - createMcBridgeObjects(mcEnv); - createScBridgeObjects(scEnv); -} -} // namespace xrpl::test::jtx diff --git a/src/test/jtx/xchain_bridge.h b/src/test/jtx/xchain_bridge.h deleted file mode 100644 index aacef80bbe..0000000000 --- a/src/test/jtx/xchain_bridge.h +++ /dev/null @@ -1,239 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace xrpl::test::jtx { - -using JValueVec = std::vector; - -constexpr std::size_t kUtXchainDefaultNumSigners = 5; -constexpr std::size_t kUtXchainDefaultQuorum = 4; - -json::Value -bridge( - Account const& lockingChainDoor, - Issue const& lockingChainIssue, - Account const& issuingChainDoor, - Issue const& issuingChainIssue); - -json::Value -bridgeCreate( - Account const& acc, - json::Value const& bridge, - STAmount const& reward, - std::optional const& minAccountCreate = std::nullopt); - -json::Value -bridgeModify( - Account const& acc, - json::Value const& bridge, - std::optional const& reward, - std::optional const& minAccountCreate = std::nullopt); - -json::Value -xchainCreateClaimId( - Account const& acc, - json::Value const& bridge, - STAmount const& reward, - Account const& otherChainSource); - -json::Value -xchainCommit( - Account const& acc, - json::Value const& bridge, - std::uint32_t claimID, - AnyAmount const& amt, - std::optional const& dst = std::nullopt); - -json::Value -xchainClaim( - Account const& acc, - json::Value const& bridge, - std::uint32_t claimID, - AnyAmount const& amt, - Account const& dst); - -json::Value -sidechainXchainAccountCreate( - Account const& acc, - json::Value const& bridge, - Account const& dst, - AnyAmount const& amt, - AnyAmount const& xChainFee); - -json::Value -sidechainXchainAccountClaim( - Account const& acc, - json::Value const& bridge, - Account const& dst, - AnyAmount const& amt); - -json::Value -claimAttestation( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - jtx::Account const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t claimID, - std::optional const& dst, - jtx::Signer const& signer); - -json::Value -createAccountAttestation( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - jtx::AnyAmount const& rewardAmount, - jtx::Account const& rewardAccount, - bool wasLockingChainSend, - std::uint64_t createCount, - jtx::Account const& dst, - jtx::Signer const& signer); - -JValueVec -claimAttestations( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - std::vector const& rewardAccounts, - bool wasLockingChainSend, - std::uint64_t claimID, - std::optional const& dst, - std::vector const& signers, - std::size_t const numAtts = kUtXchainDefaultQuorum, - std::size_t const fromIdx = 0); - -JValueVec -createAccountAttestations( - jtx::Account const& submittingAccount, - json::Value const& jvBridge, - jtx::Account const& sendingAccount, - jtx::AnyAmount const& sendingAmount, - jtx::AnyAmount const& rewardAmount, - std::vector const& rewardAccounts, - bool wasLockingChainSend, - std::uint64_t createCount, - jtx::Account const& dst, - std::vector const& signers, - std::size_t const numAtts = kUtXchainDefaultQuorum, - std::size_t const fromIdx = 0); - -struct XChainBridgeObjects -{ - // funded accounts - Account const mcDoor; - Account const mcAlice; - Account const mcBob; - Account const mcCarol; - Account const mcGw; - Account const scDoor; - Account const scAlice; - Account const scBob; - Account const scCarol; - Account const scGw; - Account const scAttester; - Account const scReward; - - // unfunded accounts - Account const mcuDoor; - Account const mcuAlice; - Account const mcuBob; - Account const mcuCarol; - Account const mcuGw; - Account const scuDoor; - Account const scuAlice; - Account const scuBob; - Account const scuCarol; - Account const scuGw; - - IOU const mcUSD; - IOU const scUSD; - - json::Value const jvXRPBridgeRPC; - json::Value jvb; // standard xrp bridge def for tx - json::Value jvub; // standard xrp bridge def for tx, unfunded accounts - - FeatureBitset const features; - std::vector const signers; - std::vector const altSigners; - std::vector const payee; - std::vector const payees; - std::uint32_t const quorum{kUtXchainDefaultQuorum}; - - STAmount const reward; // 1 xrp - STAmount const splitRewardQuorum; // 250,000 drops - STAmount const splitRewardEveryone; // 200,000 drops - - STAmount const tinyReward; // 37 drops - STAmount const tinyRewardSplit; // 9 drops - STAmount const tinyRewardRemainder; // 1 drops - - STAmount const oneXrp; - STAmount const xrpDust; - - static constexpr int kDropPerXrp = 1000000; - - XChainBridgeObjects(); - - void - createMcBridgeObjects(Env& mcEnv); - - void - createScBridgeObjects(Env& scEnv); - - void - createBridgeObjects(Env& mcEnv, Env& scEnv); - - JValueVec - attCreateAcctVec( - std::uint64_t createCount, - jtx::AnyAmount const& amt, - jtx::Account const& dst, - std::size_t const numAtts, - std::size_t const fromIdx = 0) - { - return createAccountAttestations( - scAttester, - jvb, - mcCarol, - amt, - reward, - payees, - true, - createCount, - dst, - signers, - numAtts, - fromIdx); - } - - [[nodiscard]] json::Value - createBridge( - Account const& acc, - json::Value const& bridge = json::ValueType::Null, - STAmount const& reward = XRP(1), - std::optional const& minAccountCreate = std::nullopt) const - { - return bridgeCreate( - acc, bridge == json::ValueType::Null ? jvb : bridge, reward, minAccountCreate); - } -}; - -} // namespace xrpl::test::jtx diff --git a/src/test/protocol/STParsedJSON_test.cpp b/src/test/protocol/STParsedJSON_test.cpp index 24981053f5..5c15d1a7ab 100644 --- a/src/test/protocol/STParsedJSON_test.cpp +++ b/src/test/protocol/STParsedJSON_test.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -1630,195 +1629,6 @@ class STParsedJSON_test : public beast::unit_test::Suite } } - void - testXChainBridge() - { - testcase("XChainBridge"); - // Valid XChainBridge - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value issuingChainIssue(json::ValueType::Object); - issuingChainIssue["currency"] = "USD"; - issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "EUR"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["IssuingChainIssue"] = issuingChainIssue; - bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - j[sfXChainBridge] = bridge; - STParsedJSONObject obj("Test", j); - if (BEAST_EXPECT(obj.object); obj.object.has_value()) - { - BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge)); - auto const& bridgeField = (*obj.object)[sfXChainBridge]; - BEAST_EXPECT(bridgeField->lockingChainIssue().currency.size() == 20); - BEAST_EXPECT(bridgeField->issuingChainIssue().currency.size() == 20); - } - } - - // Valid XChainBridge: issues as hex currency - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value issuingChainIssue(json::ValueType::Object); - issuingChainIssue["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123"; - issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "0123456789ABCDEF01230123456789ABCDEF0123"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["IssuingChainIssue"] = issuingChainIssue; - bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - j[sfXChainBridge] = bridge; - STParsedJSONObject obj("Test", j); - if (BEAST_EXPECT(obj.object); obj.object.has_value()) - { - BEAST_EXPECT(obj.object->isFieldPresent(sfXChainBridge)); - auto const& bridgeField = (*obj.object)[sfXChainBridge]; - BEAST_EXPECT(bridgeField->lockingChainIssue().currency.size() == 20); - BEAST_EXPECT(bridgeField->issuingChainIssue().currency.size() == 20); - } - } - - // Invalid XChainBridge: missing LockingChainIssue - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value issuingChainIssue(json::ValueType::Object); - issuingChainIssue["currency"] = "USD"; - issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["IssuingChainIssue"] = issuingChainIssue; - bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: missing IssuingChainIssue - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "EUR"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: missing LockingChainDoor - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value issuingChainIssue(json::ValueType::Object); - issuingChainIssue["currency"] = "USD"; - issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["IssuingChainIssue"] = issuingChainIssue; - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "EUR"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["IssuingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: missing IssuingChainDoor - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value issuingChainIssue(json::ValueType::Object); - issuingChainIssue["currency"] = "USD"; - issuingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["IssuingChainIssue"] = issuingChainIssue; - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "EUR"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["LockingChainDoor"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: IssuingChainIssue not an object - { - json::Value j; - json::Value bridge(json::ValueType::Object); - bridge["LockingChainIssue"] = "notanobject"; - bridge["IssuingChainIssue"] = "notanobject"; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: IssuingChainIssue missing currency - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value asset(json::ValueType::Object); - asset["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "EUR"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["IssuingChainIssue"] = asset; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: asset missing issuer - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value asset(json::ValueType::Object); - asset["currency"] = "USD"; - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "EUR"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["IssuingChainIssue"] = asset; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: asset issuer not base58 - { - json::Value j; - json::Value bridge(json::ValueType::Object); - json::Value asset(json::ValueType::Object); - asset["currency"] = "USD"; - asset["issuer"] = "notAValidBase58Account"; - json::Value lockingChainIssue(json::ValueType::Object); - lockingChainIssue["currency"] = "EUR"; - lockingChainIssue["issuer"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - bridge["LockingChainIssue"] = lockingChainIssue; - bridge["IssuingChainIssue"] = asset; - j[sfXChainBridge] = bridge; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - - // Invalid XChainBridge: not an object - { - json::Value j; - j[sfXChainBridge] = "notanobject"; - STParsedJSONObject const obj("Test", j); - BEAST_EXPECT(!obj.object.has_value()); - } - } - void testNumber() { @@ -2416,7 +2226,6 @@ class STParsedJSON_test : public beast::unit_test::Suite testAmount(); testPathSet(); testIssue(); - testXChainBridge(); testNumber(); testObject(); testArray(); diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 6ba6e7de9f..9280c71052 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -566,8 +565,7 @@ public: Account const gw{"gateway"}; auto const usd = gw["USD"]; - auto const features = - testableAmendments() | featureXChainBridge | featurePermissionedDomains; + auto const features = testableAmendments() | featurePermissionedDomains; Env env(*this, features); // Make a lambda we can use to get "account_objects" easily. @@ -740,120 +738,6 @@ public: } } - { - // Create a bridge - test::jtx::XChainBridgeObjects x; - Env scEnv(*this, envconfig(), features); - x.createScBridgeObjects(scEnv); - - auto scEnvAcctObjs = [&](Account const& acct, char const* type) { - json::Value params; - params[jss::account] = acct.human(); - params[jss::type] = type; - params[jss::ledger_index] = "validated"; - return scEnv.rpc("json", "account_objects", to_string(params)); - }; - - json::Value const resp = scEnvAcctObjs(Account::kMaster, jss::bridge); - - BEAST_EXPECT(acctObjsIsSize(resp, 1)); - auto const& acctBridge = resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT(acctBridge[sfAccount.jsonName] == Account::kMaster.human()); - BEAST_EXPECT(acctBridge[sfLedgerEntryType.getJsonName()] == "Bridge"); - BEAST_EXPECT(acctBridge[sfXChainClaimID.getJsonName()].asUInt() == 0); - BEAST_EXPECT(acctBridge[sfXChainAccountClaimCount.getJsonName()].asUInt() == 0); - BEAST_EXPECT(acctBridge[sfXChainAccountCreateCount.getJsonName()].asUInt() == 0); - BEAST_EXPECT(acctBridge[sfMinAccountCreateAmount.getJsonName()].asUInt() == 20000000); - BEAST_EXPECT(acctBridge[sfSignatureReward.getJsonName()].asUInt() == 1000000); - BEAST_EXPECT(acctBridge[sfXChainBridge.getJsonName()] == x.jvb); - } - { - // Alice and Bob create a xchain sequence number that we can look - // for in the ledger. - test::jtx::XChainBridgeObjects x; - Env scEnv(*this, envconfig(), features); - x.createScBridgeObjects(scEnv); - - scEnv(xchainCreateClaimId(x.scAlice, x.jvb, x.reward, x.mcAlice)); - scEnv.close(); - scEnv(xchainCreateClaimId(x.scBob, x.jvb, x.reward, x.mcBob)); - scEnv.close(); - - auto scEnvAcctObjs = [&](Account const& acct, char const* type) { - json::Value params; - params[jss::account] = acct.human(); - params[jss::type] = type; - params[jss::ledger_index] = "validated"; - return scEnv.rpc("json", "account_objects", to_string(params)); - }; - - { - // Find the xchain sequence number for Andrea. - json::Value const resp = scEnvAcctObjs(x.scAlice, jss::xchain_owned_claim_id); - BEAST_EXPECT(acctObjsIsSize(resp, 1)); - - auto const& xchainSeq = resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT(xchainSeq[sfAccount.jsonName] == x.scAlice.human()); - BEAST_EXPECT(xchainSeq[sfXChainClaimID.getJsonName()].asUInt() == 1); - } - { - // and the one for Bob - json::Value const resp = scEnvAcctObjs(x.scBob, jss::xchain_owned_claim_id); - BEAST_EXPECT(acctObjsIsSize(resp, 1)); - - auto const& xchainSeq = resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT(xchainSeq[sfAccount.jsonName] == x.scBob.human()); - BEAST_EXPECT(xchainSeq[sfXChainClaimID.getJsonName()].asUInt() == 2); - } - } - { - test::jtx::XChainBridgeObjects x; - Env scEnv(*this, envconfig(), features); - x.createScBridgeObjects(scEnv); - auto const amt = XRP(1000); - - // send first batch of account create attestations, so the - // xchain_create_account_claim_id_ should be present on the door - // account (Account::kMaster) to collect the signatures until a - // quorum is reached - scEnv( - test::jtx::createAccountAttestation( - x.scAttester, - x.jvb, - x.mcCarol, - amt, - x.reward, - x.payees[0], - true, - 1, - x.scuAlice, - x.signers[0])); - scEnv.close(); - - auto scEnvAcctObjs = [&](Account const& acct, char const* type) { - json::Value params; - params[jss::account] = acct.human(); - params[jss::type] = type; - params[jss::ledger_index] = "validated"; - return scEnv.rpc("json", "account_objects", to_string(params)); - }; - - { - // Find the xchain_create_account_claim_id_ - json::Value const resp = - scEnvAcctObjs(Account::kMaster, jss::xchain_owned_create_account_claim_id); - BEAST_EXPECT(acctObjsIsSize(resp, 1)); - - auto const& xchainCreateAccountClaimId = - resp[jss::result][jss::account_objects][0u]; - BEAST_EXPECT( - xchainCreateAccountClaimId[sfAccount.jsonName] == Account::kMaster.human()); - BEAST_EXPECT( - xchainCreateAccountClaimId[sfXChainAccountCreateCount.getJsonName()].asUInt() == - 1); - } - } - // gw creates an offer that we can look for in the ledger. env(offer(gw, usd(7), XRP(14))); env.close(); diff --git a/src/test/rpc/LedgerEntry_test.cpp b/src/test/rpc/LedgerEntry_test.cpp index d321ab39aa..3fc42364e0 100644 --- a/src/test/rpc/LedgerEntry_test.cpp +++ b/src/test/rpc/LedgerEntry_test.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -19,7 +18,6 @@ #include #include #include -#include #include #include @@ -45,7 +43,6 @@ #include #include #include -#include #include #include @@ -2745,294 +2742,6 @@ public: } }; -class LedgerEntry_XChain_test : public beast::unit_test::Suite, - public test::jtx::XChainBridgeObjects -{ - void - checkErrorValue(json::Value const& jv, std::string const& err, std::string const& msg) - { - if (BEAST_EXPECT(jv.isMember(jss::status))) - BEAST_EXPECT(jv[jss::status] == "error"); - if (BEAST_EXPECT(jv.isMember(jss::error))) - BEAST_EXPECT(jv[jss::error] == err); - if (msg.empty()) - { - BEAST_EXPECT( - jv[jss::error_message] == json::ValueType::Null || jv[jss::error_message] == ""); - } - else if (BEAST_EXPECT(jv.isMember(jss::error_message))) - { - BEAST_EXPECT(jv[jss::error_message] == msg); - } - } - - void - testBridge() - { - testcase("ledger_entry: bridge"); - using namespace test::jtx; - - Env mcEnv{*this, features}; - Env scEnv(*this, envconfig(), features); - - createBridgeObjects(mcEnv, scEnv); - - std::string const ledgerHash{to_string(mcEnv.closed()->header().hash)}; - std::string bridgeIndex; - json::Value mcBridge; - { - // request the bridge via RPC - json::Value jvParams; - jvParams[jss::bridge_account] = mcDoor.human(); - jvParams[jss::bridge] = jvb; - json::Value const jrr = - mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(jrr.isMember(jss::node)); - auto r = jrr[jss::node]; - - BEAST_EXPECT(r.isMember(jss::Account)); - BEAST_EXPECT(r[jss::Account] == mcDoor.human()); - - BEAST_EXPECT(r.isMember(jss::Flags)); - - BEAST_EXPECT(r.isMember(sfLedgerEntryType.jsonName)); - BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::Bridge); - - // we not created an account yet - BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName)); - BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 0); - - // we have not claimed a locking chain tx yet - BEAST_EXPECT(r.isMember(sfXChainAccountClaimCount.jsonName)); - BEAST_EXPECT(r[sfXChainAccountClaimCount.jsonName].asInt() == 0); - - BEAST_EXPECT(r.isMember(jss::index)); - bridgeIndex = r[jss::index].asString(); - mcBridge = r; - } - { - // request the bridge via RPC by index - json::Value jvParams; - jvParams[jss::index] = bridgeIndex; - json::Value const jrr = - mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(jrr.isMember(jss::node)); - BEAST_EXPECT(jrr[jss::node] == mcBridge); - } - { - // swap door accounts and make sure we get an error value - json::Value jvParams; - // Sidechain door account is "master", not scDoor - jvParams[jss::bridge_account] = Account::kMaster.human(); - jvParams[jss::bridge] = jvb; - jvParams[jss::ledger_hash] = ledgerHash; - json::Value const jrr = - mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - - checkErrorValue(jrr, "entryNotFound", "Entry not found."); - } - { - // create two claim ids and verify that the bridge counter was - // incremented - mcEnv(xchainCreateClaimId(mcAlice, jvb, reward, scAlice)); - mcEnv.close(); - mcEnv(xchainCreateClaimId(mcBob, jvb, reward, scBob)); - mcEnv.close(); - - // request the bridge via RPC - json::Value jvParams; - jvParams[jss::bridge_account] = mcDoor.human(); - jvParams[jss::bridge] = jvb; - json::Value const jrr = - mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(jrr.isMember(jss::node)); - auto r = jrr[jss::node]; - - // we executed two create claim id txs - BEAST_EXPECT(r.isMember(sfXChainClaimID.jsonName)); - BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2); - } - } - - void - testClaimID() - { - testcase("ledger_entry: xchain_claim_id"); - using namespace test::jtx; - - Env mcEnv{*this, features}; - Env scEnv(*this, envconfig(), features); - - createBridgeObjects(mcEnv, scEnv); - - scEnv(xchainCreateClaimId(scAlice, jvb, reward, mcAlice)); - scEnv.close(); - scEnv(xchainCreateClaimId(scBob, jvb, reward, mcBob)); - scEnv.close(); - - { - // request the xchain_claim_id via RPC - json::Value jvParams; - jvParams[jss::xchain_owned_claim_id] = jvXRPBridgeRPC; - jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = 1; - json::Value const jrr = - scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(jrr.isMember(jss::node)); - auto r = jrr[jss::node]; - - BEAST_EXPECT(r.isMember(jss::Account)); - BEAST_EXPECT(r[jss::Account] == scAlice.human()); - BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID); - BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 1); - BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0); - } - - { - // request the xchain_claim_id via RPC - json::Value jvParams; - jvParams[jss::xchain_owned_claim_id] = jvXRPBridgeRPC; - jvParams[jss::xchain_owned_claim_id][jss::xchain_owned_claim_id] = 2; - json::Value const jrr = - scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(jrr.isMember(jss::node)); - auto r = jrr[jss::node]; - - BEAST_EXPECT(r.isMember(jss::Account)); - BEAST_EXPECT(r[jss::Account] == scBob.human()); - BEAST_EXPECT(r[sfLedgerEntryType.jsonName] == jss::XChainOwnedClaimID); - BEAST_EXPECT(r[sfXChainClaimID.jsonName].asInt() == 2); - BEAST_EXPECT(r[sfOwnerNode.jsonName].asInt() == 0); - } - } - - void - testCreateAccountClaimID() - { - testcase("ledger_entry: xchain_create_account_claim_id"); - using namespace test::jtx; - - Env mcEnv{*this, features}; - Env scEnv(*this, envconfig(), features); - - // note: signers.size() and quorum are both 5 in createBridgeObjects - createBridgeObjects(mcEnv, scEnv); - - auto scCarol = Account("scCarol"); // Don't fund it - it will be created with the - // xchain transaction - auto const amt = XRP(1000); - mcEnv(sidechainXchainAccountCreate(mcAlice, jvb, scCarol, amt, reward)); - mcEnv.close(); - - // send less than quorum of attestations (otherwise funds are - // immediately transferred and no "claim" object is created) - static constexpr size_t kNumAttest = 3; - auto attestations = createAccountAttestations( - scAttester, - jvb, - mcAlice, - amt, - reward, - payee, - /*wasLockingChainSend*/ true, - 1, - scCarol, - signers, - kUtXchainDefaultNumSigners); - for (size_t i = 0; i < kNumAttest; ++i) - { - scEnv(attestations[i]); - } - scEnv.close(); - - { - // request the create account claim_id via RPC - json::Value jvParams; - jvParams[jss::xchain_owned_create_account_claim_id] = jvXRPBridgeRPC; - jvParams[jss::xchain_owned_create_account_claim_id] - [jss::xchain_owned_create_account_claim_id] = 1; - json::Value const jrr = - scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(jrr.isMember(jss::node)); - auto r = jrr[jss::node]; - - BEAST_EXPECT(r.isMember(jss::Account)); - BEAST_EXPECT(r[jss::Account] == Account::kMaster.human()); - - BEAST_EXPECT(r.isMember(sfXChainAccountCreateCount.jsonName)); - BEAST_EXPECT(r[sfXChainAccountCreateCount.jsonName].asInt() == 1); - - BEAST_EXPECT(r.isMember(sfXChainCreateAccountAttestations.jsonName)); - auto attest = r[sfXChainCreateAccountAttestations.jsonName]; - BEAST_EXPECT(attest.isArray()); - BEAST_EXPECT(attest.size() == 3); - BEAST_EXPECT( - attest[json::Value::UInt(0)].isMember(sfXChainCreateAccountProofSig.jsonName)); - json::Value a[kNumAttest]; - for (auto& attestation : a) - { - attestation = attest[json::Value::UInt(0)][sfXChainCreateAccountProofSig.jsonName]; - BEAST_EXPECT( - attestation.isMember(jss::Amount) && - attestation[jss::Amount].asInt() == 1000 * kDropPerXrp); - BEAST_EXPECT( - attestation.isMember(jss::Destination) && - attestation[jss::Destination] == scCarol.human()); - BEAST_EXPECT( - attestation.isMember(sfAttestationSignerAccount.jsonName) && - std::ranges::any_of(signers, [&](Signer const& s) { - return attestation[sfAttestationSignerAccount.jsonName] == - s.account.human(); - })); - BEAST_EXPECT( - attestation.isMember(sfAttestationRewardAccount.jsonName) && - std::ranges::any_of(payee, [&](Account const& account) { - return attestation[sfAttestationRewardAccount.jsonName] == account.human(); - })); - BEAST_EXPECT( - attestation.isMember(sfWasLockingChainSend.jsonName) && - attestation[sfWasLockingChainSend.jsonName] == 1); - BEAST_EXPECT( - attestation.isMember(sfSignatureReward.jsonName) && - attestation[sfSignatureReward.jsonName].asInt() == 1 * kDropPerXrp); - } - } - - // complete attestations quorum - CreateAccountClaimID should not be - // present anymore - for (size_t i = kNumAttest; i < kUtXchainDefaultNumSigners; ++i) - { - scEnv(attestations[i]); - } - scEnv.close(); - { - // request the create account claim_id via RPC - json::Value jvParams; - jvParams[jss::xchain_owned_create_account_claim_id] = jvXRPBridgeRPC; - jvParams[jss::xchain_owned_create_account_claim_id] - [jss::xchain_owned_create_account_claim_id] = 1; - json::Value const jrr = - scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "entryNotFound", "Entry not found."); - } - } - -public: - void - run() override - { - testBridge(); - testClaimID(); - testCreateAccountClaimID(); - } -}; - BEAST_DEFINE_TESTSUITE(LedgerEntry, rpc, xrpl); -BEAST_DEFINE_TESTSUITE(LedgerEntry_XChain, rpc, xrpl); } // namespace xrpl::test diff --git a/src/tests/libxrpl/protocol_autogen/TestHelpers.h b/src/tests/libxrpl/protocol_autogen/TestHelpers.h index 0fc26032f0..93151cdc84 100644 --- a/src/tests/libxrpl/protocol_autogen/TestHelpers.h +++ b/src/tests/libxrpl/protocol_autogen/TestHelpers.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -142,13 +141,6 @@ canonical_VL() return BlobValue{data.data(), data.size()}; } -using XChainBridgeValue = std::decay_t; -inline XChainBridgeValue -canonical_XCHAIN_BRIDGE() -{ - return XChainBridgeValue{xrpAccount(), xrpIssue(), xrpAccount(), xrpIssue()}; -} - // Untyped field canonical values inline STArray diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/BridgeTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/BridgeTests.cpp deleted file mode 100644 index 1d4cfc00b9..0000000000 --- a/src/tests/libxrpl/protocol_autogen/ledger_entries/BridgeTests.cpp +++ /dev/null @@ -1,341 +0,0 @@ -// Auto-generated unit tests for ledger entry Bridge - - -#include - -#include - -#include -#include -#include - -#include - -namespace xrpl::ledger_entries { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed for both the -// builder's STObject and the wrapper's SLE. -TEST(BridgeTests, BuilderSettersRoundTrip) -{ - uint256 const index{1u}; - - auto const accountValue = canonical_ACCOUNT(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const minAccountCreateAmountValue = canonical_AMOUNT(); - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const xChainAccountCreateCountValue = canonical_UINT64(); - auto const xChainAccountClaimCountValue = canonical_UINT64(); - auto const ownerNodeValue = canonical_UINT64(); - auto const previousTxnIDValue = canonical_UINT256(); - auto const previousTxnLgrSeqValue = canonical_UINT32(); - - BridgeBuilder builder{ - accountValue, - signatureRewardValue, - xChainBridgeValue, - xChainClaimIDValue, - xChainAccountCreateCountValue, - xChainAccountClaimCountValue, - ownerNodeValue, - previousTxnIDValue, - previousTxnLgrSeqValue - }; - - builder.setMinAccountCreateAmount(minAccountCreateAmountValue); - - builder.setLedgerIndex(index); - builder.setFlags(0x1u); - - EXPECT_TRUE(builder.validate()); - - auto const entry = builder.build(index); - - EXPECT_TRUE(entry.validate()); - - { - auto const& expected = accountValue; - auto const actual = entry.getAccount(); - expectEqualField(expected, actual, "sfAccount"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = entry.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - { - auto const& expected = xChainBridgeValue; - auto const actual = entry.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = entry.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - { - auto const& expected = xChainAccountCreateCountValue; - auto const actual = entry.getXChainAccountCreateCount(); - expectEqualField(expected, actual, "sfXChainAccountCreateCount"); - } - - { - auto const& expected = xChainAccountClaimCountValue; - auto const actual = entry.getXChainAccountClaimCount(); - expectEqualField(expected, actual, "sfXChainAccountClaimCount"); - } - - { - auto const& expected = ownerNodeValue; - auto const actual = entry.getOwnerNode(); - expectEqualField(expected, actual, "sfOwnerNode"); - } - - { - auto const& expected = previousTxnIDValue; - auto const actual = entry.getPreviousTxnID(); - expectEqualField(expected, actual, "sfPreviousTxnID"); - } - - { - auto const& expected = previousTxnLgrSeqValue; - auto const actual = entry.getPreviousTxnLgrSeq(); - expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); - } - - { - auto const& expected = minAccountCreateAmountValue; - auto const actualOpt = entry.getMinAccountCreateAmount(); - ASSERT_TRUE(actualOpt.has_value()); - expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); - EXPECT_TRUE(entry.hasMinAccountCreateAmount()); - } - - EXPECT_TRUE(entry.hasLedgerIndex()); - auto const ledgerIndex = entry.getLedgerIndex(); - ASSERT_TRUE(ledgerIndex.has_value()); - EXPECT_EQ(*ledgerIndex, index); - EXPECT_EQ(entry.getKey(), index); -} - -// 2 & 4) Start from an SLE, set fields directly on it, construct a builder -// from that SLE, build a new wrapper, and verify all fields (and validate()). -TEST(BridgeTests, BuilderFromSleRoundTrip) -{ - uint256 const index{2u}; - - auto const accountValue = canonical_ACCOUNT(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const minAccountCreateAmountValue = canonical_AMOUNT(); - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const xChainAccountCreateCountValue = canonical_UINT64(); - auto const xChainAccountClaimCountValue = canonical_UINT64(); - auto const ownerNodeValue = canonical_UINT64(); - auto const previousTxnIDValue = canonical_UINT256(); - auto const previousTxnLgrSeqValue = canonical_UINT32(); - - auto sle = std::make_shared(Bridge::entryType, index); - - sle->at(sfAccount) = accountValue; - sle->at(sfSignatureReward) = signatureRewardValue; - sle->at(sfMinAccountCreateAmount) = minAccountCreateAmountValue; - sle->at(sfXChainBridge) = xChainBridgeValue; - sle->at(sfXChainClaimID) = xChainClaimIDValue; - sle->at(sfXChainAccountCreateCount) = xChainAccountCreateCountValue; - sle->at(sfXChainAccountClaimCount) = xChainAccountClaimCountValue; - sle->at(sfOwnerNode) = ownerNodeValue; - sle->at(sfPreviousTxnID) = previousTxnIDValue; - sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; - - BridgeBuilder builderFromSle{sle}; - EXPECT_TRUE(builderFromSle.validate()); - - auto const entryFromBuilder = builderFromSle.build(index); - - Bridge entryFromSle{sle}; - EXPECT_TRUE(entryFromBuilder.validate()); - EXPECT_TRUE(entryFromSle.validate()); - - { - auto const& expected = accountValue; - - auto const fromSle = entryFromSle.getAccount(); - auto const fromBuilder = entryFromBuilder.getAccount(); - - expectEqualField(expected, fromSle, "sfAccount"); - expectEqualField(expected, fromBuilder, "sfAccount"); - } - - { - auto const& expected = signatureRewardValue; - - auto const fromSle = entryFromSle.getSignatureReward(); - auto const fromBuilder = entryFromBuilder.getSignatureReward(); - - expectEqualField(expected, fromSle, "sfSignatureReward"); - expectEqualField(expected, fromBuilder, "sfSignatureReward"); - } - - { - auto const& expected = xChainBridgeValue; - - auto const fromSle = entryFromSle.getXChainBridge(); - auto const fromBuilder = entryFromBuilder.getXChainBridge(); - - expectEqualField(expected, fromSle, "sfXChainBridge"); - expectEqualField(expected, fromBuilder, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - - auto const fromSle = entryFromSle.getXChainClaimID(); - auto const fromBuilder = entryFromBuilder.getXChainClaimID(); - - expectEqualField(expected, fromSle, "sfXChainClaimID"); - expectEqualField(expected, fromBuilder, "sfXChainClaimID"); - } - - { - auto const& expected = xChainAccountCreateCountValue; - - auto const fromSle = entryFromSle.getXChainAccountCreateCount(); - auto const fromBuilder = entryFromBuilder.getXChainAccountCreateCount(); - - expectEqualField(expected, fromSle, "sfXChainAccountCreateCount"); - expectEqualField(expected, fromBuilder, "sfXChainAccountCreateCount"); - } - - { - auto const& expected = xChainAccountClaimCountValue; - - auto const fromSle = entryFromSle.getXChainAccountClaimCount(); - auto const fromBuilder = entryFromBuilder.getXChainAccountClaimCount(); - - expectEqualField(expected, fromSle, "sfXChainAccountClaimCount"); - expectEqualField(expected, fromBuilder, "sfXChainAccountClaimCount"); - } - - { - auto const& expected = ownerNodeValue; - - auto const fromSle = entryFromSle.getOwnerNode(); - auto const fromBuilder = entryFromBuilder.getOwnerNode(); - - expectEqualField(expected, fromSle, "sfOwnerNode"); - expectEqualField(expected, fromBuilder, "sfOwnerNode"); - } - - { - auto const& expected = previousTxnIDValue; - - auto const fromSle = entryFromSle.getPreviousTxnID(); - auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); - - expectEqualField(expected, fromSle, "sfPreviousTxnID"); - expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); - } - - { - auto const& expected = previousTxnLgrSeqValue; - - auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); - auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); - - expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); - expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); - } - - { - auto const& expected = minAccountCreateAmountValue; - - auto const fromSleOpt = entryFromSle.getMinAccountCreateAmount(); - auto const fromBuilderOpt = entryFromBuilder.getMinAccountCreateAmount(); - - ASSERT_TRUE(fromSleOpt.has_value()); - ASSERT_TRUE(fromBuilderOpt.has_value()); - - expectEqualField(expected, *fromSleOpt, "sfMinAccountCreateAmount"); - expectEqualField(expected, *fromBuilderOpt, "sfMinAccountCreateAmount"); - } - - EXPECT_EQ(entryFromSle.getKey(), index); - EXPECT_EQ(entryFromBuilder.getKey(), index); -} - -// 3) Verify wrapper throws when constructed from wrong ledger entry type. -TEST(BridgeTests, WrapperThrowsOnWrongEntryType) -{ - uint256 const index{3u}; - - // Build a valid ledger entry of a different type - // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq - // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq - TicketBuilder wrongBuilder{ - canonical_ACCOUNT(), - canonical_UINT64(), - canonical_UINT32(), - canonical_UINT256(), - canonical_UINT32()}; - auto wrongEntry = wrongBuilder.build(index); - - EXPECT_THROW(Bridge{wrongEntry.getSle()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong ledger entry type. -TEST(BridgeTests, BuilderThrowsOnWrongEntryType) -{ - uint256 const index{4u}; - - // Build a valid ledger entry of a different type - TicketBuilder wrongBuilder{ - canonical_ACCOUNT(), - canonical_UINT64(), - canonical_UINT32(), - canonical_UINT256(), - canonical_UINT32()}; - auto wrongEntry = wrongBuilder.build(index); - - EXPECT_THROW(BridgeBuilder{wrongEntry.getSle()}, std::runtime_error); -} - -// 5) Build with only required fields and verify optional fields return nullopt. -TEST(BridgeTests, OptionalFieldsReturnNullopt) -{ - uint256 const index{3u}; - - auto const accountValue = canonical_ACCOUNT(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const xChainAccountCreateCountValue = canonical_UINT64(); - auto const xChainAccountClaimCountValue = canonical_UINT64(); - auto const ownerNodeValue = canonical_UINT64(); - auto const previousTxnIDValue = canonical_UINT256(); - auto const previousTxnLgrSeqValue = canonical_UINT32(); - - BridgeBuilder builder{ - accountValue, - signatureRewardValue, - xChainBridgeValue, - xChainClaimIDValue, - xChainAccountCreateCountValue, - xChainAccountClaimCountValue, - ownerNodeValue, - previousTxnIDValue, - previousTxnLgrSeqValue - }; - - auto const entry = builder.build(index); - - // Verify optional fields are not present - EXPECT_FALSE(entry.hasMinAccountCreateAmount()); - EXPECT_FALSE(entry.getMinAccountCreateAmount().has_value()); -} -} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedClaimIDTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedClaimIDTests.cpp deleted file mode 100644 index 4b6979b86a..0000000000 --- a/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedClaimIDTests.cpp +++ /dev/null @@ -1,283 +0,0 @@ -// Auto-generated unit tests for ledger entry XChainOwnedClaimID - - -#include - -#include - -#include -#include -#include - -#include - -namespace xrpl::ledger_entries { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed for both the -// builder's STObject and the wrapper's SLE. -TEST(XChainOwnedClaimIDTests, BuilderSettersRoundTrip) -{ - uint256 const index{1u}; - - auto const accountValue = canonical_ACCOUNT(); - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - auto const xChainClaimAttestationsValue = canonical_ARRAY(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const ownerNodeValue = canonical_UINT64(); - auto const previousTxnIDValue = canonical_UINT256(); - auto const previousTxnLgrSeqValue = canonical_UINT32(); - - XChainOwnedClaimIDBuilder builder{ - accountValue, - xChainBridgeValue, - xChainClaimIDValue, - otherChainSourceValue, - xChainClaimAttestationsValue, - signatureRewardValue, - ownerNodeValue, - previousTxnIDValue, - previousTxnLgrSeqValue - }; - - - builder.setLedgerIndex(index); - builder.setFlags(0x1u); - - EXPECT_TRUE(builder.validate()); - - auto const entry = builder.build(index); - - EXPECT_TRUE(entry.validate()); - - { - auto const& expected = accountValue; - auto const actual = entry.getAccount(); - expectEqualField(expected, actual, "sfAccount"); - } - - { - auto const& expected = xChainBridgeValue; - auto const actual = entry.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = entry.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - { - auto const& expected = otherChainSourceValue; - auto const actual = entry.getOtherChainSource(); - expectEqualField(expected, actual, "sfOtherChainSource"); - } - - { - auto const& expected = xChainClaimAttestationsValue; - auto const actual = entry.getXChainClaimAttestations(); - expectEqualField(expected, actual, "sfXChainClaimAttestations"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = entry.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - { - auto const& expected = ownerNodeValue; - auto const actual = entry.getOwnerNode(); - expectEqualField(expected, actual, "sfOwnerNode"); - } - - { - auto const& expected = previousTxnIDValue; - auto const actual = entry.getPreviousTxnID(); - expectEqualField(expected, actual, "sfPreviousTxnID"); - } - - { - auto const& expected = previousTxnLgrSeqValue; - auto const actual = entry.getPreviousTxnLgrSeq(); - expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); - } - - EXPECT_TRUE(entry.hasLedgerIndex()); - auto const ledgerIndex = entry.getLedgerIndex(); - ASSERT_TRUE(ledgerIndex.has_value()); - EXPECT_EQ(*ledgerIndex, index); - EXPECT_EQ(entry.getKey(), index); -} - -// 2 & 4) Start from an SLE, set fields directly on it, construct a builder -// from that SLE, build a new wrapper, and verify all fields (and validate()). -TEST(XChainOwnedClaimIDTests, BuilderFromSleRoundTrip) -{ - uint256 const index{2u}; - - auto const accountValue = canonical_ACCOUNT(); - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - auto const xChainClaimAttestationsValue = canonical_ARRAY(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const ownerNodeValue = canonical_UINT64(); - auto const previousTxnIDValue = canonical_UINT256(); - auto const previousTxnLgrSeqValue = canonical_UINT32(); - - auto sle = std::make_shared(XChainOwnedClaimID::entryType, index); - - sle->at(sfAccount) = accountValue; - sle->at(sfXChainBridge) = xChainBridgeValue; - sle->at(sfXChainClaimID) = xChainClaimIDValue; - sle->at(sfOtherChainSource) = otherChainSourceValue; - sle->setFieldArray(sfXChainClaimAttestations, xChainClaimAttestationsValue); - sle->at(sfSignatureReward) = signatureRewardValue; - sle->at(sfOwnerNode) = ownerNodeValue; - sle->at(sfPreviousTxnID) = previousTxnIDValue; - sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; - - XChainOwnedClaimIDBuilder builderFromSle{sle}; - EXPECT_TRUE(builderFromSle.validate()); - - auto const entryFromBuilder = builderFromSle.build(index); - - XChainOwnedClaimID entryFromSle{sle}; - EXPECT_TRUE(entryFromBuilder.validate()); - EXPECT_TRUE(entryFromSle.validate()); - - { - auto const& expected = accountValue; - - auto const fromSle = entryFromSle.getAccount(); - auto const fromBuilder = entryFromBuilder.getAccount(); - - expectEqualField(expected, fromSle, "sfAccount"); - expectEqualField(expected, fromBuilder, "sfAccount"); - } - - { - auto const& expected = xChainBridgeValue; - - auto const fromSle = entryFromSle.getXChainBridge(); - auto const fromBuilder = entryFromBuilder.getXChainBridge(); - - expectEqualField(expected, fromSle, "sfXChainBridge"); - expectEqualField(expected, fromBuilder, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - - auto const fromSle = entryFromSle.getXChainClaimID(); - auto const fromBuilder = entryFromBuilder.getXChainClaimID(); - - expectEqualField(expected, fromSle, "sfXChainClaimID"); - expectEqualField(expected, fromBuilder, "sfXChainClaimID"); - } - - { - auto const& expected = otherChainSourceValue; - - auto const fromSle = entryFromSle.getOtherChainSource(); - auto const fromBuilder = entryFromBuilder.getOtherChainSource(); - - expectEqualField(expected, fromSle, "sfOtherChainSource"); - expectEqualField(expected, fromBuilder, "sfOtherChainSource"); - } - - { - auto const& expected = xChainClaimAttestationsValue; - - auto const fromSle = entryFromSle.getXChainClaimAttestations(); - auto const fromBuilder = entryFromBuilder.getXChainClaimAttestations(); - - expectEqualField(expected, fromSle, "sfXChainClaimAttestations"); - expectEqualField(expected, fromBuilder, "sfXChainClaimAttestations"); - } - - { - auto const& expected = signatureRewardValue; - - auto const fromSle = entryFromSle.getSignatureReward(); - auto const fromBuilder = entryFromBuilder.getSignatureReward(); - - expectEqualField(expected, fromSle, "sfSignatureReward"); - expectEqualField(expected, fromBuilder, "sfSignatureReward"); - } - - { - auto const& expected = ownerNodeValue; - - auto const fromSle = entryFromSle.getOwnerNode(); - auto const fromBuilder = entryFromBuilder.getOwnerNode(); - - expectEqualField(expected, fromSle, "sfOwnerNode"); - expectEqualField(expected, fromBuilder, "sfOwnerNode"); - } - - { - auto const& expected = previousTxnIDValue; - - auto const fromSle = entryFromSle.getPreviousTxnID(); - auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); - - expectEqualField(expected, fromSle, "sfPreviousTxnID"); - expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); - } - - { - auto const& expected = previousTxnLgrSeqValue; - - auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); - auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); - - expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); - expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); - } - - EXPECT_EQ(entryFromSle.getKey(), index); - EXPECT_EQ(entryFromBuilder.getKey(), index); -} - -// 3) Verify wrapper throws when constructed from wrong ledger entry type. -TEST(XChainOwnedClaimIDTests, WrapperThrowsOnWrongEntryType) -{ - uint256 const index{3u}; - - // Build a valid ledger entry of a different type - // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq - // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq - TicketBuilder wrongBuilder{ - canonical_ACCOUNT(), - canonical_UINT64(), - canonical_UINT32(), - canonical_UINT256(), - canonical_UINT32()}; - auto wrongEntry = wrongBuilder.build(index); - - EXPECT_THROW(XChainOwnedClaimID{wrongEntry.getSle()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong ledger entry type. -TEST(XChainOwnedClaimIDTests, BuilderThrowsOnWrongEntryType) -{ - uint256 const index{4u}; - - // Build a valid ledger entry of a different type - TicketBuilder wrongBuilder{ - canonical_ACCOUNT(), - canonical_UINT64(), - canonical_UINT32(), - canonical_UINT256(), - canonical_UINT32()}; - auto wrongEntry = wrongBuilder.build(index); - - EXPECT_THROW(XChainOwnedClaimIDBuilder{wrongEntry.getSle()}, std::runtime_error); -} - -} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimIDTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimIDTests.cpp deleted file mode 100644 index 0e4e1fb977..0000000000 --- a/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimIDTests.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// Auto-generated unit tests for ledger entry XChainOwnedCreateAccountClaimID - - -#include - -#include - -#include -#include -#include - -#include - -namespace xrpl::ledger_entries { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed for both the -// builder's STObject and the wrapper's SLE. -TEST(XChainOwnedCreateAccountClaimIDTests, BuilderSettersRoundTrip) -{ - uint256 const index{1u}; - - auto const accountValue = canonical_ACCOUNT(); - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainAccountCreateCountValue = canonical_UINT64(); - auto const xChainCreateAccountAttestationsValue = canonical_ARRAY(); - auto const ownerNodeValue = canonical_UINT64(); - auto const previousTxnIDValue = canonical_UINT256(); - auto const previousTxnLgrSeqValue = canonical_UINT32(); - - XChainOwnedCreateAccountClaimIDBuilder builder{ - accountValue, - xChainBridgeValue, - xChainAccountCreateCountValue, - xChainCreateAccountAttestationsValue, - ownerNodeValue, - previousTxnIDValue, - previousTxnLgrSeqValue - }; - - - builder.setLedgerIndex(index); - builder.setFlags(0x1u); - - EXPECT_TRUE(builder.validate()); - - auto const entry = builder.build(index); - - EXPECT_TRUE(entry.validate()); - - { - auto const& expected = accountValue; - auto const actual = entry.getAccount(); - expectEqualField(expected, actual, "sfAccount"); - } - - { - auto const& expected = xChainBridgeValue; - auto const actual = entry.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = xChainAccountCreateCountValue; - auto const actual = entry.getXChainAccountCreateCount(); - expectEqualField(expected, actual, "sfXChainAccountCreateCount"); - } - - { - auto const& expected = xChainCreateAccountAttestationsValue; - auto const actual = entry.getXChainCreateAccountAttestations(); - expectEqualField(expected, actual, "sfXChainCreateAccountAttestations"); - } - - { - auto const& expected = ownerNodeValue; - auto const actual = entry.getOwnerNode(); - expectEqualField(expected, actual, "sfOwnerNode"); - } - - { - auto const& expected = previousTxnIDValue; - auto const actual = entry.getPreviousTxnID(); - expectEqualField(expected, actual, "sfPreviousTxnID"); - } - - { - auto const& expected = previousTxnLgrSeqValue; - auto const actual = entry.getPreviousTxnLgrSeq(); - expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); - } - - EXPECT_TRUE(entry.hasLedgerIndex()); - auto const ledgerIndex = entry.getLedgerIndex(); - ASSERT_TRUE(ledgerIndex.has_value()); - EXPECT_EQ(*ledgerIndex, index); - EXPECT_EQ(entry.getKey(), index); -} - -// 2 & 4) Start from an SLE, set fields directly on it, construct a builder -// from that SLE, build a new wrapper, and verify all fields (and validate()). -TEST(XChainOwnedCreateAccountClaimIDTests, BuilderFromSleRoundTrip) -{ - uint256 const index{2u}; - - auto const accountValue = canonical_ACCOUNT(); - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainAccountCreateCountValue = canonical_UINT64(); - auto const xChainCreateAccountAttestationsValue = canonical_ARRAY(); - auto const ownerNodeValue = canonical_UINT64(); - auto const previousTxnIDValue = canonical_UINT256(); - auto const previousTxnLgrSeqValue = canonical_UINT32(); - - auto sle = std::make_shared(XChainOwnedCreateAccountClaimID::entryType, index); - - sle->at(sfAccount) = accountValue; - sle->at(sfXChainBridge) = xChainBridgeValue; - sle->at(sfXChainAccountCreateCount) = xChainAccountCreateCountValue; - sle->setFieldArray(sfXChainCreateAccountAttestations, xChainCreateAccountAttestationsValue); - sle->at(sfOwnerNode) = ownerNodeValue; - sle->at(sfPreviousTxnID) = previousTxnIDValue; - sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; - - XChainOwnedCreateAccountClaimIDBuilder builderFromSle{sle}; - EXPECT_TRUE(builderFromSle.validate()); - - auto const entryFromBuilder = builderFromSle.build(index); - - XChainOwnedCreateAccountClaimID entryFromSle{sle}; - EXPECT_TRUE(entryFromBuilder.validate()); - EXPECT_TRUE(entryFromSle.validate()); - - { - auto const& expected = accountValue; - - auto const fromSle = entryFromSle.getAccount(); - auto const fromBuilder = entryFromBuilder.getAccount(); - - expectEqualField(expected, fromSle, "sfAccount"); - expectEqualField(expected, fromBuilder, "sfAccount"); - } - - { - auto const& expected = xChainBridgeValue; - - auto const fromSle = entryFromSle.getXChainBridge(); - auto const fromBuilder = entryFromBuilder.getXChainBridge(); - - expectEqualField(expected, fromSle, "sfXChainBridge"); - expectEqualField(expected, fromBuilder, "sfXChainBridge"); - } - - { - auto const& expected = xChainAccountCreateCountValue; - - auto const fromSle = entryFromSle.getXChainAccountCreateCount(); - auto const fromBuilder = entryFromBuilder.getXChainAccountCreateCount(); - - expectEqualField(expected, fromSle, "sfXChainAccountCreateCount"); - expectEqualField(expected, fromBuilder, "sfXChainAccountCreateCount"); - } - - { - auto const& expected = xChainCreateAccountAttestationsValue; - - auto const fromSle = entryFromSle.getXChainCreateAccountAttestations(); - auto const fromBuilder = entryFromBuilder.getXChainCreateAccountAttestations(); - - expectEqualField(expected, fromSle, "sfXChainCreateAccountAttestations"); - expectEqualField(expected, fromBuilder, "sfXChainCreateAccountAttestations"); - } - - { - auto const& expected = ownerNodeValue; - - auto const fromSle = entryFromSle.getOwnerNode(); - auto const fromBuilder = entryFromBuilder.getOwnerNode(); - - expectEqualField(expected, fromSle, "sfOwnerNode"); - expectEqualField(expected, fromBuilder, "sfOwnerNode"); - } - - { - auto const& expected = previousTxnIDValue; - - auto const fromSle = entryFromSle.getPreviousTxnID(); - auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); - - expectEqualField(expected, fromSle, "sfPreviousTxnID"); - expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); - } - - { - auto const& expected = previousTxnLgrSeqValue; - - auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); - auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); - - expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); - expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); - } - - EXPECT_EQ(entryFromSle.getKey(), index); - EXPECT_EQ(entryFromBuilder.getKey(), index); -} - -// 3) Verify wrapper throws when constructed from wrong ledger entry type. -TEST(XChainOwnedCreateAccountClaimIDTests, WrapperThrowsOnWrongEntryType) -{ - uint256 const index{3u}; - - // Build a valid ledger entry of a different type - // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq - // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq - TicketBuilder wrongBuilder{ - canonical_ACCOUNT(), - canonical_UINT64(), - canonical_UINT32(), - canonical_UINT256(), - canonical_UINT32()}; - auto wrongEntry = wrongBuilder.build(index); - - EXPECT_THROW(XChainOwnedCreateAccountClaimID{wrongEntry.getSle()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong ledger entry type. -TEST(XChainOwnedCreateAccountClaimIDTests, BuilderThrowsOnWrongEntryType) -{ - uint256 const index{4u}; - - // Build a valid ledger entry of a different type - TicketBuilder wrongBuilder{ - canonical_ACCOUNT(), - canonical_UINT64(), - canonical_UINT32(), - canonical_UINT256(), - canonical_UINT32()}; - auto wrongEntry = wrongBuilder.build(index); - - EXPECT_THROW(XChainOwnedCreateAccountClaimIDBuilder{wrongEntry.getSle()}, std::runtime_error); -} - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainAccountCreateCommitTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainAccountCreateCommitTests.cpp deleted file mode 100644 index 3c7ac4e193..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainAccountCreateCommitTests.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// Auto-generated unit tests for transaction XChainAccountCreateCommit - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainAccountCreateCommitTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainAccountCreateCommit")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const destinationValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - auto const signatureRewardValue = canonical_AMOUNT(); - - XChainAccountCreateCommitBuilder builder{ - accountValue, - xChainBridgeValue, - destinationValue, - amountValue, - signatureRewardValue, - sequenceValue, - feeValue - }; - - // Set optional fields - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = destinationValue; - auto const actual = tx.getDestination(); - expectEqualField(expected, actual, "sfDestination"); - } - - { - auto const& expected = amountValue; - auto const actual = tx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = tx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - // Verify optional fields -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainAccountCreateCommitTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainAccountCreateCommitFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const destinationValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - auto const signatureRewardValue = canonical_AMOUNT(); - - // Build an initial transaction - XChainAccountCreateCommitBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - destinationValue, - amountValue, - signatureRewardValue, - sequenceValue, - feeValue - }; - - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainAccountCreateCommitBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = destinationValue; - auto const actual = rebuiltTx.getDestination(); - expectEqualField(expected, actual, "sfDestination"); - } - - { - auto const& expected = amountValue; - auto const actual = rebuiltTx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = rebuiltTx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - // Verify optional fields -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainAccountCreateCommitTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainAccountCreateCommit{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainAccountCreateCommitTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainAccountCreateCommitBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestationTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestationTests.cpp deleted file mode 100644 index 9bb79f31f6..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestationTests.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// Auto-generated unit tests for transaction XChainAddAccountCreateAttestation - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainAddAccountCreateAttestationTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainAddAccountCreateAttestation")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const attestationSignerAccountValue = canonical_ACCOUNT(); - auto const publicKeyValue = canonical_VL(); - auto const signatureValue = canonical_VL(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - auto const attestationRewardAccountValue = canonical_ACCOUNT(); - auto const wasLockingChainSendValue = canonical_UINT8(); - auto const xChainAccountCreateCountValue = canonical_UINT64(); - auto const destinationValue = canonical_ACCOUNT(); - auto const signatureRewardValue = canonical_AMOUNT(); - - XChainAddAccountCreateAttestationBuilder builder{ - accountValue, - xChainBridgeValue, - attestationSignerAccountValue, - publicKeyValue, - signatureValue, - otherChainSourceValue, - amountValue, - attestationRewardAccountValue, - wasLockingChainSendValue, - xChainAccountCreateCountValue, - destinationValue, - signatureRewardValue, - sequenceValue, - feeValue - }; - - // Set optional fields - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = attestationSignerAccountValue; - auto const actual = tx.getAttestationSignerAccount(); - expectEqualField(expected, actual, "sfAttestationSignerAccount"); - } - - { - auto const& expected = publicKeyValue; - auto const actual = tx.getPublicKey(); - expectEqualField(expected, actual, "sfPublicKey"); - } - - { - auto const& expected = signatureValue; - auto const actual = tx.getSignature(); - expectEqualField(expected, actual, "sfSignature"); - } - - { - auto const& expected = otherChainSourceValue; - auto const actual = tx.getOtherChainSource(); - expectEqualField(expected, actual, "sfOtherChainSource"); - } - - { - auto const& expected = amountValue; - auto const actual = tx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - { - auto const& expected = attestationRewardAccountValue; - auto const actual = tx.getAttestationRewardAccount(); - expectEqualField(expected, actual, "sfAttestationRewardAccount"); - } - - { - auto const& expected = wasLockingChainSendValue; - auto const actual = tx.getWasLockingChainSend(); - expectEqualField(expected, actual, "sfWasLockingChainSend"); - } - - { - auto const& expected = xChainAccountCreateCountValue; - auto const actual = tx.getXChainAccountCreateCount(); - expectEqualField(expected, actual, "sfXChainAccountCreateCount"); - } - - { - auto const& expected = destinationValue; - auto const actual = tx.getDestination(); - expectEqualField(expected, actual, "sfDestination"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = tx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - // Verify optional fields -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainAddAccountCreateAttestationTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainAddAccountCreateAttestationFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const attestationSignerAccountValue = canonical_ACCOUNT(); - auto const publicKeyValue = canonical_VL(); - auto const signatureValue = canonical_VL(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - auto const attestationRewardAccountValue = canonical_ACCOUNT(); - auto const wasLockingChainSendValue = canonical_UINT8(); - auto const xChainAccountCreateCountValue = canonical_UINT64(); - auto const destinationValue = canonical_ACCOUNT(); - auto const signatureRewardValue = canonical_AMOUNT(); - - // Build an initial transaction - XChainAddAccountCreateAttestationBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - attestationSignerAccountValue, - publicKeyValue, - signatureValue, - otherChainSourceValue, - amountValue, - attestationRewardAccountValue, - wasLockingChainSendValue, - xChainAccountCreateCountValue, - destinationValue, - signatureRewardValue, - sequenceValue, - feeValue - }; - - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainAddAccountCreateAttestationBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = attestationSignerAccountValue; - auto const actual = rebuiltTx.getAttestationSignerAccount(); - expectEqualField(expected, actual, "sfAttestationSignerAccount"); - } - - { - auto const& expected = publicKeyValue; - auto const actual = rebuiltTx.getPublicKey(); - expectEqualField(expected, actual, "sfPublicKey"); - } - - { - auto const& expected = signatureValue; - auto const actual = rebuiltTx.getSignature(); - expectEqualField(expected, actual, "sfSignature"); - } - - { - auto const& expected = otherChainSourceValue; - auto const actual = rebuiltTx.getOtherChainSource(); - expectEqualField(expected, actual, "sfOtherChainSource"); - } - - { - auto const& expected = amountValue; - auto const actual = rebuiltTx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - { - auto const& expected = attestationRewardAccountValue; - auto const actual = rebuiltTx.getAttestationRewardAccount(); - expectEqualField(expected, actual, "sfAttestationRewardAccount"); - } - - { - auto const& expected = wasLockingChainSendValue; - auto const actual = rebuiltTx.getWasLockingChainSend(); - expectEqualField(expected, actual, "sfWasLockingChainSend"); - } - - { - auto const& expected = xChainAccountCreateCountValue; - auto const actual = rebuiltTx.getXChainAccountCreateCount(); - expectEqualField(expected, actual, "sfXChainAccountCreateCount"); - } - - { - auto const& expected = destinationValue; - auto const actual = rebuiltTx.getDestination(); - expectEqualField(expected, actual, "sfDestination"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = rebuiltTx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - // Verify optional fields -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainAddAccountCreateAttestationTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainAddAccountCreateAttestation{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainAddAccountCreateAttestationTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainAddAccountCreateAttestationBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainAddClaimAttestationTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainAddClaimAttestationTests.cpp deleted file mode 100644 index 661e5020f9..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainAddClaimAttestationTests.cpp +++ /dev/null @@ -1,339 +0,0 @@ -// Auto-generated unit tests for transaction XChainAddClaimAttestation - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainAddClaimAttestationTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainAddClaimAttestation")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const attestationSignerAccountValue = canonical_ACCOUNT(); - auto const publicKeyValue = canonical_VL(); - auto const signatureValue = canonical_VL(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - auto const attestationRewardAccountValue = canonical_ACCOUNT(); - auto const wasLockingChainSendValue = canonical_UINT8(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const destinationValue = canonical_ACCOUNT(); - - XChainAddClaimAttestationBuilder builder{ - accountValue, - xChainBridgeValue, - attestationSignerAccountValue, - publicKeyValue, - signatureValue, - otherChainSourceValue, - amountValue, - attestationRewardAccountValue, - wasLockingChainSendValue, - xChainClaimIDValue, - sequenceValue, - feeValue - }; - - // Set optional fields - builder.setDestination(destinationValue); - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = attestationSignerAccountValue; - auto const actual = tx.getAttestationSignerAccount(); - expectEqualField(expected, actual, "sfAttestationSignerAccount"); - } - - { - auto const& expected = publicKeyValue; - auto const actual = tx.getPublicKey(); - expectEqualField(expected, actual, "sfPublicKey"); - } - - { - auto const& expected = signatureValue; - auto const actual = tx.getSignature(); - expectEqualField(expected, actual, "sfSignature"); - } - - { - auto const& expected = otherChainSourceValue; - auto const actual = tx.getOtherChainSource(); - expectEqualField(expected, actual, "sfOtherChainSource"); - } - - { - auto const& expected = amountValue; - auto const actual = tx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - { - auto const& expected = attestationRewardAccountValue; - auto const actual = tx.getAttestationRewardAccount(); - expectEqualField(expected, actual, "sfAttestationRewardAccount"); - } - - { - auto const& expected = wasLockingChainSendValue; - auto const actual = tx.getWasLockingChainSend(); - expectEqualField(expected, actual, "sfWasLockingChainSend"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = tx.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - // Verify optional fields - { - auto const& expected = destinationValue; - auto const actualOpt = tx.getDestination(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; - expectEqualField(expected, *actualOpt, "sfDestination"); - EXPECT_TRUE(tx.hasDestination()); - } - -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainAddClaimAttestationTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainAddClaimAttestationFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const attestationSignerAccountValue = canonical_ACCOUNT(); - auto const publicKeyValue = canonical_VL(); - auto const signatureValue = canonical_VL(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - auto const attestationRewardAccountValue = canonical_ACCOUNT(); - auto const wasLockingChainSendValue = canonical_UINT8(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const destinationValue = canonical_ACCOUNT(); - - // Build an initial transaction - XChainAddClaimAttestationBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - attestationSignerAccountValue, - publicKeyValue, - signatureValue, - otherChainSourceValue, - amountValue, - attestationRewardAccountValue, - wasLockingChainSendValue, - xChainClaimIDValue, - sequenceValue, - feeValue - }; - - initialBuilder.setDestination(destinationValue); - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainAddClaimAttestationBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = attestationSignerAccountValue; - auto const actual = rebuiltTx.getAttestationSignerAccount(); - expectEqualField(expected, actual, "sfAttestationSignerAccount"); - } - - { - auto const& expected = publicKeyValue; - auto const actual = rebuiltTx.getPublicKey(); - expectEqualField(expected, actual, "sfPublicKey"); - } - - { - auto const& expected = signatureValue; - auto const actual = rebuiltTx.getSignature(); - expectEqualField(expected, actual, "sfSignature"); - } - - { - auto const& expected = otherChainSourceValue; - auto const actual = rebuiltTx.getOtherChainSource(); - expectEqualField(expected, actual, "sfOtherChainSource"); - } - - { - auto const& expected = amountValue; - auto const actual = rebuiltTx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - { - auto const& expected = attestationRewardAccountValue; - auto const actual = rebuiltTx.getAttestationRewardAccount(); - expectEqualField(expected, actual, "sfAttestationRewardAccount"); - } - - { - auto const& expected = wasLockingChainSendValue; - auto const actual = rebuiltTx.getWasLockingChainSend(); - expectEqualField(expected, actual, "sfWasLockingChainSend"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = rebuiltTx.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - // Verify optional fields - { - auto const& expected = destinationValue; - auto const actualOpt = rebuiltTx.getDestination(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; - expectEqualField(expected, *actualOpt, "sfDestination"); - } - -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainAddClaimAttestationTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainAddClaimAttestation{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainAddClaimAttestationTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainAddClaimAttestationBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - -// 5) Build with only required fields and verify optional fields return nullopt. -TEST(TransactionsXChainAddClaimAttestationTests, OptionalFieldsReturnNullopt) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainAddClaimAttestationNullopt")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 3; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific required field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const attestationSignerAccountValue = canonical_ACCOUNT(); - auto const publicKeyValue = canonical_VL(); - auto const signatureValue = canonical_VL(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - auto const attestationRewardAccountValue = canonical_ACCOUNT(); - auto const wasLockingChainSendValue = canonical_UINT8(); - auto const xChainClaimIDValue = canonical_UINT64(); - - XChainAddClaimAttestationBuilder builder{ - accountValue, - xChainBridgeValue, - attestationSignerAccountValue, - publicKeyValue, - signatureValue, - otherChainSourceValue, - amountValue, - attestationRewardAccountValue, - wasLockingChainSendValue, - xChainClaimIDValue, - sequenceValue, - feeValue - }; - - // Do NOT set optional fields - - auto tx = builder.build(publicKey, secretKey); - - // Verify optional fields are not present - EXPECT_FALSE(tx.hasDestination()); - EXPECT_FALSE(tx.getDestination().has_value()); -} - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainClaimTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainClaimTests.cpp deleted file mode 100644 index 472bf4c91d..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainClaimTests.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// Auto-generated unit tests for transaction XChainClaim - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainClaimTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainClaim")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const destinationValue = canonical_ACCOUNT(); - auto const destinationTagValue = canonical_UINT32(); - auto const amountValue = canonical_AMOUNT(); - - XChainClaimBuilder builder{ - accountValue, - xChainBridgeValue, - xChainClaimIDValue, - destinationValue, - amountValue, - sequenceValue, - feeValue - }; - - // Set optional fields - builder.setDestinationTag(destinationTagValue); - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = tx.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - { - auto const& expected = destinationValue; - auto const actual = tx.getDestination(); - expectEqualField(expected, actual, "sfDestination"); - } - - { - auto const& expected = amountValue; - auto const actual = tx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - // Verify optional fields - { - auto const& expected = destinationTagValue; - auto const actualOpt = tx.getDestinationTag(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; - expectEqualField(expected, *actualOpt, "sfDestinationTag"); - EXPECT_TRUE(tx.hasDestinationTag()); - } - -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainClaimTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainClaimFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const destinationValue = canonical_ACCOUNT(); - auto const destinationTagValue = canonical_UINT32(); - auto const amountValue = canonical_AMOUNT(); - - // Build an initial transaction - XChainClaimBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - xChainClaimIDValue, - destinationValue, - amountValue, - sequenceValue, - feeValue - }; - - initialBuilder.setDestinationTag(destinationTagValue); - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainClaimBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = rebuiltTx.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - { - auto const& expected = destinationValue; - auto const actual = rebuiltTx.getDestination(); - expectEqualField(expected, actual, "sfDestination"); - } - - { - auto const& expected = amountValue; - auto const actual = rebuiltTx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - // Verify optional fields - { - auto const& expected = destinationTagValue; - auto const actualOpt = rebuiltTx.getDestinationTag(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; - expectEqualField(expected, *actualOpt, "sfDestinationTag"); - } - -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainClaimTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainClaim{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainClaimTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainClaimBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - -// 5) Build with only required fields and verify optional fields return nullopt. -TEST(TransactionsXChainClaimTests, OptionalFieldsReturnNullopt) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainClaimNullopt")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 3; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific required field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const destinationValue = canonical_ACCOUNT(); - auto const amountValue = canonical_AMOUNT(); - - XChainClaimBuilder builder{ - accountValue, - xChainBridgeValue, - xChainClaimIDValue, - destinationValue, - amountValue, - sequenceValue, - feeValue - }; - - // Do NOT set optional fields - - auto tx = builder.build(publicKey, secretKey); - - // Verify optional fields are not present - EXPECT_FALSE(tx.hasDestinationTag()); - EXPECT_FALSE(tx.getDestinationTag().has_value()); -} - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainCommitTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainCommitTests.cpp deleted file mode 100644 index 121ab84a16..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainCommitTests.cpp +++ /dev/null @@ -1,231 +0,0 @@ -// Auto-generated unit tests for transaction XChainCommit - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainCommitTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCommit")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const amountValue = canonical_AMOUNT(); - auto const otherChainDestinationValue = canonical_ACCOUNT(); - - XChainCommitBuilder builder{ - accountValue, - xChainBridgeValue, - xChainClaimIDValue, - amountValue, - sequenceValue, - feeValue - }; - - // Set optional fields - builder.setOtherChainDestination(otherChainDestinationValue); - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = tx.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - { - auto const& expected = amountValue; - auto const actual = tx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - // Verify optional fields - { - auto const& expected = otherChainDestinationValue; - auto const actualOpt = tx.getOtherChainDestination(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOtherChainDestination should be present"; - expectEqualField(expected, *actualOpt, "sfOtherChainDestination"); - EXPECT_TRUE(tx.hasOtherChainDestination()); - } - -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainCommitTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCommitFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const amountValue = canonical_AMOUNT(); - auto const otherChainDestinationValue = canonical_ACCOUNT(); - - // Build an initial transaction - XChainCommitBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - xChainClaimIDValue, - amountValue, - sequenceValue, - feeValue - }; - - initialBuilder.setOtherChainDestination(otherChainDestinationValue); - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainCommitBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = xChainClaimIDValue; - auto const actual = rebuiltTx.getXChainClaimID(); - expectEqualField(expected, actual, "sfXChainClaimID"); - } - - { - auto const& expected = amountValue; - auto const actual = rebuiltTx.getAmount(); - expectEqualField(expected, actual, "sfAmount"); - } - - // Verify optional fields - { - auto const& expected = otherChainDestinationValue; - auto const actualOpt = rebuiltTx.getOtherChainDestination(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOtherChainDestination should be present"; - expectEqualField(expected, *actualOpt, "sfOtherChainDestination"); - } - -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainCommitTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainCommit{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainCommitTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainCommitBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - -// 5) Build with only required fields and verify optional fields return nullopt. -TEST(TransactionsXChainCommitTests, OptionalFieldsReturnNullopt) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCommitNullopt")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 3; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific required field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const xChainClaimIDValue = canonical_UINT64(); - auto const amountValue = canonical_AMOUNT(); - - XChainCommitBuilder builder{ - accountValue, - xChainBridgeValue, - xChainClaimIDValue, - amountValue, - sequenceValue, - feeValue - }; - - // Do NOT set optional fields - - auto tx = builder.build(publicKey, secretKey); - - // Verify optional fields are not present - EXPECT_FALSE(tx.hasOtherChainDestination()); - EXPECT_FALSE(tx.getOtherChainDestination().has_value()); -} - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateBridgeTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateBridgeTests.cpp deleted file mode 100644 index 7b06c4f52f..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateBridgeTests.cpp +++ /dev/null @@ -1,213 +0,0 @@ -// Auto-generated unit tests for transaction XChainCreateBridge - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainCreateBridgeTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCreateBridge")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const minAccountCreateAmountValue = canonical_AMOUNT(); - - XChainCreateBridgeBuilder builder{ - accountValue, - xChainBridgeValue, - signatureRewardValue, - sequenceValue, - feeValue - }; - - // Set optional fields - builder.setMinAccountCreateAmount(minAccountCreateAmountValue); - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = tx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - // Verify optional fields - { - auto const& expected = minAccountCreateAmountValue; - auto const actualOpt = tx.getMinAccountCreateAmount(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; - expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); - EXPECT_TRUE(tx.hasMinAccountCreateAmount()); - } - -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainCreateBridgeTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCreateBridgeFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const minAccountCreateAmountValue = canonical_AMOUNT(); - - // Build an initial transaction - XChainCreateBridgeBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - signatureRewardValue, - sequenceValue, - feeValue - }; - - initialBuilder.setMinAccountCreateAmount(minAccountCreateAmountValue); - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainCreateBridgeBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = rebuiltTx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - // Verify optional fields - { - auto const& expected = minAccountCreateAmountValue; - auto const actualOpt = rebuiltTx.getMinAccountCreateAmount(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; - expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); - } - -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainCreateBridgeTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainCreateBridge{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainCreateBridgeTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainCreateBridgeBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - -// 5) Build with only required fields and verify optional fields return nullopt. -TEST(TransactionsXChainCreateBridgeTests, OptionalFieldsReturnNullopt) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCreateBridgeNullopt")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 3; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific required field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const signatureRewardValue = canonical_AMOUNT(); - - XChainCreateBridgeBuilder builder{ - accountValue, - xChainBridgeValue, - signatureRewardValue, - sequenceValue, - feeValue - }; - - // Do NOT set optional fields - - auto tx = builder.build(publicKey, secretKey); - - // Verify optional fields are not present - EXPECT_FALSE(tx.hasMinAccountCreateAmount()); - EXPECT_FALSE(tx.getMinAccountCreateAmount().has_value()); -} - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateClaimIDTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateClaimIDTests.cpp deleted file mode 100644 index 814785bc4e..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateClaimIDTests.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Auto-generated unit tests for transaction XChainCreateClaimID - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainCreateClaimIDTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCreateClaimID")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - - XChainCreateClaimIDBuilder builder{ - accountValue, - xChainBridgeValue, - signatureRewardValue, - otherChainSourceValue, - sequenceValue, - feeValue - }; - - // Set optional fields - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = tx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - { - auto const& expected = otherChainSourceValue; - auto const actual = tx.getOtherChainSource(); - expectEqualField(expected, actual, "sfOtherChainSource"); - } - - // Verify optional fields -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainCreateClaimIDTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainCreateClaimIDFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const otherChainSourceValue = canonical_ACCOUNT(); - - // Build an initial transaction - XChainCreateClaimIDBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - signatureRewardValue, - otherChainSourceValue, - sequenceValue, - feeValue - }; - - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainCreateClaimIDBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - { - auto const& expected = signatureRewardValue; - auto const actual = rebuiltTx.getSignatureReward(); - expectEqualField(expected, actual, "sfSignatureReward"); - } - - { - auto const& expected = otherChainSourceValue; - auto const actual = rebuiltTx.getOtherChainSource(); - expectEqualField(expected, actual, "sfOtherChainSource"); - } - - // Verify optional fields -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainCreateClaimIDTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainCreateClaimID{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainCreateClaimIDTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainCreateClaimIDBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - - -} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainModifyBridgeTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainModifyBridgeTests.cpp deleted file mode 100644 index da854976b9..0000000000 --- a/src/tests/libxrpl/protocol_autogen/transactions/XChainModifyBridgeTests.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// Auto-generated unit tests for transaction XChainModifyBridge - - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -namespace xrpl::transactions { - -// 1 & 4) Set fields via builder setters, build, then read them back via -// wrapper getters. After build(), validate() should succeed. -TEST(TransactionsXChainModifyBridgeTests, BuilderSettersRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainModifyBridge")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 1; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const minAccountCreateAmountValue = canonical_AMOUNT(); - - XChainModifyBridgeBuilder builder{ - accountValue, - xChainBridgeValue, - sequenceValue, - feeValue - }; - - // Set optional fields - builder.setSignatureReward(signatureRewardValue); - builder.setMinAccountCreateAmount(minAccountCreateAmountValue); - - auto tx = builder.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(tx.validate(reason)) << reason; - - // Verify signing was applied - EXPECT_FALSE(tx.getSigningPubKey().empty()); - EXPECT_TRUE(tx.hasTxnSignature()); - - // Verify common fields - EXPECT_EQ(tx.getAccount(), accountValue); - EXPECT_EQ(tx.getSequence(), sequenceValue); - EXPECT_EQ(tx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = tx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - // Verify optional fields - { - auto const& expected = signatureRewardValue; - auto const actualOpt = tx.getSignatureReward(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignatureReward should be present"; - expectEqualField(expected, *actualOpt, "sfSignatureReward"); - EXPECT_TRUE(tx.hasSignatureReward()); - } - - { - auto const& expected = minAccountCreateAmountValue; - auto const actualOpt = tx.getMinAccountCreateAmount(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; - expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); - EXPECT_TRUE(tx.hasMinAccountCreateAmount()); - } - -} - -// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, -// and verify all fields match. -TEST(TransactionsXChainModifyBridgeTests, BuilderFromStTxRoundTrip) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainModifyBridgeFromTx")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 2; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - auto const signatureRewardValue = canonical_AMOUNT(); - auto const minAccountCreateAmountValue = canonical_AMOUNT(); - - // Build an initial transaction - XChainModifyBridgeBuilder initialBuilder{ - accountValue, - xChainBridgeValue, - sequenceValue, - feeValue - }; - - initialBuilder.setSignatureReward(signatureRewardValue); - initialBuilder.setMinAccountCreateAmount(minAccountCreateAmountValue); - - auto initialTx = initialBuilder.build(publicKey, secretKey); - - // Create builder from existing STTx - XChainModifyBridgeBuilder builderFromTx{initialTx.getSTTx()}; - - auto rebuiltTx = builderFromTx.build(publicKey, secretKey); - - std::string reason; - EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; - - // Verify common fields - EXPECT_EQ(rebuiltTx.getAccount(), accountValue); - EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); - EXPECT_EQ(rebuiltTx.getFee(), feeValue); - - // Verify required fields - { - auto const& expected = xChainBridgeValue; - auto const actual = rebuiltTx.getXChainBridge(); - expectEqualField(expected, actual, "sfXChainBridge"); - } - - // Verify optional fields - { - auto const& expected = signatureRewardValue; - auto const actualOpt = rebuiltTx.getSignatureReward(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignatureReward should be present"; - expectEqualField(expected, *actualOpt, "sfSignatureReward"); - } - - { - auto const& expected = minAccountCreateAmountValue; - auto const actualOpt = rebuiltTx.getMinAccountCreateAmount(); - ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; - expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); - } - -} - -// 3) Verify wrapper throws when constructed from wrong transaction type. -TEST(TransactionsXChainModifyBridgeTests, WrapperThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainModifyBridge{wrongTx.getSTTx()}, std::runtime_error); -} - -// 4) Verify builder throws when constructed from wrong transaction type. -TEST(TransactionsXChainModifyBridgeTests, BuilderThrowsOnWrongTxType) -{ - // Build a valid transaction of a different type - auto const [pk, sk] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder")); - auto const account = calcAccountID(pk); - - AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; - auto wrongTx = wrongBuilder.build(pk, sk); - - EXPECT_THROW(XChainModifyBridgeBuilder{wrongTx.getSTTx()}, std::runtime_error); -} - -// 5) Build with only required fields and verify optional fields return nullopt. -TEST(TransactionsXChainModifyBridgeTests, OptionalFieldsReturnNullopt) -{ - // Generate a deterministic keypair for signing - auto const [publicKey, secretKey] = - generateKeyPair(KeyType::Secp256k1, generateSeed("testXChainModifyBridgeNullopt")); - - // Common transaction fields - auto const accountValue = calcAccountID(publicKey); - std::uint32_t const sequenceValue = 3; - auto const feeValue = canonical_AMOUNT(); - - // Transaction-specific required field values - auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); - - XChainModifyBridgeBuilder builder{ - accountValue, - xChainBridgeValue, - sequenceValue, - feeValue - }; - - // Do NOT set optional fields - - auto tx = builder.build(publicKey, secretKey); - - // Verify optional fields are not present - EXPECT_FALSE(tx.hasSignatureReward()); - EXPECT_FALSE(tx.getSignatureReward().has_value()); - EXPECT_FALSE(tx.hasMinAccountCreateAmount()); - EXPECT_FALSE(tx.getMinAccountCreateAmount().has_value()); -} - -} diff --git a/src/xrpld/rpc/handlers/account/AccountObjects.cpp b/src/xrpld/rpc/handlers/account/AccountObjects.cpp index 8967509262..00712bf211 100644 --- a/src/xrpld/rpc/handlers/account/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/account/AccountObjects.cpp @@ -296,10 +296,6 @@ doAccountObjects(RPC::JsonContext& context) {.name = jss::nft_page, .type = ltNFTOKEN_PAGE}, {.name = jss::payment_channel, .type = ltPAYCHAN}, {.name = jss::state, .type = ltRIPPLE_STATE}, - {.name = jss::xchain_owned_claim_id, .type = ltXCHAIN_OWNED_CLAIM_ID}, - {.name = jss::xchain_owned_create_account_claim_id, - .type = ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, - {.name = jss::bridge, .type = ltBRIDGE}, {.name = jss::mpt_issuance, .type = ltMPTOKEN_ISSUANCE}, {.name = jss::mptoken, .type = ltMPTOKEN}, {.name = jss::permissioned_domain, .type = ltPERMISSIONED_DOMAIN}, diff --git a/src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp b/src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp index 784be779bb..148a42baaa 100644 --- a/src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/ledger/LedgerEntry.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -139,39 +138,6 @@ parseAMM( return keylet::amm(*asset, *asset2).key; } -static std::expected -parseBridge( - json::Value const& params, - json::StaticString const fieldName, - [[maybe_unused]] unsigned const apiVersion) -{ - if (!params.isMember(jss::bridge)) - { - return std::unexpected(LedgerEntryHelpers::missingFieldError(jss::bridge)); - } - - if (params[jss::bridge].isString()) - { - return parseObjectID(params, fieldName); - } - - auto const bridge = LedgerEntryHelpers::parseBridgeFields(params[jss::bridge]); - if (!bridge) - return std::unexpected(bridge.error()); - - auto const account = LedgerEntryHelpers::requiredAccountID( - params, jss::bridge_account, "malformedBridgeAccount"); - if (!account) - return std::unexpected(account.error()); - - STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(account.value() == bridge->lockingChainDoor()); - if (account.value() != bridge->door(chainType)) - return LedgerEntryHelpers::malformedError("malformedRequest", ""); - - return keylet::bridge(*bridge, chainType).key; -} - static std::expected parseCheck( json::Value const& params, @@ -786,60 +752,6 @@ parseVault( return keylet::vault(*id, *seq).key; } -static std::expected -parseXChainOwnedClaimID( - json::Value const& claimId, - json::StaticString const fieldName, - [[maybe_unused]] unsigned const apiVersion) -{ - if (!claimId.isObject()) - { - return parseObjectID(claimId, fieldName); - } - - auto const bridgeSpec = LedgerEntryHelpers::parseBridgeFields(claimId); - if (!bridgeSpec) - return std::unexpected(bridgeSpec.error()); - - auto const seq = LedgerEntryHelpers::requiredUInt32( - claimId, jss::xchain_owned_claim_id, "malformedXChainOwnedClaimID"); - if (!seq) - { - return std::unexpected(seq.error()); - } - - Keylet const keylet = keylet::xChainClaimID(*bridgeSpec, *seq); - return keylet.key; -} - -static std::expected -parseXChainOwnedCreateAccountClaimID( - json::Value const& claimId, - json::StaticString const fieldName, - [[maybe_unused]] unsigned const apiVersion) -{ - if (!claimId.isObject()) - { - return parseObjectID(claimId, fieldName); - } - - auto const bridgeSpec = LedgerEntryHelpers::parseBridgeFields(claimId); - if (!bridgeSpec) - return std::unexpected(bridgeSpec.error()); - - auto const seq = LedgerEntryHelpers::requiredUInt32( - claimId, - jss::xchain_owned_create_account_claim_id, - "malformedXChainOwnedCreateAccountClaimID"); - if (!seq) - { - return std::unexpected(seq.error()); - } - - Keylet const keylet = keylet::xChainCreateAccountClaimID(*bridgeSpec, *seq); - return keylet.key; -} - struct LedgerEntry { json::StaticString fieldName; @@ -912,15 +824,10 @@ doLedgerEntry(RPC::JsonContext& context) if (context.params.isMember(ledgerEntry.fieldName)) { expectedType = ledgerEntry.expectedType; - // `Bridge` is the only type that involves two fields at the - // `ledger_entry` param level. - // So that parser needs to have the whole `params` field. - // All other parsers only need the one field name's info. - json::Value const& params = ledgerEntry.fieldName == jss::bridge - ? context.params - : context.params[ledgerEntry.fieldName]; - auto const result = - ledgerEntry.parseFunction(params, ledgerEntry.fieldName, context.apiVersion); + auto const result = ledgerEntry.parseFunction( + context.params[ledgerEntry.fieldName], + ledgerEntry.fieldName, + context.apiVersion); if (!result) return result.error(); diff --git a/src/xrpld/rpc/handlers/ledger/LedgerEntryHelpers.h b/src/xrpld/rpc/handlers/ledger/LedgerEntryHelpers.h index 57c4e58242..9a779753bc 100644 --- a/src/xrpld/rpc/handlers/ledger/LedgerEntryHelpers.h +++ b/src/xrpld/rpc/handlers/ledger/LedgerEntryHelpers.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -239,56 +238,4 @@ requiredAsset(json::Value const& params, json::StaticString const fieldName, std return required(params, fieldName, err, "Asset"); } -inline std::expected -parseBridgeFields(json::Value const& params) -{ - if (auto const value = hasRequired( - params, - {jss::LockingChainDoor, - jss::LockingChainIssue, - jss::IssuingChainDoor, - jss::IssuingChainIssue}); - !value) - { - return std::unexpected(value.error()); - } - - auto const lockingChainDoor = - requiredAccountID(params, jss::LockingChainDoor, "malformedLockingChainDoor"); - if (!lockingChainDoor) - { - return std::unexpected(lockingChainDoor.error()); - } - - auto const issuingChainDoor = - requiredAccountID(params, jss::IssuingChainDoor, "malformedIssuingChainDoor"); - if (!issuingChainDoor) - { - return std::unexpected(issuingChainDoor.error()); - } - - Issue lockingChainIssue; - try - { - lockingChainIssue = issueFromJson(params[jss::LockingChainIssue]); - } - catch (std::runtime_error const& ex) - { - return invalidFieldError("malformedIssue", jss::LockingChainIssue, "Issue"); - } - - Issue issuingChainIssue; - try - { - issuingChainIssue = issueFromJson(params[jss::IssuingChainIssue]); - } - catch (std::runtime_error const& ex) - { - return invalidFieldError("malformedIssue", jss::IssuingChainIssue, "Issue"); - } - - return STXChainBridge( - *lockingChainDoor, lockingChainIssue, *issuingChainDoor, issuingChainIssue); -} - } // namespace xrpl::LedgerEntryHelpers diff --git a/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp b/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp index 1e9e0ddc14..5adadbad48 100644 --- a/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp +++ b/src/xrpld/rpc/handlers/server_info/ServerDefinitions.cpp @@ -86,7 +86,6 @@ ServerDefinitions::translate(std::string const& inp) {"NOTPRESENT", "NotPresent"}, {"PATHSET", "PathSet"}, {"VL", "Blob"}, - {"XCHAIN_BRIDGE", "XChainBridge"}, }; if (auto const& it = kReplacements.find(inp); it != kReplacements.end())