mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
Compare commits
4 Commits
a1q123456/
...
Bronek/for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3f4720091 | ||
|
|
0dc4c452f1 | ||
|
|
b96abfc230 | ||
|
|
f7720b08ec |
@@ -48,14 +48,6 @@ class STObject;
|
|||||||
class STAmount;
|
class STAmount;
|
||||||
class Rules;
|
class Rules;
|
||||||
|
|
||||||
/** Calculate AMM account ID.
|
|
||||||
*/
|
|
||||||
AccountID
|
|
||||||
ammAccountID(
|
|
||||||
std::uint16_t prefix,
|
|
||||||
uint256 const& parentHash,
|
|
||||||
uint256 const& ammID);
|
|
||||||
|
|
||||||
/** Calculate Liquidity Provider Token (LPT) Currency.
|
/** Calculate Liquidity Provider Token (LPT) Currency.
|
||||||
*/
|
*/
|
||||||
Currency
|
Currency
|
||||||
|
|||||||
@@ -225,6 +225,8 @@ enum TERcodes : TERUnderlyingType {
|
|||||||
terQUEUED, // Transaction is being held in TxQ until fee drops
|
terQUEUED, // Transaction is being held in TxQ until fee drops
|
||||||
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
||||||
terNO_AMM, // AMM doesn't exist for the asset pair
|
terNO_AMM, // AMM doesn't exist for the asset pair
|
||||||
|
terADDRESS_COLLISION, // Failed to allocate AccountID when trying to
|
||||||
|
// create a pseudo-account
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
// in include/xrpl/protocol/Feature.h.
|
// in include/xrpl/protocol/Feature.h.
|
||||||
|
|
||||||
// Check flags in Credential transactions
|
// Check flags in Credential transactions
|
||||||
|
XRPL_FIX (PseudoAccount, Supported::yes, VoteBehavior::DefaultNo)
|
||||||
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
|
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
|
||||||
XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo)
|
XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo)
|
||||||
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)
|
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)
|
||||||
|
|||||||
@@ -39,18 +39,6 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
AccountID
|
|
||||||
ammAccountID(
|
|
||||||
std::uint16_t prefix,
|
|
||||||
uint256 const& parentHash,
|
|
||||||
uint256 const& ammID)
|
|
||||||
{
|
|
||||||
ripesha_hasher rsh;
|
|
||||||
auto const hash = sha512Half(prefix, parentHash, ammID);
|
|
||||||
rsh(hash.data(), hash.size());
|
|
||||||
return AccountID{static_cast<ripesha_hasher::result_type>(rsh)};
|
|
||||||
}
|
|
||||||
|
|
||||||
Currency
|
Currency
|
||||||
ammLPTCurrency(Currency const& cur1, Currency const& cur2)
|
ammLPTCurrency(Currency const& cur1, Currency const& cur2)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ transResults()
|
|||||||
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
|
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
|
||||||
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
|
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
|
||||||
MAKE_ERROR(terNO_AMM, "AMM doesn't exist for the asset pair."),
|
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."),
|
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,6 +59,17 @@ private:
|
|||||||
XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0}));
|
XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// XRP to IOU, without fixPseudoAccount
|
||||||
|
testAMM(
|
||||||
|
[&](AMM& ammAlice, Env&) {
|
||||||
|
BEAST_EXPECT(ammAlice.expectBalances(
|
||||||
|
XRP(10'000), USD(10'000), IOUAmount{10'000'000, 0}));
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
0,
|
||||||
|
{},
|
||||||
|
{supported_amendments() - fixPseudoAccount});
|
||||||
|
|
||||||
// IOU to IOU
|
// IOU to IOU
|
||||||
testAMM(
|
testAMM(
|
||||||
[&](AMM& ammAlice, Env&) {
|
[&](AMM& ammAlice, Env&) {
|
||||||
|
|||||||
@@ -827,6 +827,74 @@ class Invariants_test : public beast::unit_test::suite
|
|||||||
},
|
},
|
||||||
XRPAmount{},
|
XRPAmount{},
|
||||||
STTx{ttPAYMENT, [](STObject& tx) {}});
|
STTx{ttPAYMENT, [](STObject& tx) {}});
|
||||||
|
|
||||||
|
doInvariantCheck(
|
||||||
|
{{"pseudo-account created by a wrong transaction type"}},
|
||||||
|
[](Account const&, Account const&, ApplyContext& ac) {
|
||||||
|
Account const A3{"A3"};
|
||||||
|
Keylet const acctKeylet = keylet::account(A3);
|
||||||
|
auto const sleNew = std::make_shared<SLE>(acctKeylet);
|
||||||
|
sleNew->setFieldU32(sfSequence, 0);
|
||||||
|
sleNew->setFieldH256(sfAMMID, uint256(1));
|
||||||
|
sleNew->setFieldU32(
|
||||||
|
sfFlags,
|
||||||
|
lsfDisableMaster | lsfDefaultRipple | lsfDefaultRipple);
|
||||||
|
ac.view().insert(sleNew);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
XRPAmount{},
|
||||||
|
STTx{ttPAYMENT, [](STObject& tx) {}});
|
||||||
|
|
||||||
|
doInvariantCheck(
|
||||||
|
{{"account created with wrong starting sequence number"}},
|
||||||
|
[](Account const&, Account const&, ApplyContext& ac) {
|
||||||
|
Account const A3{"A3"};
|
||||||
|
Keylet const acctKeylet = keylet::account(A3);
|
||||||
|
auto const sleNew = std::make_shared<SLE>(acctKeylet);
|
||||||
|
sleNew->setFieldU32(sfSequence, ac.view().seq());
|
||||||
|
sleNew->setFieldH256(sfAMMID, uint256(1));
|
||||||
|
sleNew->setFieldU32(
|
||||||
|
sfFlags,
|
||||||
|
lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
|
||||||
|
ac.view().insert(sleNew);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
XRPAmount{},
|
||||||
|
STTx{ttAMM_CREATE, [](STObject& tx) {}});
|
||||||
|
|
||||||
|
doInvariantCheck(
|
||||||
|
{{"pseudo-account created with wrong flags"}},
|
||||||
|
[](Account const&, Account const&, ApplyContext& ac) {
|
||||||
|
Account const A3{"A3"};
|
||||||
|
Keylet const acctKeylet = keylet::account(A3);
|
||||||
|
auto const sleNew = std::make_shared<SLE>(acctKeylet);
|
||||||
|
sleNew->setFieldU32(sfSequence, 0);
|
||||||
|
sleNew->setFieldH256(sfAMMID, uint256(1));
|
||||||
|
sleNew->setFieldU32(
|
||||||
|
sfFlags, lsfDisableMaster | lsfDefaultRipple);
|
||||||
|
ac.view().insert(sleNew);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
XRPAmount{},
|
||||||
|
STTx{ttAMM_CREATE, [](STObject& tx) {}});
|
||||||
|
|
||||||
|
doInvariantCheck(
|
||||||
|
{{"pseudo-account created with wrong flags"}},
|
||||||
|
[](Account const&, Account const&, ApplyContext& ac) {
|
||||||
|
Account const A3{"A3"};
|
||||||
|
Keylet const acctKeylet = keylet::account(A3);
|
||||||
|
auto const sleNew = std::make_shared<SLE>(acctKeylet);
|
||||||
|
sleNew->setFieldU32(sfSequence, 0);
|
||||||
|
sleNew->setFieldH256(sfAMMID, uint256(1));
|
||||||
|
sleNew->setFieldU32(
|
||||||
|
sfFlags,
|
||||||
|
lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth |
|
||||||
|
lsfRequireDestTag);
|
||||||
|
ac.view().insert(sleNew);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
XRPAmount{},
|
||||||
|
STTx{ttAMM_CREATE, [](STObject& tx) {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -219,64 +219,36 @@ applyCreate(
|
|||||||
auto const ammKeylet = keylet::amm(amount.issue(), amount2.issue());
|
auto const ammKeylet = keylet::amm(amount.issue(), amount2.issue());
|
||||||
|
|
||||||
// Mitigate same account exists possibility
|
// Mitigate same account exists possibility
|
||||||
auto const ammAccount = [&]() -> Expected<AccountID, TER> {
|
auto const maybeAccount = createPseudoAccount(sb, ammKeylet.key);
|
||||||
std::uint16_t constexpr maxAccountAttempts = 256;
|
|
||||||
for (auto p = 0; p < maxAccountAttempts; ++p)
|
|
||||||
{
|
|
||||||
auto const ammAccount =
|
|
||||||
ammAccountID(p, sb.info().parentHash, ammKeylet.key);
|
|
||||||
if (!sb.read(keylet::account(ammAccount)))
|
|
||||||
return ammAccount;
|
|
||||||
}
|
|
||||||
return Unexpected(tecDUPLICATE);
|
|
||||||
}();
|
|
||||||
|
|
||||||
// AMM account already exists (should not happen)
|
// AMM account already exists (should not happen)
|
||||||
if (!ammAccount)
|
if (!maybeAccount)
|
||||||
{
|
{
|
||||||
JLOG(j_.error()) << "AMM Instance: AMM already exists.";
|
JLOG(j_.error()) << "AMM Instance: failed to create pseudo account.";
|
||||||
return {ammAccount.error(), false};
|
return {maybeAccount.error(), false};
|
||||||
}
|
}
|
||||||
|
auto const accountId = (**maybeAccount)[sfAccount];
|
||||||
|
|
||||||
// LP Token already exists. (should not happen)
|
// LP Token already exists. (should not happen)
|
||||||
auto const lptIss = ammLPTIssue(
|
auto const lptIss = ammLPTIssue(
|
||||||
amount.issue().currency, amount2.issue().currency, *ammAccount);
|
amount.issue().currency, amount2.issue().currency, accountId);
|
||||||
if (sb.read(keylet::line(*ammAccount, lptIss)))
|
if (sb.read(keylet::line(accountId, lptIss)))
|
||||||
{
|
{
|
||||||
JLOG(j_.error()) << "AMM Instance: LP Token already exists.";
|
JLOG(j_.error()) << "AMM Instance: LP Token already exists.";
|
||||||
return {tecDUPLICATE, false};
|
return {tecDUPLICATE, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create AMM Root Account.
|
|
||||||
auto sleAMMRoot = std::make_shared<SLE>(keylet::account(*ammAccount));
|
|
||||||
sleAMMRoot->setAccountID(sfAccount, *ammAccount);
|
|
||||||
sleAMMRoot->setFieldAmount(sfBalance, STAmount{});
|
|
||||||
std::uint32_t const seqno{
|
|
||||||
ctx_.view().rules().enabled(featureDeletableAccounts)
|
|
||||||
? ctx_.view().seq()
|
|
||||||
: 1};
|
|
||||||
sleAMMRoot->setFieldU32(sfSequence, seqno);
|
|
||||||
// Ignore reserves requirement, disable the master key, allow default
|
|
||||||
// rippling (AMM LPToken can be used in payments and offer crossing but
|
|
||||||
// not as a token in another AMM), and enable deposit authorization to
|
|
||||||
// prevent payments into AMM.
|
|
||||||
// Note, that the trustlines created by AMM have 0 credit limit.
|
// Note, that the trustlines created by AMM have 0 credit limit.
|
||||||
// This prevents shifting the balance between accounts via AMM,
|
// This prevents shifting the balance between accounts via AMM,
|
||||||
// or sending unsolicited LPTokens. This is a desired behavior.
|
// or sending unsolicited LPTokens. This is a desired behavior.
|
||||||
// A user can only receive LPTokens through affirmative action -
|
// A user can only receive LPTokens through affirmative action -
|
||||||
// either an AMMDeposit, TrustSet, crossing an offer, etc.
|
// either an AMMDeposit, TrustSet, crossing an offer, etc.
|
||||||
sleAMMRoot->setFieldU32(
|
|
||||||
sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
|
|
||||||
// Link the root account and AMM object
|
|
||||||
sleAMMRoot->setFieldH256(sfAMMID, ammKeylet.key);
|
|
||||||
sb.insert(sleAMMRoot);
|
|
||||||
|
|
||||||
// Calculate initial LPT balance.
|
// Calculate initial LPT balance.
|
||||||
auto const lpTokens = ammLPTokens(amount, amount2, lptIss);
|
auto const lpTokens = ammLPTokens(amount, amount2, lptIss);
|
||||||
|
|
||||||
// Create ltAMM
|
// Create ltAMM
|
||||||
auto ammSle = std::make_shared<SLE>(ammKeylet);
|
auto ammSle = std::make_shared<SLE>(ammKeylet);
|
||||||
ammSle->setAccountID(sfAccount, *ammAccount);
|
ammSle->setAccountID(sfAccount, accountId);
|
||||||
ammSle->setFieldAmount(sfLPTokenBalance, lpTokens);
|
ammSle->setFieldAmount(sfLPTokenBalance, lpTokens);
|
||||||
auto const& [issue1, issue2] = std::minmax(amount.issue(), amount2.issue());
|
auto const& [issue1, issue2] = std::minmax(amount.issue(), amount2.issue());
|
||||||
ammSle->setFieldIssue(sfAsset, STIssue{sfAsset, issue1});
|
ammSle->setFieldIssue(sfAsset, STIssue{sfAsset, issue1});
|
||||||
@@ -287,9 +259,9 @@ applyCreate(
|
|||||||
|
|
||||||
// Add owner directory to link the root account and AMM object.
|
// Add owner directory to link the root account and AMM object.
|
||||||
if (auto const page = sb.dirInsert(
|
if (auto const page = sb.dirInsert(
|
||||||
keylet::ownerDir(*ammAccount),
|
keylet::ownerDir(accountId),
|
||||||
ammSle->key(),
|
ammSle->key(),
|
||||||
describeOwnerDir(*ammAccount)))
|
describeOwnerDir(accountId)))
|
||||||
{
|
{
|
||||||
ammSle->setFieldU64(sfOwnerNode, *page);
|
ammSle->setFieldU64(sfOwnerNode, *page);
|
||||||
}
|
}
|
||||||
@@ -301,7 +273,7 @@ applyCreate(
|
|||||||
sb.insert(ammSle);
|
sb.insert(ammSle);
|
||||||
|
|
||||||
// Send LPT to LP.
|
// Send LPT to LP.
|
||||||
auto res = accountSend(sb, *ammAccount, account_, lpTokens, ctx_.journal);
|
auto res = accountSend(sb, accountId, account_, lpTokens, ctx_.journal);
|
||||||
if (res != tesSUCCESS)
|
if (res != tesSUCCESS)
|
||||||
{
|
{
|
||||||
JLOG(j_.debug()) << "AMM Instance: failed to send LPT " << lpTokens;
|
JLOG(j_.debug()) << "AMM Instance: failed to send LPT " << lpTokens;
|
||||||
@@ -312,7 +284,7 @@ applyCreate(
|
|||||||
if (auto const res = accountSend(
|
if (auto const res = accountSend(
|
||||||
sb,
|
sb,
|
||||||
account_,
|
account_,
|
||||||
*ammAccount,
|
accountId,
|
||||||
amount,
|
amount,
|
||||||
ctx_.journal,
|
ctx_.journal,
|
||||||
WaiveTransferFee::Yes))
|
WaiveTransferFee::Yes))
|
||||||
@@ -321,7 +293,7 @@ applyCreate(
|
|||||||
if (!isXRP(amount))
|
if (!isXRP(amount))
|
||||||
{
|
{
|
||||||
if (SLE::pointer sleRippleState =
|
if (SLE::pointer sleRippleState =
|
||||||
sb.peek(keylet::line(*ammAccount, amount.issue()));
|
sb.peek(keylet::line(accountId, amount.issue()));
|
||||||
!sleRippleState)
|
!sleRippleState)
|
||||||
return tecINTERNAL;
|
return tecINTERNAL;
|
||||||
else
|
else
|
||||||
@@ -350,7 +322,7 @@ applyCreate(
|
|||||||
return {res, false};
|
return {res, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
JLOG(j_.debug()) << "AMM Instance: success " << *ammAccount << " "
|
JLOG(j_.debug()) << "AMM Instance: success " << accountId << " "
|
||||||
<< ammKeylet.key << " " << lpTokens << " " << amount << " "
|
<< ammKeylet.key << " " << lpTokens << " " << amount << " "
|
||||||
<< amount2;
|
<< amount2;
|
||||||
auto addOrderBook =
|
auto addOrderBook =
|
||||||
|
|||||||
@@ -882,6 +882,8 @@ ValidNewAccountRoot::visitEntry(
|
|||||||
{
|
{
|
||||||
accountsCreated_++;
|
accountsCreated_++;
|
||||||
accountSeq_ = (*after)[sfSequence];
|
accountSeq_ = (*after)[sfSequence];
|
||||||
|
pseudoAccount_ = after->isFieldPresent(sfAMMID);
|
||||||
|
flags_ = after->getFlags();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,8 +911,22 @@ ValidNewAccountRoot::finalize(
|
|||||||
tx.getTxnType() == ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION) &&
|
tx.getTxnType() == ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION) &&
|
||||||
result == tesSUCCESS)
|
result == tesSUCCESS)
|
||||||
{
|
{
|
||||||
std::uint32_t const startingSeq{
|
bool const pseudoAccount =
|
||||||
view.rules().enabled(featureDeletableAccounts) ? view.seq() : 1};
|
(pseudoAccount_ && view.rules().enabled(fixPseudoAccount));
|
||||||
|
|
||||||
|
if (pseudoAccount && tx.getTxnType() != ttAMM_CREATE)
|
||||||
|
{
|
||||||
|
JLOG(j.fatal()) << "Invariant failed: pseudo-account created by a "
|
||||||
|
"wrong transaction type";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t const startingSeq = //
|
||||||
|
pseudoAccount //
|
||||||
|
? 0 //
|
||||||
|
: view.rules().enabled(featureDeletableAccounts) //
|
||||||
|
? view.seq() //
|
||||||
|
: 1;
|
||||||
|
|
||||||
if (accountSeq_ != startingSeq)
|
if (accountSeq_ != startingSeq)
|
||||||
{
|
{
|
||||||
@@ -918,6 +934,20 @@ ValidNewAccountRoot::finalize(
|
|||||||
"wrong starting sequence number";
|
"wrong starting sequence number";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pseudoAccount)
|
||||||
|
{
|
||||||
|
std::uint32_t const expected =
|
||||||
|
(lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
|
||||||
|
if (flags_ != expected)
|
||||||
|
{
|
||||||
|
JLOG(j.fatal())
|
||||||
|
<< "Invariant failed: pseudo-account created with "
|
||||||
|
"wrong flags";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -438,6 +438,8 @@ class ValidNewAccountRoot
|
|||||||
{
|
{
|
||||||
std::uint32_t accountsCreated_ = 0;
|
std::uint32_t accountsCreated_ = 0;
|
||||||
std::uint32_t accountSeq_ = 0;
|
std::uint32_t accountSeq_ = 0;
|
||||||
|
bool pseudoAccount_ = false;
|
||||||
|
std::uint32_t flags_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -430,6 +430,11 @@ dirNext(
|
|||||||
[[nodiscard]] std::function<void(SLE::ref)>
|
[[nodiscard]] std::function<void(SLE::ref)>
|
||||||
describeOwnerDir(AccountID const& account);
|
describeOwnerDir(AccountID const& account);
|
||||||
|
|
||||||
|
/** Create a pseudo-account
|
||||||
|
*/
|
||||||
|
[[nodiscard]] Expected<std::shared_ptr<SLE>, TER>
|
||||||
|
createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey);
|
||||||
|
|
||||||
// VFALCO NOTE Both STAmount parameters should just
|
// VFALCO NOTE Both STAmount parameters should just
|
||||||
// be "Amount", a unit-less number.
|
// be "Amount", a unit-less number.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Protocol.h>
|
#include <xrpl/protocol/Protocol.h>
|
||||||
#include <xrpl/protocol/Quality.h>
|
#include <xrpl/protocol/Quality.h>
|
||||||
|
#include <xrpl/protocol/digest.h>
|
||||||
#include <xrpl/protocol/st.h>
|
#include <xrpl/protocol/st.h>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -929,6 +930,62 @@ describeOwnerDir(AccountID const& account)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expected<std::shared_ptr<SLE>, TER>
|
||||||
|
createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (accountId == beast::zero)
|
||||||
|
{
|
||||||
|
TER const code = view.rules().enabled(fixPseudoAccount) && view.open()
|
||||||
|
? TER(terADDRESS_COLLISION)
|
||||||
|
: TER(tecDUPLICATE);
|
||||||
|
return Unexpected(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create pseudo-account.
|
||||||
|
auto account = std::make_shared<SLE>(keylet::account(accountId));
|
||||||
|
account->setAccountID(sfAccount, accountId);
|
||||||
|
account->setFieldAmount(sfBalance, STAmount{});
|
||||||
|
|
||||||
|
// Pseudo-accounts can't submit transactions, so set the sequence number
|
||||||
|
// to 0 to make them easier to spot and verify, and add an extra level
|
||||||
|
// of protection.
|
||||||
|
std::uint32_t const seqno = //
|
||||||
|
view.rules().enabled(fixPseudoAccount) //
|
||||||
|
? 0 //
|
||||||
|
: view.rules().enabled(featureDeletableAccounts) //
|
||||||
|
? view.seq() //
|
||||||
|
: 1;
|
||||||
|
account->setFieldU32(sfSequence, seqno);
|
||||||
|
// Ignore reserves requirement, disable the master key, allow default
|
||||||
|
// rippling, and enable deposit authorization to prevent payments into
|
||||||
|
// pseudo-account.
|
||||||
|
account->setFieldU32(
|
||||||
|
sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
|
||||||
|
// Link the root account and AMM object
|
||||||
|
account->setFieldH256(sfAMMID, pseudoOwnerKey);
|
||||||
|
|
||||||
|
view.insert(account);
|
||||||
|
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
TER
|
TER
|
||||||
trustCreate(
|
trustCreate(
|
||||||
ApplyView& view,
|
ApplyView& view,
|
||||||
|
|||||||
Reference in New Issue
Block a user