mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 22:30:57 +00:00
test: Re-home the credential pin tests into the vault bug suite
develop split Vault_test.cpp into topical suites under src/test/app/vault/, which removed the file these two regression tests lived in. They cover a bug, so they follow the neighbouring bug tests into VaultBugs_test.cpp; the suite's includes grow to cover ownerCount, the credentials helpers, keylet::account and std::uint16_t, none of which the file used before.
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/CaptureLogs.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/credentials.h>
|
||||
#include <test/jtx/flags.h>
|
||||
#include <test/jtx/pay.h>
|
||||
#include <test/jtx/ter.h>
|
||||
@@ -15,6 +17,7 @@
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
@@ -22,6 +25,7 @@
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
@@ -792,6 +796,117 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testCredentialPinsPseudoAccount()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
|
||||
// A credential issued to a vault pseudo-account can't be accepted or
|
||||
// deleted by it (pseudo-accounts can't sign), so it stays pinned in the
|
||||
// pseudo-account's owner directory and blocks VaultDelete with
|
||||
// tecHAS_OBLIGATIONS. A pin created before the cure activates is removed
|
||||
// by VaultDelete once it does.
|
||||
Account const owner{"owner"};
|
||||
Account const attacker{"attacker"};
|
||||
char const credType[] = "FN36";
|
||||
|
||||
Env env{*this, all_ - fixCleanup3_3_0 - fixCleanup3_4_0};
|
||||
env.fund(XRP(1'000'000), owner, attacker);
|
||||
env.close();
|
||||
|
||||
Vault const vault{env};
|
||||
PrettyAsset const asset = xrpIssue();
|
||||
auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
auto const vaultSle = env.le(keylet);
|
||||
BEAST_EXPECT(vaultSle);
|
||||
Account const pseudo{"vault pseudo-account", vaultSle->at(sfAccount)};
|
||||
env.memoize(pseudo);
|
||||
|
||||
// The pseudo-account owns the share issuance; the pin must not change
|
||||
// its owner count (an unaccepted credential is owned by the issuer).
|
||||
auto const pseudoOwnerCount = ownerCount(env, pseudo);
|
||||
|
||||
testcase("Credential pins vault pseudo-account");
|
||||
env(credentials::create(pseudo, attacker, credType));
|
||||
env.close();
|
||||
|
||||
auto const credKey = credentials::keylet(pseudo, attacker, credType);
|
||||
BEAST_EXPECT(env.le(credKey));
|
||||
BEAST_EXPECT(ownerCount(env, attacker) == 1);
|
||||
BEAST_EXPECT(ownerCount(env, pseudo) == pseudoOwnerCount);
|
||||
|
||||
// The pin blocks deletion of an otherwise-empty vault.
|
||||
env(vault.del({.owner = owner, .id = keylet.key}), Ter(tecHAS_OBLIGATIONS));
|
||||
env.close();
|
||||
|
||||
env.enableFeature(fixCleanup3_4_0);
|
||||
env.close();
|
||||
|
||||
// The pre-existing pin no longer blocks deletion; the credential is
|
||||
// cleaned up and the issuer's owner count is restored.
|
||||
testcase("VaultDelete removes pinned credential");
|
||||
env(vault.del({.owner = owner, .id = keylet.key}));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(!env.le(credKey));
|
||||
BEAST_EXPECT(!env.le(keylet));
|
||||
BEAST_EXPECT(!env.le(::xrpl::keylet::account(pseudo.id())));
|
||||
BEAST_EXPECT(ownerCount(env, attacker) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
testCredentialPinOverflow()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
testcase("Credential pin cleanup is bounded (tecINCOMPLETE)");
|
||||
|
||||
// A pseudo-account can be pinned with more credentials than one
|
||||
// transaction is allowed to clean up. VaultDelete then removes them a
|
||||
// bounded batch at a time, returning tecINCOMPLETE until the last batch.
|
||||
Account const owner{"owner"};
|
||||
Account const attacker{"attacker"};
|
||||
|
||||
Env env{*this, all_ - fixCleanup3_3_0 - fixCleanup3_4_0};
|
||||
env.fund(XRP(10'000'000), owner, attacker);
|
||||
env.close();
|
||||
|
||||
Vault const vault{env};
|
||||
auto [tx, keylet] = vault.create({.owner = owner, .asset = xrpIssue()});
|
||||
env(tx);
|
||||
env.close();
|
||||
auto const vaultSle = env.le(keylet);
|
||||
BEAST_EXPECT(vaultSle);
|
||||
Account const pseudo{"vault pseudo-account", vaultSle->at(sfAccount)};
|
||||
env.memoize(pseudo);
|
||||
|
||||
// Pin more than one cleanup batch's worth of credentials.
|
||||
std::uint16_t const count = kMaxDeletablePseudoAccountCredentials + 3;
|
||||
for (std::uint16_t i = 0; i < count; ++i)
|
||||
env(credentials::create(pseudo, attacker, std::to_string(i)));
|
||||
env.close();
|
||||
BEAST_EXPECT(ownerCount(env, attacker) == count);
|
||||
|
||||
env.enableFeature(fixCleanup3_4_0);
|
||||
env.close();
|
||||
|
||||
// First delete removes one bounded batch and reports it isn't finished.
|
||||
env(vault.del({.owner = owner, .id = keylet.key}), Ter(tecINCOMPLETE));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.le(keylet)); // vault still exists
|
||||
auto const remaining = ownerCount(env, attacker);
|
||||
BEAST_EXPECT(remaining > 0 && remaining < count);
|
||||
|
||||
// Second delete finishes the cleanup and removes the vault.
|
||||
env(vault.del({.owner = owner, .id = keylet.key}));
|
||||
env.close();
|
||||
BEAST_EXPECT(!env.le(keylet));
|
||||
BEAST_EXPECT(!env.le(::xrpl::keylet::account(pseudo.id())));
|
||||
BEAST_EXPECT(ownerCount(env, attacker) == 0);
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
@@ -804,6 +919,8 @@ public:
|
||||
testVaultWithdrawCanonicalizeToZero();
|
||||
testBugVaultDustDebitCanonicalizesToNoOp();
|
||||
testVaultDepositNegativeBalanceFromOppositeLimit();
|
||||
testCredentialPinsPseudoAccount();
|
||||
testCredentialPinOverflow();
|
||||
testBug6LimitBypassWithShares();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user