diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index ca09fc3d71..cb852e5fe3 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -23,6 +23,12 @@ enum SOEStyle { /** Amount fields that can support MPT */ enum SOETxMPTIssue { soeMPTNone, soeMPTSupported, soeMPTNotSupported }; +enum SOEConstant { + soeCONSTANTINVALID = 0, + soeCONSTANT = 1, + soeNOTCONSTANT = 2, +}; + //------------------------------------------------------------------------------ /** An element in a SOTemplate. */ @@ -31,6 +37,7 @@ class SOElement // Use std::reference_wrapper so SOElement can be stored in a std::vector. std::reference_wrapper sField_; SOEStyle style_; + SOEConstant constant_ = soeCONSTANTINVALID; SOETxMPTIssue supportMpt_ = soeMPTNone; private: @@ -52,6 +59,12 @@ public: init(fieldName); } + SOElement(SField const& fieldName, SOEStyle style, SOEConstant constant) + : sField_(fieldName), style_(style), constant_(constant) + { + init(fieldName); + } + template requires(std::is_same_v || std::is_same_v) SOElement( @@ -63,6 +76,18 @@ public: init(fieldName); } + template + requires(std::is_same_v || std::is_same_v) + SOElement( + TypedField const& fieldName, + SOEStyle style, + SOEConstant constant, + SOETxMPTIssue supportMpt = soeMPTNotSupported) + : sField_(fieldName), style_(style), constant_(constant), supportMpt_(supportMpt) + { + init(fieldName); + } + [[nodiscard]] SField const& sField() const { @@ -75,6 +100,12 @@ public: return style_; } + [[nodiscard]] SOEConstant + constant() const + { + return constant_; + } + [[nodiscard]] SOETxMPTIssue supportMPT() const { diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 494b3fa6cd..f7a9566b16 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -36,7 +36,6 @@ XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultN XRPL_FEATURE(Batch, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(SingleAssetVault, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo) -// Check flags in Credential transactions XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo) diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index e4182f0cba..8f341de27e 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -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, soeCONSTANT}, + {sfNFTokenID, soeREQUIRED, soeCONSTANT}, + {sfAmount, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfNFTokenOfferNode, soeREQUIRED, soeCONSTANT}, + {sfDestination, soeOPTIONAL, soeCONSTANT}, + {sfExpiration, soeOPTIONAL, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfDestination, soeREQUIRED, soeCONSTANT}, + {sfSendMax, soeREQUIRED, soeCONSTANT}, + {sfSequence, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfDestinationNode, soeREQUIRED, soeCONSTANT}, + {sfExpiration, soeOPTIONAL, soeCONSTANT}, + {sfInvoiceID, soeOPTIONAL, soeCONSTANT}, + {sfSourceTag, soeOPTIONAL, soeCONSTANT}, + {sfDestinationTag, soeOPTIONAL, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfDIDDocument, soeOPTIONAL, soeNOTCONSTANT}, + {sfURI, soeOPTIONAL, soeNOTCONSTANT}, + {sfData, soeOPTIONAL, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeNOTCONSTANT}, + {sfValidatorToDisable, soeOPTIONAL, soeNOTCONSTANT}, + {sfValidatorToReEnable, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnID, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeOPTIONAL, soeNOTCONSTANT}, })) /** A ledger object which contains a list of NFTs @@ -87,11 +87,11 @@ LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, nunl, ({ \sa keylet::nftpage_min, keylet::nftpage_max, keylet::nftpage */ LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({ - {sfPreviousPageMin, soeOPTIONAL}, - {sfNextPageMin, soeOPTIONAL}, - {sfNFTokens, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfPreviousPageMin, soeOPTIONAL, soeCONSTANT}, + {sfNextPageMin, soeOPTIONAL, soeCONSTANT}, + {sfNFTokens, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfSignerQuorum, soeREQUIRED, soeNOTCONSTANT}, + {sfSignerEntries, soeREQUIRED, soeNOTCONSTANT}, + {sfSignerListID, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeCONSTANT}, })) /** A ledger object which describes a ticket. @@ -115,11 +115,11 @@ LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, signer_list, ({ \sa keylet::ticket */ LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, ({ - {sfAccount, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfTicketSequence, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfTicketSequence, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfSequence, soeREQUIRED, soeNOTCONSTANT}, + {sfBalance, soeREQUIRED, soeNOTCONSTANT}, + {sfOwnerCount, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfAccountTxnID, soeOPTIONAL, soeNOTCONSTANT}, + {sfRegularKey, soeOPTIONAL, soeNOTCONSTANT}, + {sfEmailHash, soeOPTIONAL, soeNOTCONSTANT}, + {sfWalletLocator, soeOPTIONAL, soeNOTCONSTANT}, + {sfWalletSize, soeOPTIONAL, soeNOTCONSTANT}, + {sfMessageKey, soeOPTIONAL, soeNOTCONSTANT}, + {sfTransferRate, soeOPTIONAL, soeNOTCONSTANT}, + {sfDomain, soeOPTIONAL, soeNOTCONSTANT}, + {sfTickSize, soeOPTIONAL, soeNOTCONSTANT}, + {sfTicketCount, soeOPTIONAL, soeNOTCONSTANT}, + {sfNFTokenMinter, soeOPTIONAL, soeNOTCONSTANT}, + {sfMintedNFTokens, soeDEFAULT, soeNOTCONSTANT}, + {sfBurnedNFTokens, soeDEFAULT, soeNOTCONSTANT}, + {sfFirstNFTokenSequence, soeOPTIONAL, soeCONSTANT}, + {sfAMMID, soeOPTIONAL, soeCONSTANT}, // pseudo-account designator + {sfVaultID, soeOPTIONAL, soeCONSTANT}, // pseudo-account designator + {sfLoanBrokerID, soeOPTIONAL, soeCONSTANT}, // 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, soeCONSTANT}, // for owner directories + {sfTakerPaysCurrency, soeOPTIONAL, soeCONSTANT}, // order book directories + {sfTakerPaysIssuer, soeOPTIONAL, soeCONSTANT}, // order book directories + {sfTakerPaysMPT, soeOPTIONAL, soeCONSTANT}, // order book directories + {sfTakerGetsCurrency, soeOPTIONAL, soeCONSTANT}, // order book directories + {sfTakerGetsIssuer, soeOPTIONAL, soeCONSTANT}, // order book directories + {sfTakerGetsMPT, soeOPTIONAL, soeCONSTANT}, // order book directories + {sfExchangeRate, soeOPTIONAL, soeCONSTANT}, // order book directories + {sfIndexes, soeREQUIRED, soeNOTCONSTANT}, + {sfRootIndex, soeREQUIRED, soeCONSTANT}, + {sfIndexNext, soeOPTIONAL, soeNOTCONSTANT}, + {sfIndexPrevious, soeOPTIONAL, soeNOTCONSTANT}, + {sfNFTokenID, soeOPTIONAL, soeCONSTANT}, + {sfPreviousTxnID, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeOPTIONAL, soeNOTCONSTANT}, + {sfDomainID, soeOPTIONAL, soeCONSTANT}, // 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, soeNOTCONSTANT}, // Enabled + {sfMajorities, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnID, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeOPTIONAL, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfLastLedgerSequence, soeOPTIONAL, soeNOTCONSTANT}, + {sfHashes, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfSignatureReward, soeREQUIRED, soeNOTCONSTANT}, + {sfMinAccountCreateAmount, soeOPTIONAL, soeNOTCONSTANT}, + {sfXChainBridge, soeREQUIRED, soeCONSTANT}, + {sfXChainClaimID, soeREQUIRED, soeNOTCONSTANT}, + {sfXChainAccountCreateCount, soeREQUIRED, soeNOTCONSTANT}, + {sfXChainAccountClaimCount, soeREQUIRED, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfSequence, soeREQUIRED, soeCONSTANT}, + {sfTakerPays, soeREQUIRED, soeNOTCONSTANT}, + {sfTakerGets, soeREQUIRED, soeNOTCONSTANT}, + {sfBookDirectory, soeREQUIRED, soeCONSTANT}, + {sfBookNode, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfExpiration, soeOPTIONAL, soeCONSTANT}, + {sfDomainID, soeOPTIONAL, soeCONSTANT}, + {sfAdditionalBooks, soeOPTIONAL, soeCONSTANT}, })) /** 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, soeCONSTANT}, + {sfAuthorize, soeOPTIONAL, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfAuthorizeCredentials, soeOPTIONAL, soeCONSTANT}, })) /** 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, soeCONSTANT}, + {sfXChainBridge, soeREQUIRED, soeCONSTANT}, + {sfXChainClaimID, soeREQUIRED, soeCONSTANT}, + {sfOtherChainSource, soeREQUIRED, soeCONSTANT}, + {sfXChainClaimAttestations, soeREQUIRED, soeCONSTANT}, + {sfSignatureReward, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeNOTCONSTANT}, + {sfLowLimit, soeREQUIRED, soeNOTCONSTANT}, + {sfHighLimit, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfLowNode, soeOPTIONAL, soeNOTCONSTANT}, + {sfLowQualityIn, soeOPTIONAL, soeNOTCONSTANT}, + {sfLowQualityOut, soeOPTIONAL, soeNOTCONSTANT}, + {sfHighNode, soeOPTIONAL, soeNOTCONSTANT}, + {sfHighQualityIn, soeOPTIONAL, soeNOTCONSTANT}, + {sfHighQualityOut, soeOPTIONAL, soeNOTCONSTANT}, })) /** 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, soeNOTCONSTANT}, + {sfReferenceFeeUnits, soeOPTIONAL, soeNOTCONSTANT}, + {sfReserveBase, soeOPTIONAL, soeNOTCONSTANT}, + {sfReserveIncrement, soeOPTIONAL, soeNOTCONSTANT}, // New version uses Amounts - {sfBaseFeeDrops, soeOPTIONAL}, - {sfReserveBaseDrops, soeOPTIONAL}, - {sfReserveIncrementDrops, soeOPTIONAL}, - {sfPreviousTxnID, soeOPTIONAL}, - {sfPreviousTxnLgrSeq, soeOPTIONAL}, + {sfBaseFeeDrops, soeOPTIONAL, soeNOTCONSTANT}, + {sfReserveBaseDrops, soeOPTIONAL, soeNOTCONSTANT}, + {sfReserveIncrementDrops, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnID, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeOPTIONAL, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfXChainBridge, soeREQUIRED, soeCONSTANT}, + {sfXChainAccountCreateCount, soeREQUIRED, soeCONSTANT}, + {sfXChainCreateAccountAttestations, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfSequence, soeOPTIONAL, soeCONSTANT}, + {sfDestination, soeREQUIRED, soeCONSTANT}, + {sfAmount, soeREQUIRED, soeCONSTANT}, + {sfCondition, soeOPTIONAL, soeCONSTANT}, + {sfCancelAfter, soeOPTIONAL, soeCONSTANT}, + {sfFinishAfter, soeOPTIONAL, soeCONSTANT}, + {sfSourceTag, soeOPTIONAL, soeCONSTANT}, + {sfDestinationTag, soeOPTIONAL, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfDestinationNode, soeOPTIONAL, soeCONSTANT}, + {sfTransferRate, soeOPTIONAL, soeCONSTANT}, + {sfIssuerNode, soeOPTIONAL, soeCONSTANT}, })) /** 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, soeCONSTANT}, + {sfDestination, soeREQUIRED, soeCONSTANT}, + {sfSequence, soeOPTIONAL, soeCONSTANT}, + {sfAmount, soeREQUIRED, soeCONSTANT}, + {sfBalance, soeREQUIRED, soeNOTCONSTANT}, + {sfPublicKey, soeREQUIRED, soeCONSTANT}, + {sfSettleDelay, soeREQUIRED, soeCONSTANT}, + {sfExpiration, soeOPTIONAL, soeNOTCONSTANT}, + {sfCancelAfter, soeOPTIONAL, soeCONSTANT}, + {sfSourceTag, soeOPTIONAL, soeCONSTANT}, + {sfDestinationTag, soeOPTIONAL, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeCONSTANT}, + {sfDestinationNode, soeOPTIONAL, soeCONSTANT}, })) /** The ledger object which tracks the AMM. @@ -371,124 +371,124 @@ 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, soeCONSTANT}, + {sfTradingFee, soeDEFAULT, soeNOTCONSTANT}, + {sfVoteSlots, soeOPTIONAL, soeNOTCONSTANT}, + {sfAuctionSlot, soeOPTIONAL, soeNOTCONSTANT}, + {sfLPTokenBalance, soeREQUIRED, soeNOTCONSTANT}, + {sfAsset, soeREQUIRED, soeCONSTANT}, + {sfAsset2, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeOPTIONAL, soeNOTCONSTANT}, })) /** 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}, + {sfIssuer, soeREQUIRED, soeCONSTANT}, + {sfSequence, soeREQUIRED, soeCONSTANT}, + {sfTransferFee, soeDEFAULT, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfAssetScale, soeDEFAULT, soeNOTCONSTANT}, + {sfMaximumAmount, soeOPTIONAL, soeCONSTANT}, + {sfOutstandingAmount, soeREQUIRED, soeNOTCONSTANT}, + {sfLockedAmount, soeOPTIONAL, soeNOTCONSTANT}, + {sfMPTokenMetadata, soeOPTIONAL, soeNOTCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfDomainID, soeOPTIONAL, soeNOTCONSTANT}, + {sfMutableFlags, soeDEFAULT, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfMPTokenIssuanceID, soeREQUIRED, soeCONSTANT}, + {sfMPTAmount, soeDEFAULT, soeNOTCONSTANT}, + {sfLockedAmount, soeOPTIONAL, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfOracleDocumentID, soeOPTIONAL, soeCONSTANT}, + {sfProvider, soeREQUIRED, soeCONSTANT}, + {sfPriceDataSeries, soeREQUIRED, soeNOTCONSTANT}, + {sfAssetClass, soeREQUIRED, soeNOTCONSTANT}, + {sfLastUpdateTime, soeREQUIRED, soeNOTCONSTANT}, + {sfURI, soeOPTIONAL, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfIssuer, soeREQUIRED, soeCONSTANT}, + {sfCredentialType, soeREQUIRED, soeCONSTANT}, + {sfExpiration, soeOPTIONAL, soeCONSTANT}, + {sfURI, soeOPTIONAL, soeCONSTANT}, + {sfIssuerNode, soeREQUIRED, soeCONSTANT}, + {sfSubjectNode, soeOPTIONAL, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeCONSTANT}, + {sfSequence, soeREQUIRED, soeCONSTANT}, + {sfAcceptedCredentials, soeREQUIRED, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfAuthorize, soeREQUIRED, soeCONSTANT}, + {sfPermissions, soeREQUIRED, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfPreviousTxnID, soeREQUIRED, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, })) /** 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, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfSequence, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfOwner, soeREQUIRED, soeCONSTANT}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfData, soeOPTIONAL, soeNOTCONSTANT}, + {sfAsset, soeREQUIRED, soeCONSTANT}, + {sfAssetsTotal, soeDEFAULT, soeNOTCONSTANT}, + {sfAssetsAvailable, soeDEFAULT, soeNOTCONSTANT}, + {sfAssetsMaximum, soeDEFAULT, soeNOTCONSTANT}, + {sfLossUnrealized, soeDEFAULT, soeNOTCONSTANT}, + {sfShareMPTID, soeREQUIRED, soeCONSTANT}, + {sfWithdrawalPolicy, soeREQUIRED, soeCONSTANT}, + {sfScale, soeDEFAULT, soeCONSTANT}, // no SharesTotal ever (use MPTIssuance.sfOutstandingAmount) // no PermissionedDomainID ever (use MPTIssuance.sfDomainID) })) @@ -500,23 +500,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, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfSequence, soeREQUIRED, soeCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfVaultNode, soeREQUIRED, soeCONSTANT}, + {sfVaultID, soeREQUIRED, soeCONSTANT}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfOwner, soeREQUIRED, soeCONSTANT}, + {sfLoanSequence, soeREQUIRED, soeNOTCONSTANT}, + {sfData, soeDEFAULT, soeNOTCONSTANT}, + {sfManagementFeeRate, soeDEFAULT, soeCONSTANT}, + {sfOwnerCount, soeDEFAULT, soeNOTCONSTANT}, + {sfDebtTotal, soeDEFAULT, soeNOTCONSTANT}, + {sfDebtMaximum, soeDEFAULT, soeNOTCONSTANT}, + {sfCoverAvailable, soeDEFAULT, soeNOTCONSTANT}, + {sfCoverRateMinimum, soeDEFAULT, soeCONSTANT}, + {sfCoverRateLiquidation, soeDEFAULT, soeCONSTANT}, })) /** A ledger object representing a loan between a Borrower and a Loan Broker @@ -524,27 +524,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, soeNOTCONSTANT}, + {sfPreviousTxnLgrSeq, soeREQUIRED, soeNOTCONSTANT}, + {sfOwnerNode, soeREQUIRED, soeCONSTANT}, + {sfLoanBrokerNode, soeREQUIRED, soeCONSTANT}, + {sfLoanBrokerID, soeREQUIRED, soeCONSTANT}, + {sfLoanSequence, soeREQUIRED, soeCONSTANT}, + {sfBorrower, soeREQUIRED, soeCONSTANT}, + {sfLoanOriginationFee, soeDEFAULT, soeCONSTANT}, + {sfLoanServiceFee, soeDEFAULT, soeCONSTANT}, + {sfLatePaymentFee, soeDEFAULT, soeCONSTANT}, + {sfClosePaymentFee, soeDEFAULT, soeCONSTANT}, + {sfOverpaymentFee, soeDEFAULT, soeCONSTANT}, + {sfInterestRate, soeDEFAULT, soeCONSTANT}, + {sfLateInterestRate, soeDEFAULT, soeCONSTANT}, + {sfCloseInterestRate, soeDEFAULT, soeCONSTANT}, + {sfOverpaymentInterestRate, soeDEFAULT, soeCONSTANT}, + {sfStartDate, soeREQUIRED, soeCONSTANT}, + {sfPaymentInterval, soeREQUIRED, soeCONSTANT}, + {sfGracePeriod, soeDEFAULT, soeCONSTANT}, + {sfPreviousPaymentDueDate, soeDEFAULT, soeNOTCONSTANT}, + {sfNextPaymentDueDate, soeDEFAULT, soeNOTCONSTANT}, // The loan object tracks these values: // // - PaymentRemaining: The number of payments left in the loan. When it @@ -592,17 +592,17 @@ LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({ // // Note the the "True" values may differ significantly from the tracked // rounded values. - {sfPaymentRemaining, soeDEFAULT}, - {sfPeriodicPayment, soeREQUIRED}, - {sfPrincipalOutstanding, soeDEFAULT}, - {sfTotalValueOutstanding, soeDEFAULT}, - {sfManagementFeeOutstanding, soeDEFAULT}, + {sfPaymentRemaining, soeDEFAULT, soeNOTCONSTANT}, + {sfPeriodicPayment, soeREQUIRED, soeNOTCONSTANT}, + {sfPrincipalOutstanding, soeDEFAULT, soeNOTCONSTANT}, + {sfTotalValueOutstanding, soeDEFAULT, soeNOTCONSTANT}, + {sfManagementFeeOutstanding, soeDEFAULT, soeNOTCONSTANT}, // 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, soeCONSTANT}, })) #undef EXPAND diff --git a/src/libxrpl/protocol/InnerObjectFormats.cpp b/src/libxrpl/protocol/InnerObjectFormats.cpp index f4a88ec171..57e81ae3f4 100644 --- a/src/libxrpl/protocol/InnerObjectFormats.cpp +++ b/src/libxrpl/protocol/InnerObjectFormats.cpp @@ -13,152 +13,154 @@ InnerObjectFormats::InnerObjectFormats() add(sfSignerEntry.jsonName, sfSignerEntry.getCode(), { - {sfAccount, soeREQUIRED}, - {sfSignerWeight, soeREQUIRED}, - {sfWalletLocator, soeOPTIONAL}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfSignerWeight, soeREQUIRED, soeNOTCONSTANT}, + {sfWalletLocator, soeOPTIONAL, soeNOTCONSTANT}, }); add(sfSigner.jsonName, sfSigner.getCode(), { - {sfAccount, soeREQUIRED}, - {sfSigningPubKey, soeREQUIRED}, - {sfTxnSignature, soeREQUIRED}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfSigningPubKey, soeREQUIRED, soeCONSTANT}, + {sfTxnSignature, soeREQUIRED, soeCONSTANT}, }); add(sfMajority.jsonName, sfMajority.getCode(), { - {sfAmendment, soeREQUIRED}, - {sfCloseTime, soeREQUIRED}, + {sfAmendment, soeREQUIRED, soeCONSTANT}, + {sfCloseTime, soeREQUIRED, soeCONSTANT}, }); add(sfDisabledValidator.jsonName, sfDisabledValidator.getCode(), { - {sfPublicKey, soeREQUIRED}, - {sfFirstLedgerSequence, soeREQUIRED}, + {sfPublicKey, soeREQUIRED, soeCONSTANT}, + {sfFirstLedgerSequence, soeREQUIRED, soeCONSTANT}, }); add(sfNFToken.jsonName, sfNFToken.getCode(), { - {sfNFTokenID, soeREQUIRED}, - {sfURI, soeOPTIONAL}, + {sfNFTokenID, soeREQUIRED, soeCONSTANT}, + {sfURI, soeOPTIONAL, soeNOTCONSTANT}, }); add(sfVoteEntry.jsonName, sfVoteEntry.getCode(), { - {sfAccount, soeREQUIRED}, - {sfTradingFee, soeDEFAULT}, - {sfVoteWeight, soeREQUIRED}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfTradingFee, soeDEFAULT, soeNOTCONSTANT}, + {sfVoteWeight, soeREQUIRED, soeNOTCONSTANT}, }); add(sfAuctionSlot.jsonName, sfAuctionSlot.getCode(), - {{sfAccount, soeREQUIRED}, - {sfExpiration, soeREQUIRED}, - {sfDiscountedFee, soeDEFAULT}, - {sfPrice, soeREQUIRED}, - {sfAuthAccounts, soeOPTIONAL}}); + {{sfAccount, soeREQUIRED, soeCONSTANT}, + {sfExpiration, soeREQUIRED, soeCONSTANT}, + {sfDiscountedFee, soeDEFAULT, soeCONSTANT}, + {sfPrice, soeREQUIRED, soeCONSTANT}, + {sfAuthAccounts, soeOPTIONAL, soeCONSTANT}}); add(sfXChainClaimAttestationCollectionElement.jsonName, sfXChainClaimAttestationCollectionElement.getCode(), { - {sfAttestationSignerAccount, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, - {sfSignature, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfAccount, soeREQUIRED}, - {sfAttestationRewardAccount, soeREQUIRED}, - {sfWasLockingChainSend, soeREQUIRED}, - {sfXChainClaimID, soeREQUIRED}, - {sfDestination, soeOPTIONAL}, + {sfAttestationSignerAccount, soeREQUIRED, soeCONSTANT}, + {sfPublicKey, soeREQUIRED, soeCONSTANT}, + {sfSignature, soeREQUIRED, soeCONSTANT}, + {sfAmount, soeREQUIRED, soeCONSTANT}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfAttestationRewardAccount, soeREQUIRED, soeCONSTANT}, + {sfWasLockingChainSend, soeREQUIRED, soeCONSTANT}, + {sfXChainClaimID, soeREQUIRED, soeCONSTANT}, + {sfDestination, soeOPTIONAL, soeCONSTANT}, }); 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}, + {sfAttestationSignerAccount, soeREQUIRED, soeCONSTANT}, + {sfPublicKey, soeREQUIRED, soeCONSTANT}, + {sfSignature, soeREQUIRED, soeCONSTANT}, + {sfAmount, soeREQUIRED, soeCONSTANT}, + {sfAccount, soeREQUIRED, soeCONSTANT}, + {sfAttestationRewardAccount, soeREQUIRED, soeCONSTANT}, + {sfWasLockingChainSend, soeREQUIRED, soeCONSTANT}, + {sfXChainAccountCreateCount, soeREQUIRED, soeCONSTANT}, + {sfDestination, soeREQUIRED, soeCONSTANT}, + {sfSignatureReward, soeREQUIRED, soeCONSTANT}, }); add(sfXChainClaimProofSig.jsonName, sfXChainClaimProofSig.getCode(), { - {sfAttestationSignerAccount, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfAttestationRewardAccount, soeREQUIRED}, - {sfWasLockingChainSend, soeREQUIRED}, - {sfDestination, soeOPTIONAL}, + {sfAttestationSignerAccount, soeREQUIRED, soeCONSTANT}, + {sfPublicKey, soeREQUIRED, soeCONSTANT}, + {sfAmount, soeREQUIRED, soeCONSTANT}, + {sfAttestationRewardAccount, soeREQUIRED, soeCONSTANT}, + {sfWasLockingChainSend, soeREQUIRED, soeCONSTANT}, + {sfDestination, soeOPTIONAL, soeCONSTANT}, }); add(sfXChainCreateAccountProofSig.jsonName, sfXChainCreateAccountProofSig.getCode(), { - {sfAttestationSignerAccount, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfSignatureReward, soeREQUIRED}, - {sfAttestationRewardAccount, soeREQUIRED}, - {sfWasLockingChainSend, soeREQUIRED}, - {sfDestination, soeREQUIRED}, + {sfAttestationSignerAccount, soeREQUIRED, soeCONSTANT}, + {sfPublicKey, soeREQUIRED, soeCONSTANT}, + {sfAmount, soeREQUIRED, soeCONSTANT}, + {sfSignatureReward, soeREQUIRED, soeCONSTANT}, + {sfAttestationRewardAccount, soeREQUIRED, soeCONSTANT}, + {sfWasLockingChainSend, soeREQUIRED, soeCONSTANT}, + {sfDestination, soeREQUIRED, soeCONSTANT}, }); add(sfAuthAccount.jsonName, sfAuthAccount.getCode(), { - {sfAccount, soeREQUIRED}, + {sfAccount, soeREQUIRED, soeCONSTANT}, }); add(sfPriceData.jsonName, sfPriceData.getCode(), { - {sfBaseAsset, soeREQUIRED}, - {sfQuoteAsset, soeREQUIRED}, - {sfAssetPrice, soeOPTIONAL}, - {sfScale, soeDEFAULT}, + {sfBaseAsset, soeREQUIRED, soeCONSTANT}, + {sfQuoteAsset, soeREQUIRED, soeCONSTANT}, + {sfAssetPrice, soeOPTIONAL, soeCONSTANT}, + {sfScale, soeDEFAULT, soeCONSTANT}, }); add(sfCredential.jsonName, sfCredential.getCode(), { - {sfIssuer, soeREQUIRED}, - {sfCredentialType, soeREQUIRED}, + {sfIssuer, soeREQUIRED, soeCONSTANT}, + {sfCredentialType, soeREQUIRED, soeCONSTANT}, }); - add(sfPermission.jsonName.c_str(), sfPermission.getCode(), {{sfPermissionValue, soeREQUIRED}}); + add(sfPermission.jsonName.c_str(), + sfPermission.getCode(), + {{sfPermissionValue, soeREQUIRED, soeCONSTANT}}); add(sfBatchSigner.jsonName.c_str(), sfBatchSigner.getCode(), - {{sfAccount, soeREQUIRED}, - {sfSigningPubKey, soeOPTIONAL}, - {sfTxnSignature, soeOPTIONAL}, + {{sfAccount, soeREQUIRED, soeCONSTANT}, + {sfSigningPubKey, soeOPTIONAL, soeCONSTANT}, + {sfTxnSignature, soeOPTIONAL, soeCONSTANT}, {sfSigners, soeOPTIONAL}}); add(sfBook.jsonName, sfBook.getCode(), { - {sfBookDirectory, soeREQUIRED}, - {sfBookNode, soeREQUIRED}, + {sfBookDirectory, soeREQUIRED, soeCONSTANT}, + {sfBookNode, soeREQUIRED, soeCONSTANT}, }); add(sfCounterpartySignature.jsonName, sfCounterpartySignature.getCode(), { - {sfSigningPubKey, soeOPTIONAL}, - {sfTxnSignature, soeOPTIONAL}, - {sfSigners, soeOPTIONAL}, + {sfSigningPubKey, soeOPTIONAL, soeCONSTANT}, + {sfTxnSignature, soeOPTIONAL, soeCONSTANT}, + {sfSigners, soeOPTIONAL, soeCONSTANT}, }); } diff --git a/src/libxrpl/protocol/LedgerFormats.cpp b/src/libxrpl/protocol/LedgerFormats.cpp index 7826435e51..dd21a3ae5e 100644 --- a/src/libxrpl/protocol/LedgerFormats.cpp +++ b/src/libxrpl/protocol/LedgerFormats.cpp @@ -12,9 +12,9 @@ std::vector const& LedgerFormats::getCommonFields() { static auto const commonFields = std::vector{ - {sfLedgerIndex, soeOPTIONAL}, - {sfLedgerEntryType, soeREQUIRED}, - {sfFlags, soeREQUIRED}, + {sfLedgerIndex, soeOPTIONAL, soeCONSTANT}, + {sfLedgerEntryType, soeREQUIRED, soeCONSTANT}, + {sfFlags, soeREQUIRED, soeNOTCONSTANT}, }; return commonFields; } diff --git a/src/libxrpl/tx/invariants/InvariantCheck.cpp b/src/libxrpl/tx/invariants/InvariantCheck.cpp index f2570d14e8..827c72974a 100644 --- a/src/libxrpl/tx/invariants/InvariantCheck.cpp +++ b/src/libxrpl/tx/invariants/InvariantCheck.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include // IWYU pragma: keep #include @@ -945,6 +947,73 @@ NoModifiedUnmodifiableFields::visitEntry( changedEntries_.emplace(before, after); } +// Check whether any constant (or unannotated) fields in the given template +// have been modified between before and after. Recurses into STObject and +// STArray fields using InnerObjectFormats. +static bool +hasConstantFieldChanged(STObject const& before, STObject const& after, SOTemplate const& tmpl) +{ + for (auto const& elem : tmpl) + { + auto const& sf = elem.sField(); + auto const constant = elem.constant(); + + auto const* bField = before.peekAtPField(sf); + auto const* aField = after.peekAtPField(sf); + bool const bPresent = bField && bField->getSType() != STI_NOTPRESENT; + bool const aPresent = aField && aField->getSType() != STI_NOTPRESENT; + + if (constant == soeCONSTANT || constant == soeCONSTANTINVALID) + { + // The field must not change at all. + if (bPresent != aPresent || (aPresent && *bField != *aField)) + return true; + } + else if (constant == soeNOTCONSTANT) + { + // The field itself may change, but if it is an STObject or + // STArray we still need to recurse and check the inner + // fields against the inner object template. + if (!bPresent || !aPresent) + continue; + + if (sf.fieldType == STI_OBJECT) + { + auto const* innerTmpl = + InnerObjectFormats::getInstance().findSOTemplateBySField(sf); + if (innerTmpl) + { + auto const& bObj = before.getFieldObject(sf); + auto const& aObj = after.getFieldObject(sf); + if (hasConstantFieldChanged(bObj, aObj, *innerTmpl)) + return true; + } + } + else if (sf.fieldType == STI_ARRAY) + { + auto const& bArr = before.getFieldArray(sf); + auto const& aArr = after.getFieldArray(sf); + auto const n = std::min(bArr.size(), aArr.size()); + for (std::size_t i = 0; i < n; ++i) + { + auto const& bElem = bArr[i]; + auto const& aElem = aArr[i]; + // Each element of the array is an STObject whose + // template is determined by its SField name. + auto const* innerTmpl = + InnerObjectFormats::getInstance().findSOTemplateBySField(bElem.getFName()); + if (innerTmpl) + { + if (hasConstantFieldChanged(bElem, aElem, *innerTmpl)) + return true; + } + } + } + } + } + return false; +} + bool NoModifiedUnmodifiableFields::finalize( STTx const& tx, @@ -958,23 +1027,31 @@ NoModifiedUnmodifiableFields::finalize( bool const afterField = after->isFieldPresent(field); return beforeField != afterField || (afterField && before->at(field) != after->at(field)); }; + + bool const useTemplate = view.rules().enabled(featureInvariantsV1_1); + for (auto const& slePair : changedEntries_) { auto const& before = slePair.first; auto const& after = slePair.second; auto const type = after->getType(); + + // New template-based check bool bad = false; - [[maybe_unused]] bool enforce = false; + { + auto const* format = LedgerFormats::getInstance().findByType(type); + if (format) + bad = hasConstantFieldChanged(*before, *after, format->getSOTemplate()); + } + + // Old hardcoded check + bool badOld = false; + [[maybe_unused]] bool enforceOld = false; switch (type) { case ltLOAN_BROKER: - /* - * We check this invariant regardless of lending protocol - * amendment status, allowing for detection and logging of - * potential issues even when the amendment is disabled. - */ - enforce = view.rules().enabled(featureLendingProtocol); - bad = fieldChanged(before, after, sfLedgerEntryType) || + enforceOld = view.rules().enabled(featureLendingProtocol); + badOld = fieldChanged(before, after, sfLedgerEntryType) || fieldChanged(before, after, sfLedgerIndex) || fieldChanged(before, after, sfSequence) || fieldChanged(before, after, sfOwnerNode) || @@ -987,13 +1064,8 @@ NoModifiedUnmodifiableFields::finalize( fieldChanged(before, after, sfCoverRateLiquidation); break; case ltLOAN: - /* - * We check this invariant regardless of lending protocol - * amendment status, allowing for detection and logging of - * potential issues even when the amendment is disabled. - */ - enforce = view.rules().enabled(featureLendingProtocol); - bad = fieldChanged(before, after, sfLedgerEntryType) || + enforceOld = view.rules().enabled(featureLendingProtocol); + badOld = fieldChanged(before, after, sfLedgerEntryType) || fieldChanged(before, after, sfLedgerIndex) || fieldChanged(before, after, sfSequence) || fieldChanged(before, after, sfOwnerNode) || @@ -1015,28 +1087,32 @@ NoModifiedUnmodifiableFields::finalize( fieldChanged(before, after, sfLoanScale); break; default: - /* - * We check this invariant regardless of lending protocol - * amendment status, allowing for detection and logging of - * potential issues even when the amendment is disabled. - * - * We use the lending protocol as a gate, even though - * all transactions are affected because that's when it - * was added. - */ - enforce = view.rules().enabled(featureLendingProtocol); - bad = fieldChanged(before, after, sfLedgerEntryType) || + enforceOld = view.rules().enabled(featureLendingProtocol); + badOld = fieldChanged(before, after, sfLedgerEntryType) || fieldChanged(before, after, sfLedgerIndex); } + XRPL_ASSERT( - !bad || enforce, + !bad || useTemplate, "xrpl::NoModifiedUnmodifiableFields::finalize : no bad " - "changes or enforce invariant"); + "changes or enforce invariant (template)"); if (bad) { JLOG(j.fatal()) << "Invariant failed: changed an unchangeable field for " << tx.getTransactionID(); - if (enforce) + if (useTemplate) + return false; + } + + XRPL_ASSERT( + !badOld || enforceOld, + "xrpl::NoModifiedUnmodifiableFields::finalize : no bad " + "changes or enforce invariant"); + if (badOld) + { + JLOG(j.fatal()) << "Invariant failed: changed an unchangeable field for " + << tx.getTransactionID(); + if (!useTemplate && enforceOld) return false; } }