Return terADDRESS_COLLISION from preclaim if cannot allocate AccountID

This commit is contained in:
Bronek Kozicki
2025-03-28 19:49:37 +00:00
parent f77ad36283
commit d3c1d02c72
5 changed files with 31 additions and 17 deletions

View File

@@ -225,6 +225,8 @@ enum TERcodes : TERUnderlyingType {
terQUEUED, // Transaction is being held in TxQ until fee drops
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
terNO_AMM, // AMM doesn't exist for the asset pair
terADDRESS_COLLISION, // Failed to allocate AccountID when trying to
// create a pseudo-account
};
//------------------------------------------------------------------------------

View File

@@ -231,6 +231,7 @@ transResults()
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
MAKE_ERROR(terNO_AMM, "AMM doesn't exist for the asset pair."),
MAKE_ERROR(terADDRESS_COLLISION, "Failed to allocate an unique account address"),
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
};

View File

@@ -119,6 +119,12 @@ VaultCreate::preclaim(PreclaimContext const& ctx)
return tecOBJECT_NOT_FOUND;
}
auto sequence = ctx.tx.getSeqValue();
if (auto const accountId = pseudoAccountAddress(
ctx.view, keylet::vault(account, sequence).key);
accountId == beast::zero)
return terADDRESS_COLLISION;
return tesSUCCESS;
}

View File

@@ -488,6 +488,9 @@ describeOwnerDir(AccountID const& account);
[[nodiscard]] TER
dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr<SLE>& object);
AccountID
pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey);
// Which of the owner-object fields should we set: sfAMMID, sfVaultID
enum class PseudoAccountOwnerType : int { AMM, Vault };

View File

@@ -1037,29 +1037,31 @@ dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr<SLE>& object)
return tesSUCCESS;
}
AccountID
pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey)
{
AccountID ret = beast::zero;
// This number must not be changed without an amendment
constexpr int maxAccountAttempts = 256;
for (auto i = 0; i < maxAccountAttempts; ++i)
{
ripesha_hasher rsh;
auto const hash = sha512Half(i, view.info().parentHash, pseudoOwnerKey);
rsh(hash.data(), hash.size());
ret = static_cast<ripesha_hasher::result_type>(rsh);
if (!view.read(keylet::account(ret)))
return ret;
}
return ret;
}
Expected<std::shared_ptr<SLE>, TER>
createPseudoAccount(
ApplyView& view,
uint256 const& pseudoOwnerKey,
PseudoAccountOwnerType type)
{
auto const accountId = [&]() -> AccountID {
AccountID ret = beast::zero;
// This number must not be changed without an amendment
constexpr int maxAccountAttempts = 256;
for (auto i = 0; i < maxAccountAttempts; ++i)
{
ripesha_hasher rsh;
auto const hash =
sha512Half(i, view.info().parentHash, pseudoOwnerKey);
rsh(hash.data(), hash.size());
ret = static_cast<ripesha_hasher::result_type>(rsh);
if (!view.read(keylet::account(ret)))
return ret;
}
return ret;
}();
auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey);
if (accountId == beast::zero)
return Unexpected(tecDUPLICATE);