From f96d50b487135c21ed026ad6f6ff849b8e601be6 Mon Sep 17 00:00:00 2001 From: Peter Chen <34582813+PeterChen13579@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:40:16 -0700 Subject: [PATCH] add server logging (#7645) --- include/xrpl/protocol/detail/sfields.macro | 4 +- include/xrpl/tx/invariants/MPTInvariant.h | 4 +- src/libxrpl/tx/invariants/MPTInvariant.cpp | 11 +++-- .../token/ConfidentialMPTConvert.cpp | 25 ++++++++-- .../token/ConfidentialMPTConvertBack.cpp | 26 ++++++++-- .../token/ConfidentialMPTMergeInbox.cpp | 9 +++- .../transactors/token/ConfidentialMPTSend.cpp | 49 ++++++++++++++++--- src/test/app/Invariants_test.cpp | 18 +++++++ 8 files changed, 126 insertions(+), 20 deletions(-) diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index 8acf3fe1c5..0d453eea11 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -207,8 +207,8 @@ TYPED_SFIELD(sfParentBatchID, UINT256, 36) TYPED_SFIELD(sfLoanBrokerID, UINT256, 37, SField::kSmdPseudoAccount | SField::kSmdDefault) TYPED_SFIELD(sfLoanID, UINT256, 38) -TYPED_SFIELD(sfBlindingFactor, UINT256, 39) -TYPED_SFIELD(sfReferenceHolding, UINT256, 40) +TYPED_SFIELD(sfReferenceHolding, UINT256, 39) +TYPED_SFIELD(sfBlindingFactor, UINT256, 40) // number (common) TYPED_SFIELD(sfNumber, NUMBER, 1) diff --git a/include/xrpl/tx/invariants/MPTInvariant.h b/include/xrpl/tx/invariants/MPTInvariant.h index 6585ac4f32..aa90f1b8ef 100644 --- a/include/xrpl/tx/invariants/MPTInvariant.h +++ b/include/xrpl/tx/invariants/MPTInvariant.h @@ -131,7 +131,9 @@ public: * lsfMPTCanHoldConfidentialBalance is set on the issuance. * - Encrypted field existence consistency: * If sfConfidentialBalanceSpending/sfConfidentialBalanceInbox exists, then - * sfIssuerEncryptedBalance must also exist (and vice versa). + * sfIssuerEncryptedBalance must also exist (and vice versa). If + * sfAuditorEncryptedBalance exists, then those core encrypted balance fields + * must also exist. * - COA <= OutstandingAmount: * Confidential outstanding balance cannot exceed total outstanding. * - Verifies sfConfidentialBalanceVersion is changed whenever sfConfidentialBalanceSpending is diff --git a/src/libxrpl/tx/invariants/MPTInvariant.cpp b/src/libxrpl/tx/invariants/MPTInvariant.cpp index 87f1e148b1..13057e4866 100644 --- a/src/libxrpl/tx/invariants/MPTInvariant.cpp +++ b/src/libxrpl/tx/invariants/MPTInvariant.cpp @@ -543,7 +543,8 @@ ValidConfidentialMPToken::visitEntry( bool const hasPublicBalance = before->getFieldU64(sfMPTAmount) > 0; bool const hasEncryptedFields = before->isFieldPresent(sfConfidentialBalanceSpending) || before->isFieldPresent(sfConfidentialBalanceInbox) || - before->isFieldPresent(sfIssuerEncryptedBalance); + before->isFieldPresent(sfIssuerEncryptedBalance) || + before->isFieldPresent(sfAuditorEncryptedBalance); if (hasPublicBalance || hasEncryptedFields) changes_[id].deletedWithEncrypted = true; @@ -561,10 +562,12 @@ ValidConfidentialMPToken::visitEntry( bool const hasIssuerBalance = after->isFieldPresent(sfIssuerEncryptedBalance); bool const hasHolderInbox = after->isFieldPresent(sfConfidentialBalanceInbox); bool const hasHolderSpending = after->isFieldPresent(sfConfidentialBalanceSpending); + bool const hasAuditorBalance = after->isFieldPresent(sfAuditorEncryptedBalance); - // sfIssuerEncryptedBalance, sfConfidentialBalanceInbox, and sfConfidentialBalanceSpending - // must all exist or not exist same time. - if (hasHolderInbox != hasHolderSpending || hasHolderInbox != hasIssuerBalance) + // The core encrypted balances must all exist or not exist at the same time. The auditor + // balance is optional, but cannot exist without the core fields. + if (hasHolderInbox != hasHolderSpending || hasHolderInbox != hasIssuerBalance || + (hasAuditorBalance && !hasIssuerBalance)) changes_[id].badConsistency = true; auto const confidentialBalanceFieldChanged = [&before, &after](auto const& field) { diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp index 4a87faa7f8..2a06648810 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -246,7 +247,13 @@ ConfidentialMPTConvert::doApply() { auto sum = homomorphicAdd(holderEc, (*sleMptoken)[sfConfidentialBalanceInbox]); if (!sum) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTConvert failed homomorphic add for holder inbox."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleMptoken)[sfConfidentialBalanceInbox] = std::move(*sum); } @@ -255,7 +262,13 @@ ConfidentialMPTConvert::doApply() { auto sum = homomorphicAdd(issuerEc, (*sleMptoken)[sfIssuerEncryptedBalance]); if (!sum) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTConvert failed homomorphic add for issuer balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleMptoken)[sfIssuerEncryptedBalance] = std::move(*sum); } @@ -268,7 +281,13 @@ ConfidentialMPTConvert::doApply() auto sum = homomorphicAdd(*auditorEc, (*sleMptoken)[sfAuditorEncryptedBalance]); if (!sum) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTConvert failed homomorphic add for auditor balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleMptoken)[sfAuditorEncryptedBalance] = std::move(*sum); } diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp index b05474c851..9443876ce9 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -245,7 +246,14 @@ ConfidentialMPTConvertBack::doApply() auto res = homomorphicSubtract( (*sleMptoken)[sfConfidentialBalanceSpending], ctx_.tx[sfHolderEncryptedAmount]); if (!res) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTConvertBack failed homomorphic subtract for holder spending " + "balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleMptoken)[sfConfidentialBalanceSpending] = std::move(*res); } @@ -255,7 +263,13 @@ ConfidentialMPTConvertBack::doApply() auto res = homomorphicSubtract( (*sleMptoken)[sfIssuerEncryptedBalance], ctx_.tx[sfIssuerEncryptedAmount]); if (!res) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTConvertBack failed homomorphic subtract for issuer balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleMptoken)[sfIssuerEncryptedBalance] = std::move(*res); } @@ -265,7 +279,13 @@ ConfidentialMPTConvertBack::doApply() auto res = homomorphicSubtract( (*sleMptoken)[sfAuditorEncryptedBalance], ctx_.tx[sfAuditorEncryptedAmount]); if (!res) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTConvertBack failed homomorphic subtract for auditor balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleMptoken)[sfAuditorEncryptedBalance] = std::move(*res); } diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp index ab9529942b..e6bc9b29a4 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -101,7 +102,13 @@ ConfidentialMPTMergeInbox::doApply() auto sum = homomorphicAdd( (*sleMptoken)[sfConfidentialBalanceSpending], (*sleMptoken)[sfConfidentialBalanceInbox]); if (!sum) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTMergeInbox failed homomorphic add for inbox merge."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleMptoken)[sfConfidentialBalanceSpending] = std::move(*sum); diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp index 336355a7ab..b6383e7ca4 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -306,7 +307,13 @@ ConfidentialMPTSend::doApply() auto const curSpending = (*sleSenderMPToken)[sfConfidentialBalanceSpending]; auto newSpending = homomorphicSubtract(curSpending, senderEc); if (!newSpending) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTSend failed homomorphic subtract for sender spending balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleSenderMPToken)[sfConfidentialBalanceSpending] = std::move(*newSpending); } @@ -316,7 +323,13 @@ ConfidentialMPTSend::doApply() auto const curIssuerEnc = (*sleSenderMPToken)[sfIssuerEncryptedBalance]; auto newIssuerEnc = homomorphicSubtract(curIssuerEnc, issuerEc); if (!newIssuerEnc) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTSend failed homomorphic subtract for sender issuer balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleSenderMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc); } @@ -327,7 +340,13 @@ ConfidentialMPTSend::doApply() auto const curAuditorEnc = (*sleSenderMPToken)[sfAuditorEncryptedBalance]; auto newAuditorEnc = homomorphicSubtract(curAuditorEnc, *auditorEc); if (!newAuditorEnc) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTSend failed homomorphic subtract for sender auditor balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleSenderMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc); } @@ -342,7 +361,13 @@ ConfidentialMPTSend::doApply() auto const curInbox = (*sleDestinationMPToken)[sfConfidentialBalanceInbox]; auto newInbox = homomorphicAdd(curInbox, *rerandomizedDestEc); if (!newInbox) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTSend failed homomorphic add for destination inbox."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleDestinationMPToken)[sfConfidentialBalanceInbox] = std::move(*newInbox); } @@ -357,7 +382,13 @@ ConfidentialMPTSend::doApply() auto const curIssuerEnc = (*sleDestinationMPToken)[sfIssuerEncryptedBalance]; auto newIssuerEnc = homomorphicAdd(curIssuerEnc, *rerandomizedIssuerEc); if (!newIssuerEnc) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTSend failed homomorphic add for destination issuer balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleDestinationMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc); } @@ -373,7 +404,13 @@ ConfidentialMPTSend::doApply() auto const curAuditorEnc = (*sleDestinationMPToken)[sfAuditorEncryptedBalance]; auto newAuditorEnc = homomorphicAdd(curAuditorEnc, *rerandomizedAuditorEc); if (!newAuditorEnc) - return tecINTERNAL; // LCOV_EXCL_LINE + { + // LCOV_EXCL_START + JLOG(ctx_.journal.error()) + << "ConfidentialMPTSend failed homomorphic add for destination auditor balance."; + return tecINTERNAL; + // LCOV_EXCL_STOP + } (*sleDestinationMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc); } diff --git a/src/test/app/Invariants_test.cpp b/src/test/app/Invariants_test.cpp index 46ec3de8f7..593a344bdd 100644 --- a/src/test/app/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -5029,6 +5029,24 @@ class Invariants_test : public beast::unit_test::Suite {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, precloseConfidential); + doInvariantCheck( + {"MPToken encrypted field existence inconsistency"}, + [&mptID](Account const& a1, Account const& a2, ApplyContext& ac) { + auto sleToken = ac.view().peek(keylet::mptoken(mptID, a2.id())); + if (!sleToken) + return false; + sleToken->makeFieldAbsent(sfIssuerEncryptedBalance); + sleToken->makeFieldAbsent(sfConfidentialBalanceInbox); + sleToken->makeFieldAbsent(sfConfidentialBalanceSpending); + sleToken->setFieldVL(sfAuditorEncryptedBalance, Blob{0x00}); + ac.view().update(sleToken); + return true; + }, + XRPAmount{}, + STTx{ttMPTOKEN_AUTHORIZE, [](STObject&) {}}, + {tecINVARIANT_FAILED, tecINVARIANT_FAILED}, + precloseConfidential); + // requiresPrivacyFlag auto const precloseNoPrivacy = [&mptID]( Account const& a1, Account const& a2, Env& env) -> bool {