diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index 64201881b07..c6742c6acbc 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -342,9 +342,10 @@ enum TECcodes : TERUnderlyingType { tecLIMIT_EXCEEDED = 195, tecPSEUDO_ACCOUNT = 196, tecPRECISION_LOSS = 197, - // DEPRECATED: This error code tecNO_DELEGATE_PERMISSION is reserved for - // backward compatibility with historical data on non-prod networks, can be - // reclaimed after those networks reset. + // DEPRECATED: tecNO_DELEGATE_PERMISSION is reserved for backward + // compatibility with historical data on non-prod networks only. + // TODO(deprecation): Remove this entry and reclaim value 198 once all + // non-prod networks that recorded this code have been reset. tecNO_DELEGATE_PERMISSION = 198, }; diff --git a/src/libxrpl/protocol/Permissions.cpp b/src/libxrpl/protocol/Permissions.cpp index 47fc0d28b6c..686b6376c1c 100644 --- a/src/libxrpl/protocol/Permissions.cpp +++ b/src/libxrpl/protocol/Permissions.cpp @@ -67,6 +67,11 @@ Permission::Permission() #pragma pop_macro("PERMISSION") }; + XRPL_ASSERT( + txFeatureMap_.size() == delegableTx_.size(), + "xrpl::Permission : txFeatureMap_ and delegableTx_ must have same " + "size"); + for ([[maybe_unused]] auto const& permission : granularPermissionMap_) { XRPL_ASSERT( diff --git a/src/libxrpl/tx/transactors/delegate/DelegateUtils.cpp b/src/libxrpl/tx/transactors/delegate/DelegateUtils.cpp index d9d74a1212c..38f02593865 100644 --- a/src/libxrpl/tx/transactors/delegate/DelegateUtils.cpp +++ b/src/libxrpl/tx/transactors/delegate/DelegateUtils.cpp @@ -6,7 +6,7 @@ NotTEC checkTxPermission(std::shared_ptr const& delegate, STTx const& tx) { if (!delegate) - return terNO_DELEGATE_PERMISSION; // LCOV_EXCL_LINE + return terNO_DELEGATE_PERMISSION; auto const permissionArray = delegate->getFieldArray(sfPermissions); auto const txPermission = tx.getTxnType() + 1; @@ -28,7 +28,7 @@ loadGranularPermission( std::unordered_set& granularPermissions) { if (!delegate) - return; // LCOV_EXCL_LINE + return; auto const permissionArray = delegate->getFieldArray(sfPermissions); for (auto const& permission : permissionArray) diff --git a/src/libxrpl/tx/transactors/payment/Payment.cpp b/src/libxrpl/tx/transactors/payment/Payment.cpp index 5f2a78917cf..27c54b8323a 100644 --- a/src/libxrpl/tx/transactors/payment/Payment.cpp +++ b/src/libxrpl/tx/transactors/payment/Payment.cpp @@ -252,6 +252,7 @@ Payment::checkPermission(ReadView const& view, STTx const& tx) tx.isFieldPresent(sfPaths)) return terNO_DELEGATE_PERMISSION; + // PaymentMint and PaymentBurn apply to both IOU and MPT direct payments. if (granularPermissions.contains(PaymentMint) && !isXRP(amountAsset) && amountAsset.getIssuer() == tx[sfAccount]) return tesSUCCESS; diff --git a/src/test/app/Batch_test.cpp b/src/test/app/Batch_test.cpp index adc36e4340f..e2d109a65e9 100644 --- a/src/test/app/Batch_test.cpp +++ b/src/test/app/Batch_test.cpp @@ -4154,8 +4154,12 @@ class Batch_test : public beast::unit_test::suite std::vector testCases = { {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, {1, "TrustSet", "tesSUCCESS", txIDs[0], batchID}, + // jv2 fails with terNO_DELEGATE_PERMISSION. }; validateClosedLedger(env, testCases); + + // verify jv2 is not present in the closed ledger. + BEAST_EXPECT(env.rpc("tx", txIDs[1])[jss::result][jss::error] == "txnNotFound"); } } diff --git a/src/test/app/Delegate_test.cpp b/src/test/app/Delegate_test.cpp index 2618a95d0d0..8e3e26679ed 100644 --- a/src/test/app/Delegate_test.cpp +++ b/src/test/app/Delegate_test.cpp @@ -4,6 +4,7 @@ #include #include +#include namespace xrpl { namespace test { @@ -1721,6 +1722,21 @@ class Delegate_test : public beast::unit_test::suite "\n Action: Verify security requirements to interact with Delegation feature"); } + void + testDelegateUtilsNullptrCheck() + { + testcase("DelegateUtils nullptr check"); + + // checkTxPermission nullptr check + STTx const tx{ttPAYMENT, [](STObject&) {}}; + BEAST_EXPECT(checkTxPermission(nullptr, tx) == terNO_DELEGATE_PERMISSION); + + // loadGranularPermission nullptr check + std::unordered_set granularPermissions; + loadGranularPermission(nullptr, ttPAYMENT, granularPermissions); + BEAST_EXPECT(granularPermissions.empty()); + } + void run() override { @@ -1746,6 +1762,7 @@ class Delegate_test : public beast::unit_test::suite testPermissionValue(all); testTxRequireFeatures(all); testTxDelegableCount(); + testDelegateUtilsNullptrCheck(); } }; BEAST_DEFINE_TESTSUITE(Delegate, app, xrpl);