From 1cbf843fd3b375b9b70f748c08587b4792a84d66 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Tue, 8 Oct 2024 12:55:50 -0500 Subject: [PATCH] flags --- include/xrpl/protocol/LedgerFormats.h | 3 + include/xrpl/protocol/TER.h | 3 +- include/xrpl/protocol/TxFlags.h | 5 ++ include/xrpl/protocol/detail/ledger_entries.m | 10 +-- src/xrpld/app/tx/detail/VaultSet.cpp | 87 ++++++++++--------- 5 files changed, 59 insertions(+), 49 deletions(-) diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index 8d148771cc5..b6669824164 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -186,6 +186,9 @@ enum LedgerSpecificFlags { // ltMPTOKEN lsfMPTAuthorized = 0x00000002, + + // ltVAULT + lsfVaultPrivate = 0x00000001, }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index b4dcd6ff875..ed85f1225ae 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -345,7 +345,8 @@ enum TECcodes : TERUnderlyingType { tecMPT_MAX_AMOUNT_EXCEEDED = 193, tecMPT_LOCKED = 194, tecMPT_NOT_SUPPORTED = 195, - tecMPT_ISSUANCE_NOT_FOUND = 196 + tecMPT_ISSUANCE_NOT_FOUND = 196, + tecIMMUTABLE = 197, }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index e364b9ba6e2..de81df1bc64 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -216,6 +216,11 @@ constexpr std::uint32_t const tfMPTokenAuthorizeMask = ~(tfMPTUnauthorize | tfU // MPTokenIssuanceSet flags: constexpr std::uint32_t const tfMPTokenIssuanceSetMask = ~(tfMPTLock | tfMPTUnlock | tfUniversal); + +// Vault flags: +constexpr std::uint32_t const tfVaultPrivate = 0x00000001; +static_assert(tfVaultPrivate == lsfVaultPrivate); +constexpr std::uint32_t const tfVaultShareNonTransferable = 0x00000002; // clang-format on } // namespace ripple diff --git a/include/xrpl/protocol/detail/ledger_entries.m b/include/xrpl/protocol/detail/ledger_entries.m index b4875624302..d114798b697 100644 --- a/include/xrpl/protocol/detail/ledger_entries.m +++ b/include/xrpl/protocol/detail/ledger_entries.m @@ -437,14 +437,14 @@ to implement skip lists that allow for efficient backwards (and, in {sfOwnerNode, soeREQUIRED}, {sfOwner, soeREQUIRED}, {sfAccount, soeREQUIRED}, - {sfData, soeOPTIONAL}, + {sfData, soeDEFAULT}, {sfAsset, soeREQUIRED}, - {sfAssetTotal, soeREQUIRED}, - {sfAssetAvailable, soeREQUIRED}, - {sfAssetMaximum, soeOPTIONAL}, + {sfAssetTotal, soeDEFAULT}, + {sfAssetAvailable, soeDEFAULT}, + {sfAssetMaximum, soeDEFAULT}, {sfMPTokenIssuanceID, soeREQUIRED}, // sfShare // no ShareTotal ever (use MPTIssuance.sfOutstandingAmount) // no WithdrawalPolicy ever (YAGNI) // no PermissionedDomainID yet - {sfLossUnrealized, soeOPTIONAL}, // not in spec + {sfLossUnrealized, soeDEFAULT}, // not in spec })) diff --git a/src/xrpld/app/tx/detail/VaultSet.cpp b/src/xrpld/app/tx/detail/VaultSet.cpp index 72dab311025..bd6ee541bed 100644 --- a/src/xrpld/app/tx/detail/VaultSet.cpp +++ b/src/xrpld/app/tx/detail/VaultSet.cpp @@ -56,82 +56,83 @@ VaultSet::doApply() auto const& owner = account_; auto sequence = tx.getSequence(); - auto const& vaultId = tx[~sfVaultID]; - auto keylet = - vaultId ? Keylet{ltVAULT, *vaultId} : keylet::vault(owner, sequence); - - auto vault = view().peek(keylet); - - if (vault) + if (auto const& vaultId = tx[~sfVaultID]; vaultId) { // Update existing object. + auto keylet = Keylet{ltVAULT, *vaultId}; + auto vault = view().peek(keylet); + if (!vault) + return tecOBJECT_NOT_FOUND; + // Assert that submitter is the Owner. - if (owner != (*vault)[sfOwner]) - return tecNO_PERMISSION; - // Assert that Asset is the same if given. - if (tx.isFieldPresent(sfAsset) && tx[sfAsset] != (*vault)[sfAsset]) + if (owner != vault->at(sfOwner)) return tecNO_PERMISSION; + + // Assert immutable flags not given. + auto txFlags = tx[sfFlags]; + if ((txFlags & tfVaultPrivate) || (txFlags & tfVaultShareNonTransferable)) + return tecIMMUTABLE; + // Assert identical immutable fields if given. + if (tx.isFieldPresent(sfAsset) && tx[sfAsset] != vault->at(sfAsset)) + return tecIMMUTABLE; + + // TODO: sfMPTokenMetadata? + + // Update mutable flags and fields if given. + if (tx.isFieldPresent(sfData)) + vault->at(~sfData) = tx[~sfData]; + if (tx.isFieldPresent(sfAssetMaximum)) + vault->at(~sfAssetMaximum) = tx[sfAssetMaximum]; + view().update(vault); } - else if (tx.isFieldPresent(sfVaultID)) - { - // Update missing object. - return tecOBJECT_NOT_FOUND; - } else { // Create new object. if (!tx.isFieldPresent(sfAsset)) return tecINCOMPLETE; - vault = std::make_shared(keylet); + auto keylet = keylet::vault(owner, sequence); + auto vault = std::make_shared(keylet); if (auto ter = dirLink(view(), owner, vault); ter) return ter; auto maybe = createPseudoAccount(view(), vault->key()); if (!maybe) return maybe.error(); auto& pseudo = *maybe; - auto pseudoId = (*pseudo)[sfAccount]; + auto pseudoId = pseudo->at(sfAccount); + auto txFlags = tx[sfFlags]; + std::uint32_t mptFlags = 0; + if (!(txFlags & tfVaultShareNonTransferable)) + mptFlags |= (lsfMPTCanEscrow | lsfMPTCanTrade | lsfMPTCanTransfer); + if (txFlags & tfVaultPrivate) + mptFlags |= lsfMPTRequireAuth; auto maybe2 = MPTokenIssuanceCreate::create( view(), j_, { .account = pseudoId, .sequence = 1, - // !tfShareNonTransferable => lsfMPTCanEscrow, lsfMPTCanTrade, - // lsfMPTCanTransfer tfPrivate => lsfMPTRequireAuth - .flags = 0, + .flags = mptFlags, .metadata = tx[~sfMPTokenMetadata], }); if (!maybe2) return maybe2.error(); auto& mptId = *maybe2; - (*vault)[sfSequence] = sequence; - (*vault)[sfOwner] = owner; - (*vault)[sfAccount] = pseudoId; - (*vault)[~sfData] = tx[~sfData]; - (*vault)[sfAsset] = tx[sfAsset]; - (*vault)[sfAssetTotal] = 0; - (*vault)[sfAssetAvailable] = 0; - (*vault)[~sfAssetMaximum] = tx[~sfAssetMaximum]; - (*vault)[sfMPTokenIssuanceID] = mptId; + vault->at(sfFlags) = txFlags & tfVaultPrivate; + vault->at(sfSequence) = sequence; + vault->at(sfOwner) = owner; + vault->at(sfAccount) = pseudoId; + vault->at(~sfData) = tx[~sfData]; + vault->at(sfAsset) = tx[sfAsset]; + // vault->at(sfAssetTotal) = 0; + // vault->at(sfAssetAvailable) = 0; + vault->at(~sfAssetMaximum) = tx[~sfAssetMaximum]; + vault->at(sfMPTokenIssuanceID) = mptId; // No `LossUnrealized`. view().insert(vault); } - // Set or clear field AssetMaximum. - if (tx.isFieldPresent(sfAssetMaximum)) - { - if (tx[sfAssetMaximum] == 0) - { - vault->delField(sfAssetMaximum); - } - else - { - (*vault)[sfAssetMaximum] = tx[sfAssetMaximum]; - } - } - return tesSUCCESS; }