mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-05 17:56:49 +00:00
Compare commits
25 Commits
release/3.
...
mvadari/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
646b3aa269 | ||
|
|
4dc61deeb4 | ||
|
|
e2103b1bef | ||
|
|
9dfb0cf981 | ||
|
|
84908d56c1 | ||
|
|
076d923cc1 | ||
|
|
fd86ca9205 | ||
|
|
effec43851 | ||
|
|
08d5e1f6db | ||
|
|
ceba7c6e34 | ||
|
|
18994a31b1 | ||
|
|
0a671b7d0b | ||
|
|
9cf2c0c3ae | ||
|
|
bf68edb541 | ||
|
|
67a199fcb5 | ||
|
|
02fba4c998 | ||
|
|
1e51b61747 | ||
|
|
7b9a98692d | ||
|
|
98ed477ca7 | ||
|
|
654734dcf9 | ||
|
|
d5ca8ef77d | ||
|
|
7de9560048 | ||
|
|
568623f699 | ||
|
|
cf33298abd | ||
|
|
b46ca16f7d |
@@ -27,6 +27,13 @@ enum SOEStyle {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||||
enum SOETxMPTIssue { SoeMptNone, SoeMptSupported, SoeMptNotSupported };
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||||
enum SOEMutability {
|
||||
SoeImmutable,
|
||||
SoeMutable,
|
||||
SoeImmutableSetOnce,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** An element in a SOTemplate. */
|
||||
@@ -35,6 +42,7 @@ class SOElement
|
||||
// Use std::reference_wrapper so SOElement can be stored in a std::vector.
|
||||
std::reference_wrapper<SField const> sField_;
|
||||
SOEStyle style_;
|
||||
SOEMutability mutability_ = SoeImmutable;
|
||||
SOETxMPTIssue supportMpt_ = SoeMptNone;
|
||||
|
||||
private:
|
||||
@@ -48,6 +56,14 @@ private:
|
||||
nm += ": '" + fieldName.getName() + "'";
|
||||
Throw<std::runtime_error>("SField (" + nm + ") in SOElement must be useful.");
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
mutability_ != SoeImmutableSetOnce || style_ == SoeOptional,
|
||||
"xrpl::SOElement::init : set-once fields must be optional");
|
||||
XRPL_ASSERT(
|
||||
mutability_ != SoeMutable || style_ == SoeRequired || style_ == SoeOptional ||
|
||||
style_ == SoeDefault,
|
||||
"xrpl::SOElement::init : mutable fields must have a valid style");
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -56,6 +72,12 @@ public:
|
||||
init(fieldName);
|
||||
}
|
||||
|
||||
SOElement(SField const& fieldName, SOEStyle style, SOEMutability mutability)
|
||||
: sField_(fieldName), style_(style), mutability_(mutability)
|
||||
{
|
||||
init(fieldName);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_same_v<T, STAmount> || std::is_same_v<T, STIssue>)
|
||||
SOElement(
|
||||
@@ -67,6 +89,18 @@ public:
|
||||
init(fieldName);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(std::is_same_v<T, STAmount> || std::is_same_v<T, STIssue>)
|
||||
SOElement(
|
||||
TypedField<T> const& fieldName,
|
||||
SOEStyle style,
|
||||
SOEMutability mutability,
|
||||
SOETxMPTIssue supportMpt = SoeMptNotSupported)
|
||||
: sField_(fieldName), style_(style), mutability_(mutability), supportMpt_(supportMpt)
|
||||
{
|
||||
init(fieldName);
|
||||
}
|
||||
|
||||
[[nodiscard]] SField const&
|
||||
sField() const
|
||||
{
|
||||
@@ -79,6 +113,12 @@ public:
|
||||
return style_;
|
||||
}
|
||||
|
||||
[[nodiscard]] SOEMutability
|
||||
mutability() const
|
||||
{
|
||||
return mutability_;
|
||||
}
|
||||
|
||||
[[nodiscard]] SOETxMPTIssue
|
||||
supportMPT() const
|
||||
{
|
||||
|
||||
@@ -587,7 +587,7 @@ public:
|
||||
|
||||
/** Returns `true` if the field is set.
|
||||
|
||||
Fields with soeDEFAULT and set to the
|
||||
Fields with SoeDefault and set to the
|
||||
default value will return `true`
|
||||
*/
|
||||
explicit
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FIX (ImmutableInvariant, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_2_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(MPTokensV2, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_1_3, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
|
||||
@@ -24,15 +24,15 @@
|
||||
\sa keylet::nftoffer
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_OFFER, 0x0037, NFTokenOffer, nft_offer, ({
|
||||
{sfOwner, SoeRequired},
|
||||
{sfNFTokenID, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfNFTokenOfferNode, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
{sfExpiration, SoeOptional},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfOwner, SoeRequired, SoeImmutable},
|
||||
{sfNFTokenID, SoeRequired, SoeImmutable},
|
||||
{sfAmount, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfNFTokenOfferNode, SoeRequired, SoeImmutable},
|
||||
{sfDestination, SoeOptional, SoeImmutable},
|
||||
{sfExpiration, SoeOptional, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes a check.
|
||||
@@ -40,18 +40,18 @@ LEDGER_ENTRY(ltNFTOKEN_OFFER, 0x0037, NFTokenOffer, nft_offer, ({
|
||||
\sa keylet::check
|
||||
*/
|
||||
LEDGER_ENTRY(ltCHECK, 0x0043, Check, check, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSendMax, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfDestinationNode, SoeRequired},
|
||||
{sfExpiration, SoeOptional},
|
||||
{sfInvoiceID, SoeOptional},
|
||||
{sfSourceTag, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfDestination, SoeRequired, SoeImmutable},
|
||||
{sfSendMax, SoeRequired, SoeImmutable},
|
||||
{sfSequence, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfDestinationNode, SoeRequired, SoeImmutable},
|
||||
{sfExpiration, SoeOptional, SoeImmutable},
|
||||
{sfInvoiceID, SoeOptional, SoeImmutable},
|
||||
{sfSourceTag, SoeOptional, SoeImmutable},
|
||||
{sfDestinationTag, SoeOptional, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** The ledger object which tracks the DID.
|
||||
@@ -59,13 +59,13 @@ LEDGER_ENTRY(ltCHECK, 0x0043, Check, check, ({
|
||||
\sa keylet::did
|
||||
*/
|
||||
LEDGER_ENTRY(ltDID, 0x0049, DID, did, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfDIDDocument, SoeOptional},
|
||||
{sfURI, SoeOptional},
|
||||
{sfData, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfDIDDocument, SoeOptional, SoeMutable},
|
||||
{sfURI, SoeOptional, SoeMutable},
|
||||
{sfData, SoeOptional, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** The ledger object which tracks the current negative UNL state.
|
||||
@@ -75,11 +75,11 @@ LEDGER_ENTRY(ltDID, 0x0049, DID, did, ({
|
||||
\sa keylet::negativeUNL
|
||||
*/
|
||||
LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, nunl, ({
|
||||
{sfDisabledValidators, SoeOptional},
|
||||
{sfValidatorToDisable, SoeOptional},
|
||||
{sfValidatorToReEnable, SoeOptional},
|
||||
{sfPreviousTxnID, SoeOptional},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
{sfDisabledValidators, SoeOptional, SoeMutable},
|
||||
{sfValidatorToDisable, SoeOptional, SoeMutable},
|
||||
{sfValidatorToReEnable, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnID, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which contains a list of NFTs
|
||||
@@ -87,11 +87,11 @@ LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, nunl, ({
|
||||
\sa keylet::nftpageMin, keylet::nftpageMax, keylet::nftpage
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
{sfPreviousPageMin, SoeOptional},
|
||||
{sfNextPageMin, SoeOptional},
|
||||
{sfNFTokens, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfPreviousPageMin, SoeOptional, SoeMutable},
|
||||
{sfNextPageMin, SoeOptional, SoeMutable},
|
||||
{sfNFTokens, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which contains a signer list for an account.
|
||||
@@ -101,13 +101,13 @@ LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
// All fields are SoeRequired because there is always a SignerEntries.
|
||||
// If there are no SignerEntries the node is deleted.
|
||||
LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, signer_list, ({
|
||||
{sfOwner, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfSignerQuorum, SoeRequired},
|
||||
{sfSignerEntries, SoeRequired},
|
||||
{sfSignerListID, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfOwner, SoeOptional, SoeImmutableSetOnce},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfSignerQuorum, SoeRequired, SoeMutable},
|
||||
{sfSignerEntries, SoeRequired, SoeMutable},
|
||||
{sfSignerListID, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes a ticket.
|
||||
@@ -115,11 +115,11 @@ LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, signer_list, ({
|
||||
\sa keylet::kTicket
|
||||
*/
|
||||
LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfTicketSequence, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfTicketSequence, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes an account.
|
||||
@@ -127,29 +127,29 @@ LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, ({
|
||||
\sa keylet::account
|
||||
*/
|
||||
LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfBalance, SoeRequired},
|
||||
{sfOwnerCount, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccountTxnID, SoeOptional},
|
||||
{sfRegularKey, SoeOptional},
|
||||
{sfEmailHash, SoeOptional},
|
||||
{sfWalletLocator, SoeOptional},
|
||||
{sfWalletSize, SoeOptional},
|
||||
{sfMessageKey, SoeOptional},
|
||||
{sfTransferRate, SoeOptional},
|
||||
{sfDomain, SoeOptional},
|
||||
{sfTickSize, SoeOptional},
|
||||
{sfTicketCount, SoeOptional},
|
||||
{sfNFTokenMinter, SoeOptional},
|
||||
{sfMintedNFTokens, SoeDefault},
|
||||
{sfBurnedNFTokens, SoeDefault},
|
||||
{sfFirstNFTokenSequence, SoeOptional},
|
||||
{sfAMMID, SoeOptional}, // pseudo-account designator
|
||||
{sfVaultID, SoeOptional}, // pseudo-account designator
|
||||
{sfLoanBrokerID, SoeOptional}, // pseudo-account designator
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfSequence, SoeRequired, SoeMutable},
|
||||
{sfBalance, SoeRequired, SoeMutable},
|
||||
{sfOwnerCount, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfAccountTxnID, SoeOptional, SoeMutable},
|
||||
{sfRegularKey, SoeOptional, SoeMutable},
|
||||
{sfEmailHash, SoeOptional, SoeMutable},
|
||||
{sfWalletLocator, SoeOptional, SoeMutable},
|
||||
{sfWalletSize, SoeOptional, SoeMutable},
|
||||
{sfMessageKey, SoeOptional, SoeMutable},
|
||||
{sfTransferRate, SoeOptional, SoeMutable},
|
||||
{sfDomain, SoeOptional, SoeMutable},
|
||||
{sfTickSize, SoeOptional, SoeMutable},
|
||||
{sfTicketCount, SoeOptional, SoeMutable},
|
||||
{sfNFTokenMinter, SoeOptional, SoeMutable},
|
||||
{sfMintedNFTokens, SoeDefault, SoeMutable},
|
||||
{sfBurnedNFTokens, SoeDefault, SoeMutable},
|
||||
{sfFirstNFTokenSequence, SoeOptional, SoeImmutableSetOnce},
|
||||
{sfAMMID, SoeOptional, SoeImmutable}, // pseudo-account designator
|
||||
{sfVaultID, SoeOptional, SoeImmutable}, // pseudo-account designator
|
||||
{sfLoanBrokerID, SoeOptional, SoeImmutable}, // pseudo-account designator
|
||||
}))
|
||||
|
||||
/** A ledger object which contains a list of object identifiers.
|
||||
@@ -158,22 +158,22 @@ LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
|
||||
keylet::ownerDir
|
||||
*/
|
||||
LEDGER_ENTRY(ltDIR_NODE, 0x0064, DirectoryNode, directory, ({
|
||||
{sfOwner, SoeOptional}, // for owner directories
|
||||
{sfTakerPaysCurrency, SoeOptional}, // order book directories
|
||||
{sfTakerPaysIssuer, SoeOptional}, // order book directories
|
||||
{sfTakerPaysMPT, SoeOptional}, // order book directories
|
||||
{sfTakerGetsCurrency, SoeOptional}, // order book directories
|
||||
{sfTakerGetsIssuer, SoeOptional}, // order book directories
|
||||
{sfTakerGetsMPT, SoeOptional}, // order book directories
|
||||
{sfExchangeRate, SoeOptional}, // order book directories
|
||||
{sfIndexes, SoeRequired},
|
||||
{sfRootIndex, SoeRequired},
|
||||
{sfIndexNext, SoeOptional},
|
||||
{sfIndexPrevious, SoeOptional},
|
||||
{sfNFTokenID, SoeOptional},
|
||||
{sfPreviousTxnID, SoeOptional},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
{sfDomainID, SoeOptional} // order book directories
|
||||
{sfOwner, SoeOptional, SoeImmutable}, // for owner directories
|
||||
{sfTakerPaysCurrency, SoeOptional, SoeImmutable}, // order book directories
|
||||
{sfTakerPaysIssuer, SoeOptional, SoeImmutable}, // order book directories
|
||||
{sfTakerPaysMPT, SoeOptional, SoeImmutable}, // order book directories
|
||||
{sfTakerGetsCurrency, SoeOptional, SoeImmutable}, // order book directories
|
||||
{sfTakerGetsIssuer, SoeOptional, SoeImmutable}, // order book directories
|
||||
{sfTakerGetsMPT, SoeOptional, SoeImmutable}, // order book directories
|
||||
{sfExchangeRate, SoeOptional, SoeImmutable}, // order book directories
|
||||
{sfIndexes, SoeRequired, SoeMutable},
|
||||
{sfRootIndex, SoeRequired, SoeImmutable},
|
||||
{sfIndexNext, SoeOptional, SoeMutable},
|
||||
{sfIndexPrevious, SoeOptional, SoeMutable},
|
||||
{sfNFTokenID, SoeOptional, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional, SoeMutable},
|
||||
{sfDomainID, SoeOptional, SoeImmutable}, // order book directories
|
||||
}))
|
||||
|
||||
/** The ledger object which lists details about amendments on the network.
|
||||
@@ -183,10 +183,10 @@ LEDGER_ENTRY(ltDIR_NODE, 0x0064, DirectoryNode, directory, ({
|
||||
\sa keylet::amendments
|
||||
*/
|
||||
LEDGER_ENTRY(ltAMENDMENTS, 0x0066, Amendments, amendments, ({
|
||||
{sfAmendments, SoeOptional}, // Enabled
|
||||
{sfMajorities, SoeOptional},
|
||||
{sfPreviousTxnID, SoeOptional},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
{sfAmendments, SoeOptional, SoeMutable}, // Enabled
|
||||
{sfMajorities, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnID, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object that contains a list of ledger hashes.
|
||||
@@ -198,9 +198,9 @@ LEDGER_ENTRY(ltAMENDMENTS, 0x0066, Amendments, amendments, ({
|
||||
\sa keylet::skip
|
||||
*/
|
||||
LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, hashes, ({
|
||||
{sfFirstLedgerSequence, SoeOptional},
|
||||
{sfLastLedgerSequence, SoeOptional},
|
||||
{sfHashes, SoeRequired},
|
||||
{sfFirstLedgerSequence, SoeOptional, SoeImmutable},
|
||||
{sfLastLedgerSequence, SoeOptional, SoeMutable},
|
||||
{sfHashes, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** The ledger object which lists details about sidechains.
|
||||
@@ -208,16 +208,16 @@ LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, hashes, ({
|
||||
\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},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfSignatureReward, SoeRequired, SoeMutable},
|
||||
{sfMinAccountCreateAmount, SoeOptional, SoeMutable},
|
||||
{sfXChainBridge, SoeRequired, SoeImmutable},
|
||||
{sfXChainClaimID, SoeRequired, SoeMutable},
|
||||
{sfXChainAccountCreateCount, SoeRequired, SoeMutable},
|
||||
{sfXChainAccountClaimCount, SoeRequired, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes an offer on the DEX.
|
||||
@@ -225,18 +225,18 @@ LEDGER_ENTRY(ltBRIDGE, 0x0069, Bridge, bridge, ({
|
||||
\sa keylet::offer
|
||||
*/
|
||||
LEDGER_ENTRY(ltOFFER, 0x006f, Offer, offer, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfTakerPays, SoeRequired},
|
||||
{sfTakerGets, SoeRequired},
|
||||
{sfBookDirectory, SoeRequired},
|
||||
{sfBookNode, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfExpiration, SoeOptional},
|
||||
{sfDomainID, SoeOptional},
|
||||
{sfAdditionalBooks, SoeOptional},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfSequence, SoeRequired, SoeImmutable},
|
||||
{sfTakerPays, SoeRequired, SoeMutable},
|
||||
{sfTakerGets, SoeRequired, SoeMutable},
|
||||
{sfBookDirectory, SoeRequired, SoeImmutable},
|
||||
{sfBookNode, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfExpiration, SoeOptional, SoeImmutable},
|
||||
{sfDomainID, SoeOptional, SoeImmutable},
|
||||
{sfAdditionalBooks, SoeOptional, SoeImmutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes a deposit pre-authorization.
|
||||
@@ -244,12 +244,12 @@ LEDGER_ENTRY(ltOFFER, 0x006f, Offer, offer, ({
|
||||
\sa keylet::depositPreauth
|
||||
*/
|
||||
LEDGER_ENTRY_DUPLICATE(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, deposit_preauth, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAuthorize, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAuthorizeCredentials, SoeOptional},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfAuthorize, SoeOptional, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfAuthorizeCredentials, SoeOptional, SoeImmutable},
|
||||
}))
|
||||
|
||||
/** A claim id for a cross chain transaction.
|
||||
@@ -257,15 +257,15 @@ LEDGER_ENTRY_DUPLICATE(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, deposit_preaut
|
||||
\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},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfXChainBridge, SoeRequired, SoeImmutable},
|
||||
{sfXChainClaimID, SoeRequired, SoeImmutable},
|
||||
{sfOtherChainSource, SoeRequired, SoeImmutable},
|
||||
{sfXChainClaimAttestations, SoeRequired, SoeMutable},
|
||||
{sfSignatureReward, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes a bidirectional trust line.
|
||||
@@ -275,17 +275,17 @@ LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_c
|
||||
\sa keylet::line
|
||||
*/
|
||||
LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
{sfBalance, SoeRequired},
|
||||
{sfLowLimit, SoeRequired},
|
||||
{sfHighLimit, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfLowNode, SoeOptional},
|
||||
{sfLowQualityIn, SoeOptional},
|
||||
{sfLowQualityOut, SoeOptional},
|
||||
{sfHighNode, SoeOptional},
|
||||
{sfHighQualityIn, SoeOptional},
|
||||
{sfHighQualityOut, SoeOptional},
|
||||
{sfBalance, SoeRequired, SoeMutable},
|
||||
{sfLowLimit, SoeRequired, SoeMutable},
|
||||
{sfHighLimit, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfLowNode, SoeOptional, SoeImmutable},
|
||||
{sfLowQualityIn, SoeOptional, SoeMutable},
|
||||
{sfLowQualityOut, SoeOptional, SoeMutable},
|
||||
{sfHighNode, SoeOptional, SoeImmutable},
|
||||
{sfHighQualityIn, SoeOptional, SoeMutable},
|
||||
{sfHighQualityOut, SoeOptional, SoeMutable},
|
||||
}))
|
||||
|
||||
/** The ledger object which lists the network's fee settings.
|
||||
@@ -296,16 +296,16 @@ LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
*/
|
||||
LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
// Old version uses raw numbers
|
||||
{sfBaseFee, SoeOptional},
|
||||
{sfReferenceFeeUnits, SoeOptional},
|
||||
{sfReserveBase, SoeOptional},
|
||||
{sfReserveIncrement, SoeOptional},
|
||||
{sfBaseFee, SoeOptional, SoeMutable},
|
||||
{sfReferenceFeeUnits, SoeOptional, SoeMutable},
|
||||
{sfReserveBase, SoeOptional, SoeMutable},
|
||||
{sfReserveIncrement, SoeOptional, SoeMutable},
|
||||
// New version uses Amounts
|
||||
{sfBaseFeeDrops, SoeOptional},
|
||||
{sfReserveBaseDrops, SoeOptional},
|
||||
{sfReserveIncrementDrops, SoeOptional},
|
||||
{sfPreviousTxnID, SoeOptional},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
{sfBaseFeeDrops, SoeOptional, SoeMutable},
|
||||
{sfReserveBaseDrops, SoeOptional, SoeMutable},
|
||||
{sfReserveIncrementDrops, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnID, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A claim id for a cross chain create account transaction.
|
||||
@@ -313,13 +313,13 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
\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},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfXChainBridge, SoeRequired, SoeImmutable},
|
||||
{sfXChainAccountCreateCount, SoeRequired, SoeImmutable},
|
||||
{sfXChainCreateAccountAttestations, SoeRequired, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object describing a single escrow.
|
||||
@@ -327,21 +327,21 @@ LEDGER_ENTRY(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, 0x0074, XChainOwnedCreateAc
|
||||
\sa keylet::escrow
|
||||
*/
|
||||
LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSequence, SoeOptional},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfCondition, SoeOptional},
|
||||
{sfCancelAfter, SoeOptional},
|
||||
{sfFinishAfter, SoeOptional},
|
||||
{sfSourceTag, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfDestinationNode, SoeOptional},
|
||||
{sfTransferRate, SoeOptional},
|
||||
{sfIssuerNode, SoeOptional},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfSequence, SoeOptional, SoeImmutable},
|
||||
{sfDestination, SoeRequired, SoeImmutable},
|
||||
{sfAmount, SoeRequired, SoeImmutable},
|
||||
{sfCondition, SoeOptional, SoeImmutable},
|
||||
{sfCancelAfter, SoeOptional, SoeImmutable},
|
||||
{sfFinishAfter, SoeOptional, SoeImmutable},
|
||||
{sfSourceTag, SoeOptional, SoeImmutable},
|
||||
{sfDestinationTag, SoeOptional, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfDestinationNode, SoeOptional, SoeImmutable},
|
||||
{sfTransferRate, SoeOptional, SoeImmutable},
|
||||
{sfIssuerNode, SoeOptional, SoeImmutable},
|
||||
}))
|
||||
|
||||
/** A ledger object describing a single unidirectional XRP payment channel.
|
||||
@@ -349,21 +349,21 @@ LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
|
||||
\sa keylet::payChan
|
||||
*/
|
||||
LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, payment_channel, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSequence, SoeOptional},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfBalance, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSettleDelay, SoeRequired},
|
||||
{sfExpiration, SoeOptional},
|
||||
{sfCancelAfter, SoeOptional},
|
||||
{sfSourceTag, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfDestinationNode, SoeOptional},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfDestination, SoeRequired, SoeImmutable},
|
||||
{sfSequence, SoeOptional, SoeImmutable},
|
||||
{sfAmount, SoeRequired, SoeMutable},
|
||||
{sfBalance, SoeRequired, SoeMutable},
|
||||
{sfPublicKey, SoeRequired, SoeImmutable},
|
||||
{sfSettleDelay, SoeRequired, SoeImmutable},
|
||||
{sfExpiration, SoeOptional, SoeMutable},
|
||||
{sfCancelAfter, SoeOptional, SoeImmutable},
|
||||
{sfSourceTag, SoeOptional, SoeImmutable},
|
||||
{sfDestinationTag, SoeOptional, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfDestinationNode, SoeOptional, SoeImmutable},
|
||||
}))
|
||||
|
||||
/** The ledger object which tracks the AMM.
|
||||
@@ -371,126 +371,126 @@ LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, payment_channel, ({
|
||||
\sa keylet::amm
|
||||
*/
|
||||
LEDGER_ENTRY(ltAMM, 0x0079, AMM, amm, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfTradingFee, SoeDefault},
|
||||
{sfVoteSlots, SoeOptional},
|
||||
{sfAuctionSlot, SoeOptional},
|
||||
{sfLPTokenBalance, SoeRequired},
|
||||
{sfAsset, SoeRequired},
|
||||
{sfAsset2, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeOptional},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfTradingFee, SoeDefault, SoeMutable},
|
||||
{sfVoteSlots, SoeOptional, SoeMutable},
|
||||
{sfAuctionSlot, SoeOptional, SoeMutable},
|
||||
{sfLPTokenBalance, SoeRequired, SoeMutable},
|
||||
{sfAsset, SoeRequired, SoeImmutable},
|
||||
{sfAsset2, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks MPTokenIssuance
|
||||
\sa keylet::mptIssuance
|
||||
*/
|
||||
LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfIssuer, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfTransferFee, SoeDefault},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfAssetScale, SoeDefault},
|
||||
{sfMaximumAmount, SoeOptional},
|
||||
{sfOutstandingAmount, SoeRequired},
|
||||
{sfLockedAmount, SoeOptional},
|
||||
{sfMPTokenMetadata, SoeOptional},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfDomainID, SoeOptional},
|
||||
{sfMutableFlags, SoeDefault},
|
||||
{sfReferenceHolding, SoeOptional},
|
||||
{sfIssuer, SoeRequired, SoeImmutable},
|
||||
{sfSequence, SoeRequired, SoeImmutable},
|
||||
{sfTransferFee, SoeDefault, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfAssetScale, SoeDefault, SoeImmutable},
|
||||
{sfMaximumAmount, SoeOptional, SoeImmutable},
|
||||
{sfOutstandingAmount, SoeRequired, SoeMutable},
|
||||
{sfLockedAmount, SoeOptional, SoeMutable},
|
||||
{sfMPTokenMetadata, SoeOptional, SoeMutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfDomainID, SoeOptional, SoeMutable},
|
||||
{sfMutableFlags, SoeDefault, SoeMutable},
|
||||
{sfReferenceHolding, SoeOptional, SoeImmutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks MPToken
|
||||
\sa keylet::mptoken
|
||||
*/
|
||||
LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfMPTAmount, SoeDefault},
|
||||
{sfLockedAmount, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfMPTokenIssuanceID, SoeRequired, SoeImmutable},
|
||||
{sfMPTAmount, SoeDefault, SoeMutable},
|
||||
{sfLockedAmount, SoeOptional, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks Oracle
|
||||
\sa keylet::oracle
|
||||
*/
|
||||
LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, oracle, ({
|
||||
{sfOwner, SoeRequired},
|
||||
{sfOracleDocumentID, SoeOptional},
|
||||
{sfProvider, SoeRequired},
|
||||
{sfPriceDataSeries, SoeRequired},
|
||||
{sfAssetClass, SoeRequired},
|
||||
{sfLastUpdateTime, SoeRequired},
|
||||
{sfURI, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfOwner, SoeRequired, SoeImmutable},
|
||||
{sfOracleDocumentID, SoeOptional, SoeImmutableSetOnce},
|
||||
{sfProvider, SoeRequired, SoeImmutable},
|
||||
{sfPriceDataSeries, SoeRequired, SoeMutable},
|
||||
{sfAssetClass, SoeRequired, SoeImmutable},
|
||||
{sfLastUpdateTime, SoeRequired, SoeMutable},
|
||||
{sfURI, SoeOptional, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks Credential
|
||||
\sa keylet::credential
|
||||
*/
|
||||
LEDGER_ENTRY(ltCREDENTIAL, 0x0081, Credential, credential, ({
|
||||
{sfSubject, SoeRequired},
|
||||
{sfIssuer, SoeRequired},
|
||||
{sfCredentialType, SoeRequired},
|
||||
{sfExpiration, SoeOptional},
|
||||
{sfURI, SoeOptional},
|
||||
{sfIssuerNode, SoeRequired},
|
||||
{sfSubjectNode, SoeOptional},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfSubject, SoeRequired, SoeImmutable},
|
||||
{sfIssuer, SoeRequired, SoeImmutable},
|
||||
{sfCredentialType, SoeRequired, SoeImmutable},
|
||||
{sfExpiration, SoeOptional, SoeImmutable},
|
||||
{sfURI, SoeOptional, SoeImmutable},
|
||||
{sfIssuerNode, SoeRequired, SoeImmutable},
|
||||
{sfSubjectNode, SoeOptional, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks PermissionedDomain
|
||||
\sa keylet::permissionedDomain
|
||||
*/
|
||||
LEDGER_ENTRY(ltPERMISSIONED_DOMAIN, 0x0082, PermissionedDomain, permissioned_domain, ({
|
||||
{sfOwner, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfAcceptedCredentials, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfOwner, SoeRequired, SoeImmutable},
|
||||
{sfSequence, SoeRequired, SoeImmutable},
|
||||
{sfAcceptedCredentials, SoeRequired, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object representing permissions an account has delegated to another account.
|
||||
\sa keylet::delegate
|
||||
*/
|
||||
LEDGER_ENTRY(ltDELEGATE, 0x0083, Delegate, delegate, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAuthorize, SoeRequired},
|
||||
{sfPermissions, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfDestinationNode, SoeOptional},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfAuthorize, SoeRequired, SoeImmutable},
|
||||
{sfPermissions, SoeRequired, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfDestinationNode, SoeOptional, SoeImmutable},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a single asset vault.
|
||||
\sa keylet::vault
|
||||
*/
|
||||
LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfOwner, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfData, SoeOptional},
|
||||
{sfAsset, SoeRequired},
|
||||
{sfAssetsTotal, SoeDefault},
|
||||
{sfAssetsAvailable, SoeDefault},
|
||||
{sfAssetsMaximum, SoeDefault},
|
||||
{sfLossUnrealized, SoeDefault},
|
||||
{sfShareMPTID, SoeRequired},
|
||||
{sfWithdrawalPolicy, SoeRequired},
|
||||
{sfScale, SoeDefault},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfSequence, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfOwner, SoeRequired, SoeImmutable},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfData, SoeOptional, SoeMutable},
|
||||
{sfAsset, SoeRequired, SoeImmutable},
|
||||
{sfAssetsTotal, SoeDefault, SoeMutable},
|
||||
{sfAssetsAvailable, SoeDefault, SoeMutable},
|
||||
{sfAssetsMaximum, SoeDefault, SoeMutable},
|
||||
{sfLossUnrealized, SoeDefault, SoeMutable},
|
||||
{sfShareMPTID, SoeRequired, SoeImmutable},
|
||||
{sfWithdrawalPolicy, SoeRequired, SoeImmutable},
|
||||
{sfScale, SoeDefault, SoeImmutable},
|
||||
// no SharesTotal ever (use MPTIssuance.sfOutstandingAmount)
|
||||
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
|
||||
}))
|
||||
@@ -502,23 +502,23 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
\sa keylet::loanbroker
|
||||
*/
|
||||
LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfVaultNode, SoeRequired},
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfOwner, SoeRequired},
|
||||
{sfLoanSequence, SoeRequired},
|
||||
{sfData, SoeDefault},
|
||||
{sfManagementFeeRate, SoeDefault},
|
||||
{sfOwnerCount, SoeDefault},
|
||||
{sfDebtTotal, SoeDefault},
|
||||
{sfDebtMaximum, SoeDefault},
|
||||
{sfCoverAvailable, SoeDefault},
|
||||
{sfCoverRateMinimum, SoeDefault},
|
||||
{sfCoverRateLiquidation, SoeDefault},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfSequence, SoeRequired, SoeImmutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfVaultNode, SoeRequired, SoeImmutable},
|
||||
{sfVaultID, SoeRequired, SoeImmutable},
|
||||
{sfAccount, SoeRequired, SoeImmutable},
|
||||
{sfOwner, SoeRequired, SoeImmutable},
|
||||
{sfLoanSequence, SoeRequired, SoeMutable},
|
||||
{sfData, SoeDefault, SoeMutable},
|
||||
{sfManagementFeeRate, SoeDefault, SoeImmutable},
|
||||
{sfOwnerCount, SoeDefault, SoeMutable},
|
||||
{sfDebtTotal, SoeDefault, SoeMutable},
|
||||
{sfDebtMaximum, SoeDefault, SoeMutable},
|
||||
{sfCoverAvailable, SoeDefault, SoeMutable},
|
||||
{sfCoverRateMinimum, SoeDefault, SoeImmutable},
|
||||
{sfCoverRateLiquidation, SoeDefault, SoeImmutable},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a loan between a Borrower and a Loan Broker
|
||||
@@ -526,27 +526,27 @@ LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
|
||||
\sa keylet::loan
|
||||
*/
|
||||
LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfLoanBrokerNode, SoeRequired},
|
||||
{sfLoanBrokerID, SoeRequired},
|
||||
{sfLoanSequence, SoeRequired},
|
||||
{sfBorrower, SoeRequired},
|
||||
{sfLoanOriginationFee, SoeDefault},
|
||||
{sfLoanServiceFee, SoeDefault},
|
||||
{sfLatePaymentFee, SoeDefault},
|
||||
{sfClosePaymentFee, SoeDefault},
|
||||
{sfOverpaymentFee, SoeDefault},
|
||||
{sfInterestRate, SoeDefault},
|
||||
{sfLateInterestRate, SoeDefault},
|
||||
{sfCloseInterestRate, SoeDefault},
|
||||
{sfOverpaymentInterestRate, SoeDefault},
|
||||
{sfStartDate, SoeRequired},
|
||||
{sfPaymentInterval, SoeRequired},
|
||||
{sfGracePeriod, SoeDefault},
|
||||
{sfPreviousPaymentDueDate, SoeDefault},
|
||||
{sfNextPaymentDueDate, SoeDefault},
|
||||
{sfPreviousTxnID, SoeRequired, SoeMutable},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired, SoeMutable},
|
||||
{sfOwnerNode, SoeRequired, SoeImmutable},
|
||||
{sfLoanBrokerNode, SoeRequired, SoeImmutable},
|
||||
{sfLoanBrokerID, SoeRequired, SoeImmutable},
|
||||
{sfLoanSequence, SoeRequired, SoeImmutable},
|
||||
{sfBorrower, SoeRequired, SoeImmutable},
|
||||
{sfLoanOriginationFee, SoeDefault, SoeImmutable},
|
||||
{sfLoanServiceFee, SoeDefault, SoeImmutable},
|
||||
{sfLatePaymentFee, SoeDefault, SoeImmutable},
|
||||
{sfClosePaymentFee, SoeDefault, SoeImmutable},
|
||||
{sfOverpaymentFee, SoeDefault, SoeImmutable},
|
||||
{sfInterestRate, SoeDefault, SoeImmutable},
|
||||
{sfLateInterestRate, SoeDefault, SoeImmutable},
|
||||
{sfCloseInterestRate, SoeDefault, SoeImmutable},
|
||||
{sfOverpaymentInterestRate, SoeDefault, SoeImmutable},
|
||||
{sfStartDate, SoeRequired, SoeImmutable},
|
||||
{sfPaymentInterval, SoeRequired, SoeImmutable},
|
||||
{sfGracePeriod, SoeDefault, SoeImmutable},
|
||||
{sfPreviousPaymentDueDate, SoeDefault, SoeMutable},
|
||||
{sfNextPaymentDueDate, SoeDefault, SoeMutable},
|
||||
// The loan object tracks these values:
|
||||
//
|
||||
// - PaymentRemaining: The number of payments left in the loan. When it
|
||||
@@ -594,17 +594,17 @@ LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({
|
||||
//
|
||||
// Note the "True" values may differ significantly from the tracked
|
||||
// rounded values.
|
||||
{sfPaymentRemaining, SoeDefault},
|
||||
{sfPeriodicPayment, SoeRequired},
|
||||
{sfPrincipalOutstanding, SoeDefault},
|
||||
{sfTotalValueOutstanding, SoeDefault},
|
||||
{sfManagementFeeOutstanding, SoeDefault},
|
||||
{sfPaymentRemaining, SoeDefault, SoeMutable},
|
||||
{sfPeriodicPayment, SoeRequired, SoeMutable},
|
||||
{sfPrincipalOutstanding, SoeDefault, SoeMutable},
|
||||
{sfTotalValueOutstanding, SoeDefault, SoeMutable},
|
||||
{sfManagementFeeOutstanding, SoeDefault, SoeMutable},
|
||||
// Based on the computed total value at creation, used for
|
||||
// rounding calculated values so they are all on a
|
||||
// consistent scale - that is, they all have the same
|
||||
// number of digits after the decimal point (excluding
|
||||
// trailing zeros).
|
||||
{sfLoanScale, SoeDefault},
|
||||
{sfLoanScale, SoeDefault, SoeImmutable},
|
||||
}))
|
||||
|
||||
#undef EXPAND
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
SF_UINT32::type::value_type flags = 0)
|
||||
{
|
||||
// Don't call object_.set(soTemplate) - keep object_ as a free object.
|
||||
// This avoids creating STBase placeholders for soeDEFAULT fields,
|
||||
// This avoids creating STBase placeholders for SoeDefault fields,
|
||||
// which would cause applyTemplate() to throw "may not be explicitly
|
||||
// set to default" when building the SLE.
|
||||
// The SLE constructor will call applyTemplate() which properly
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
std::optional<SF_AMOUNT::type::value_type> fee)
|
||||
{
|
||||
// Don't call object_.set(soTemplate) - keep object_ as a free object.
|
||||
// This avoids creating STBase placeholders for soeDEFAULT fields,
|
||||
// This avoids creating STBase placeholders for SoeDefault fields,
|
||||
// which would cause applyTemplate() to throw "may not be explicitly
|
||||
// set to default" when building the STTx.
|
||||
// The STTx constructor will call applyTemplate() which properly
|
||||
|
||||
@@ -360,7 +360,7 @@ public:
|
||||
* object is modified. Creation and deletion are ignored.
|
||||
*
|
||||
*/
|
||||
class NoModifiedUnmodifiableFields
|
||||
class NoModifiedImmutableFields
|
||||
{
|
||||
// Pair is <before, after>.
|
||||
std::set<std::pair<SLE::const_pointer, SLE::const_pointer>> changedEntries_;
|
||||
@@ -411,7 +411,7 @@ using InvariantChecks = std::tuple<
|
||||
ValidPermissionedDEX,
|
||||
ValidBookDirectory,
|
||||
ValidAMM,
|
||||
NoModifiedUnmodifiableFields,
|
||||
NoModifiedImmutableFields,
|
||||
ValidPseudoAccounts,
|
||||
ValidLoanBroker,
|
||||
ValidLoan,
|
||||
|
||||
@@ -137,9 +137,9 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfCredentialType, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfPermission.jsonName.cStr(), sfPermission.getCode(), {{sfPermissionValue, SoeRequired}});
|
||||
add(sfPermission.jsonName, sfPermission.getCode(), {{sfPermissionValue, SoeRequired}});
|
||||
|
||||
add(sfBatchSigner.jsonName.cStr(),
|
||||
add(sfBatchSigner.jsonName,
|
||||
sfBatchSigner.getCode(),
|
||||
{{sfAccount, SoeRequired},
|
||||
{sfSigningPubKey, SoeOptional},
|
||||
|
||||
@@ -12,9 +12,9 @@ std::vector<SOElement> const&
|
||||
LedgerFormats::getCommonFields()
|
||||
{
|
||||
static auto const kCommonFields = std::vector<SOElement>{
|
||||
{sfLedgerIndex, SoeOptional},
|
||||
{sfLedgerEntryType, SoeRequired},
|
||||
{sfFlags, SoeRequired},
|
||||
{sfLedgerIndex, SoeOptional, SoeImmutable},
|
||||
{sfLedgerEntryType, SoeRequired, SoeImmutable},
|
||||
{sfFlags, SoeRequired, SoeMutable},
|
||||
};
|
||||
return kCommonFields;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ associateAsset(SLE& sle, Asset const& asset)
|
||||
|
||||
// associateAsset in derived classes may change the underlying
|
||||
// value, but it won't know anything about how the value relates to
|
||||
// the SLE. If the template element is soeDEFAULT, and the value
|
||||
// the SLE. If the template element is SoeDefault, and the value
|
||||
// changed to the default value, remove the field.
|
||||
if (style == SoeDefault && ta.isDefault())
|
||||
sle.makeFieldAbsent(field);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/SOTemplate.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
|
||||
@@ -968,7 +969,7 @@ ValidPseudoAccounts::finalize(
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
NoModifiedUnmodifiableFields::visitEntry(
|
||||
NoModifiedImmutableFields::visitEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after)
|
||||
@@ -982,26 +983,105 @@ NoModifiedUnmodifiableFields::visitEntry(
|
||||
changedEntries_.emplace(before, after);
|
||||
}
|
||||
|
||||
// Check whether any immutable (or unannotated) fields in the given template
|
||||
// have been modified between before and after.
|
||||
// TODO(future): recurse into STObject and STArray fields using InnerObjectFormats
|
||||
static bool
|
||||
hasImmutableFieldChanged(STObject const& before, STObject const& after, SOTemplate const& tmpl)
|
||||
{
|
||||
for (auto const& elem : tmpl)
|
||||
{
|
||||
auto const& sf = elem.sField();
|
||||
auto const mutability = elem.mutability();
|
||||
|
||||
auto const* bField = before.peekAtPField(sf);
|
||||
auto const* aField = after.peekAtPField(sf);
|
||||
bool const bPresent = (bField != nullptr) && bField->getSType() != STI_NOTPRESENT;
|
||||
bool const aPresent = (aField != nullptr) && aField->getSType() != STI_NOTPRESENT;
|
||||
|
||||
if (mutability == SoeImmutable)
|
||||
{
|
||||
// Field must not change at all, including transitions between
|
||||
// default (not-present) and explicit values.
|
||||
if (bPresent != aPresent || (bPresent && aPresent && *bField != *aField))
|
||||
return true;
|
||||
}
|
||||
else if (mutability == SoeImmutableSetOnce)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
elem.style() == SoeOptional,
|
||||
"xrpl::hasImmutableFieldChanged : set-once fields must be optional");
|
||||
|
||||
// Field may be set once, but cannot be removed or changed after
|
||||
// it is present.
|
||||
if (bPresent && (!aPresent || *bField != *aField))
|
||||
return true;
|
||||
}
|
||||
// SoeMutable fields may change freely — no recursion
|
||||
// into inner objects/arrays is needed because the parent
|
||||
// field explicitly allows changes to its entire contents.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
NoModifiedUnmodifiableFields::finalize(
|
||||
NoModifiedImmutableFields::finalize(
|
||||
STTx const& tx,
|
||||
TER const,
|
||||
XRPAmount const,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j)
|
||||
{
|
||||
// LedgerStateFix repairs ledger invariants, so it may need to modify
|
||||
// fields that are otherwise immutable.
|
||||
if (tx.getTxnType() == ttLEDGER_STATE_FIX)
|
||||
return true;
|
||||
|
||||
static auto const kFieldChanged = [](auto const& before, auto const& after, auto const& field) {
|
||||
bool const beforeField = before->isFieldPresent(field);
|
||||
bool const afterField = after->isFieldPresent(field);
|
||||
return beforeField != afterField || (afterField && before->at(field) != after->at(field));
|
||||
};
|
||||
|
||||
bool const useTemplate = view.rules().enabled(fixImmutableInvariant);
|
||||
|
||||
for (auto const& slePair : changedEntries_)
|
||||
{
|
||||
auto const& before = slePair.first;
|
||||
auto const& after = slePair.second;
|
||||
auto const type = after->getType();
|
||||
bool bad = false;
|
||||
[[maybe_unused]] bool enforce = false;
|
||||
|
||||
// New template-based check. This is a superset of the old hardcoded
|
||||
// path below: the common template includes sfLedgerEntryType, the
|
||||
// explicit check below covers sfLedgerIndex, and the loan/loan-broker
|
||||
// fields from the old switch are marked immutable in their ledger
|
||||
// templates.
|
||||
if (useTemplate)
|
||||
{
|
||||
bool bad = false;
|
||||
auto const* format = LedgerFormats::getInstance().findByType(type);
|
||||
if (format != nullptr)
|
||||
bad = hasImmutableFieldChanged(*before, *after, format->getSOTemplate());
|
||||
|
||||
// sfLedgerIndex is a non-serialized (discardable) field
|
||||
// that is not reliably present via peekAtPField, so we
|
||||
// check it explicitly.
|
||||
if (!bad)
|
||||
bad = kFieldChanged(before, after, sfLedgerIndex);
|
||||
|
||||
if (bad)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: changed an unchangeable field for "
|
||||
<< tx.getTransactionID();
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Old hardcoded check
|
||||
bool badOld = false;
|
||||
bool const enforceOld = view.rules().enabled(featureLendingProtocol);
|
||||
switch (type)
|
||||
{
|
||||
case ltLOAN_BROKER:
|
||||
@@ -1010,8 +1090,7 @@ NoModifiedUnmodifiableFields::finalize(
|
||||
* amendment status, allowing for detection and logging of
|
||||
* potential issues even when the amendment is disabled.
|
||||
*/
|
||||
enforce = view.rules().enabled(featureLendingProtocol);
|
||||
bad = kFieldChanged(before, after, sfLedgerEntryType) ||
|
||||
badOld = kFieldChanged(before, after, sfLedgerEntryType) ||
|
||||
kFieldChanged(before, after, sfLedgerIndex) ||
|
||||
kFieldChanged(before, after, sfSequence) ||
|
||||
kFieldChanged(before, after, sfOwnerNode) ||
|
||||
@@ -1029,10 +1108,9 @@ NoModifiedUnmodifiableFields::finalize(
|
||||
* amendment status, allowing for detection and logging of
|
||||
* potential issues even when the amendment is disabled.
|
||||
*/
|
||||
enforce = view.rules().enabled(featureLendingProtocol);
|
||||
bad = kFieldChanged(before, after, sfLedgerEntryType) ||
|
||||
badOld = kFieldChanged(before, after, sfLedgerEntryType) ||
|
||||
kFieldChanged(before, after, sfLedgerIndex) ||
|
||||
kFieldChanged(before, after, sfSequence) ||
|
||||
kFieldChanged(before, after, sfLoanSequence) ||
|
||||
kFieldChanged(before, after, sfOwnerNode) ||
|
||||
kFieldChanged(before, after, sfLoanBrokerNode) ||
|
||||
kFieldChanged(before, after, sfLoanBrokerID) ||
|
||||
@@ -1061,19 +1139,19 @@ NoModifiedUnmodifiableFields::finalize(
|
||||
* all transactions are affected because that's when it
|
||||
* was added.
|
||||
*/
|
||||
enforce = view.rules().enabled(featureLendingProtocol);
|
||||
bad = kFieldChanged(before, after, sfLedgerEntryType) ||
|
||||
badOld = kFieldChanged(before, after, sfLedgerEntryType) ||
|
||||
kFieldChanged(before, after, sfLedgerIndex);
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
!bad || enforce,
|
||||
"xrpl::NoModifiedUnmodifiableFields::finalize : no bad "
|
||||
!badOld || enforceOld,
|
||||
"xrpl::NoModifiedImmutableFields::finalize : no bad "
|
||||
"changes or enforce invariant");
|
||||
if (bad)
|
||||
if (badOld)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: changed an unchangeable field for "
|
||||
<< tx.getTransactionID();
|
||||
if (enforce)
|
||||
if (enforceOld)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// sfMutableFlags is soeDEFAULT, defaulting to 0 if not specified on
|
||||
// sfMutableFlags is SoeDefault, defaulting to 0 if not specified on
|
||||
// the ledger.
|
||||
auto const currentMutableFlags = sleMptIssuance->getFieldU32(sfMutableFlags);
|
||||
|
||||
@@ -323,7 +323,7 @@ MPTokenIssuanceSet::doApply()
|
||||
|
||||
if (auto const transferFee = ctx_.tx[~sfTransferFee])
|
||||
{
|
||||
// TransferFee uses soeDEFAULT style:
|
||||
// TransferFee uses SoeDefault style:
|
||||
// - If the field is absent, it is interpreted as 0.
|
||||
// - If the field is present, it must be non-zero.
|
||||
// Therefore, when TransferFee is 0, the field should be removed.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <test/jtx/AMM.h>
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/Oracle.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/fee.h>
|
||||
@@ -2228,7 +2229,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
};
|
||||
|
||||
void
|
||||
testNoModifiedUnmodifiableFields()
|
||||
testNoModifiedImmutableFields()
|
||||
{
|
||||
testcase("no modified unmodifiable fields");
|
||||
using namespace jtx;
|
||||
@@ -2278,10 +2279,12 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
|
||||
// TODO: Loan Object
|
||||
|
||||
// Template-based checks: common constant fields on AccountRoot
|
||||
{
|
||||
auto const mods = std::to_array<std::function<void(SLE::pointer&)>>({
|
||||
[](SLE::pointer& sle) { sle->at(sfLedgerEntryType) += 1; },
|
||||
[](SLE::pointer& sle) { sle->at(sfLedgerIndex) = uint256(1u); },
|
||||
[](SLE::pointer& sle) { sle->at(sfAccount) = Account("other").id(); },
|
||||
});
|
||||
|
||||
for (auto const& mod : mods)
|
||||
@@ -2298,6 +2301,133 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Template-based checks: SoeMutable field
|
||||
// (sfPreviousTxnID) on AccountRoot should NOT fail when
|
||||
// modified — no invariant checks this field.
|
||||
{
|
||||
doInvariantCheck(
|
||||
{},
|
||||
[&](Account const& a1, Account const&, ApplyContext& ac) {
|
||||
auto sle = ac.view().peek(keylet::account(a1.id()));
|
||||
if (!sle)
|
||||
return false;
|
||||
sle->at(sfPreviousTxnID) = uint256(42u);
|
||||
ac.view().update(sle);
|
||||
return true;
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttACCOUNT_SET, [](STObject&) {}},
|
||||
{tesSUCCESS, tesSUCCESS});
|
||||
}
|
||||
|
||||
// Without fixImmutableInvariant, old hardcoded path should
|
||||
// still catch sfLedgerEntryType/sfLedgerIndex changes
|
||||
{
|
||||
auto const mods = std::to_array<std::function<void(SLE::pointer&)>>({
|
||||
[](SLE::pointer& sle) { sle->at(sfLedgerEntryType) += 1; },
|
||||
[](SLE::pointer& sle) { sle->at(sfLedgerIndex) = uint256(1u); },
|
||||
});
|
||||
|
||||
for (auto const& mod : mods)
|
||||
{
|
||||
doInvariantCheck(
|
||||
Env(*this, defaultAmendments() - fixImmutableInvariant),
|
||||
{{"changed an unchangeable field"}},
|
||||
[&](Account const& a1, Account const&, ApplyContext& ac) {
|
||||
auto sle = ac.view().peek(keylet::account(a1.id()));
|
||||
if (!sle)
|
||||
return false;
|
||||
mod(sle);
|
||||
ac.view().update(sle);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Without fixImmutableInvariant, modifying a SoeImmutable field
|
||||
// that is NOT sfLedgerEntryType/sfLedgerIndex on a non-loan
|
||||
// type should NOT fail (old code doesn't check it)
|
||||
{
|
||||
doInvariantCheck(
|
||||
Env(*this, defaultAmendments() - fixImmutableInvariant),
|
||||
{},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto sle = ac.view().peek(keylet::account(a1.id()));
|
||||
if (!sle)
|
||||
return false;
|
||||
sle->at(sfAccount) = a2.id();
|
||||
ac.view().update(sle);
|
||||
return true;
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttACCOUNT_SET, [](STObject&) {}},
|
||||
{tesSUCCESS, tesSUCCESS});
|
||||
}
|
||||
|
||||
// Template-based checks: SoeImmutableSetOnce field on Oracle.
|
||||
{
|
||||
Keylet oracleKeylet = keylet::amendments();
|
||||
Preclose const createLegacyOracle = [this, &oracleKeylet](
|
||||
Account const& a, Account const&, Env& env) {
|
||||
jtx::oracle::Oracle const oracle{env, {.owner = a.id()}};
|
||||
oracleKeylet = keylet::oracle(a.id(), oracle.documentID());
|
||||
|
||||
auto const sle = env.le(oracleKeylet);
|
||||
return BEAST_EXPECT(sle && !sle->isFieldPresent(sfOracleDocumentID));
|
||||
};
|
||||
|
||||
doInvariantCheck(
|
||||
Env(*this, defaultAmendments() - fixIncludeKeyletFields),
|
||||
{},
|
||||
[&](Account const&, Account const&, ApplyContext& ac) {
|
||||
auto sle = ac.view().peek(oracleKeylet);
|
||||
if (!sle)
|
||||
return false;
|
||||
sle->at(sfOracleDocumentID) = std::uint32_t{1};
|
||||
ac.view().update(sle);
|
||||
return true;
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttACCOUNT_SET, [](STObject&) {}},
|
||||
{tesSUCCESS, tesSUCCESS},
|
||||
createLegacyOracle);
|
||||
}
|
||||
|
||||
{
|
||||
Keylet oracleKeylet = keylet::amendments();
|
||||
Preclose const createOracle = [this, &oracleKeylet](
|
||||
Account const& a, Account const&, Env& env) {
|
||||
jtx::oracle::Oracle const oracle{env, {.owner = a.id()}};
|
||||
oracleKeylet = keylet::oracle(a.id(), oracle.documentID());
|
||||
|
||||
auto const sle = env.le(oracleKeylet);
|
||||
return BEAST_EXPECT(sle && sle->isFieldPresent(sfOracleDocumentID));
|
||||
};
|
||||
|
||||
auto const mods = std::to_array<std::function<void(SLE::pointer&)>>({
|
||||
[](SLE::pointer& sle) { sle->at(sfOracleDocumentID) = std::uint32_t{2}; },
|
||||
[](SLE::pointer& sle) { sle->makeFieldAbsent(sfOracleDocumentID); },
|
||||
});
|
||||
|
||||
for (auto const& mod : mods)
|
||||
{
|
||||
doInvariantCheck(
|
||||
{{"changed an unchangeable field"}},
|
||||
[&](Account const&, Account const&, ApplyContext& ac) {
|
||||
auto sle = ac.view().peek(oracleKeylet);
|
||||
if (!sle)
|
||||
return false;
|
||||
mod(sle);
|
||||
ac.view().update(sle);
|
||||
return true;
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttACCOUNT_SET, [](STObject&) {}},
|
||||
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
|
||||
createOracle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3094,7 +3224,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
TxAccount::A2);
|
||||
|
||||
doInvariantCheck(
|
||||
{"violation of vault immutable data"},
|
||||
{"violation of vault immutable data", "changed an unchangeable field"},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto const keylet = keylet::vault(a1.id(), ac.view().seq());
|
||||
auto sleVault = ac.view().peek(keylet);
|
||||
@@ -3106,11 +3236,11 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttVAULT_SET, [](STObject& tx) {}},
|
||||
{tecINVARIANT_FAILED, tecINVARIANT_FAILED},
|
||||
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
|
||||
precloseXrp);
|
||||
|
||||
doInvariantCheck(
|
||||
{"violation of vault immutable data"},
|
||||
{"violation of vault immutable data", "changed an unchangeable field"},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto const keylet = keylet::vault(a1.id(), ac.view().seq());
|
||||
auto sleVault = ac.view().peek(keylet);
|
||||
@@ -3122,11 +3252,11 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttVAULT_SET, [](STObject& tx) {}},
|
||||
{tecINVARIANT_FAILED, tecINVARIANT_FAILED},
|
||||
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
|
||||
precloseXrp);
|
||||
|
||||
doInvariantCheck(
|
||||
{"violation of vault immutable data"},
|
||||
{"violation of vault immutable data", "changed an unchangeable field"},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto const keylet = keylet::vault(a1.id(), ac.view().seq());
|
||||
auto sleVault = ac.view().peek(keylet);
|
||||
@@ -3138,7 +3268,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttVAULT_SET, [](STObject& tx) {}},
|
||||
{tecINVARIANT_FAILED, tecINVARIANT_FAILED},
|
||||
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
|
||||
precloseXrp);
|
||||
|
||||
doInvariantCheck(
|
||||
@@ -3226,7 +3356,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
TxAccount::A2);
|
||||
|
||||
doInvariantCheck(
|
||||
{"updated shares must not exceed maximum"},
|
||||
{"updated shares must not exceed maximum", "changed an unchangeable field"},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto const keylet = keylet::vault(a1.id(), ac.view().seq());
|
||||
auto sleVault = ac.view().peek(keylet);
|
||||
@@ -3242,7 +3372,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttVAULT_DEPOSIT, [](STObject&) {}},
|
||||
{tecINVARIANT_FAILED, tecINVARIANT_FAILED},
|
||||
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
|
||||
precloseXrp,
|
||||
TxAccount::A2);
|
||||
|
||||
@@ -3403,7 +3533,8 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
{"create operation must not have updated a vault",
|
||||
"shares issuer and vault pseudo-account must be the same",
|
||||
"shares issuer must be a pseudo-account",
|
||||
"shares issuer pseudo-account must point back to the vault"},
|
||||
"shares issuer pseudo-account must point back to the vault",
|
||||
"changed an unchangeable field"},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto const keylet = keylet::vault(a1.id(), ac.view().seq());
|
||||
auto sleVault = ac.view().peek(keylet);
|
||||
@@ -3419,7 +3550,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
},
|
||||
XRPAmount{},
|
||||
STTx{ttVAULT_CREATE, [](STObject&) {}},
|
||||
{tecINVARIANT_FAILED, tecINVARIANT_FAILED},
|
||||
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
|
||||
[&](Account const& a1, Account const& a2, Env& env) {
|
||||
Vault const vault{env};
|
||||
auto [tx, keylet] = vault.create({.owner = a1, .asset = xrpIssue()});
|
||||
@@ -4906,7 +5037,7 @@ public:
|
||||
testPermissionedDEX(defaultAmendments() | fixCleanup3_1_3);
|
||||
testPermissionedDEX(defaultAmendments() - fixCleanup3_1_3);
|
||||
testBookDirectoryExchangeRate();
|
||||
testNoModifiedUnmodifiableFields();
|
||||
testNoModifiedImmutableFields();
|
||||
testValidPseudoAccounts();
|
||||
testValidLoanBroker();
|
||||
testVault();
|
||||
|
||||
@@ -3673,7 +3673,7 @@ protected:
|
||||
|
||||
auto const loan = objects[0u];
|
||||
BEAST_EXPECT(loan[sfBorrower] == lender.human());
|
||||
// soeDEFAULT fields are not returned if they're in the default
|
||||
// SoeDefault fields are not returned if they're in the default
|
||||
// state
|
||||
BEAST_EXPECT(!loan.isMember(sfCloseInterestRate));
|
||||
BEAST_EXPECT(!loan.isMember(sfClosePaymentFee));
|
||||
|
||||
Reference in New Issue
Block a user