bool CreateAccountOpFrame::doApply(medida::MetricsRegistry& metrics, LedgerDelta& delta, LedgerManager& ledgerManager) { AccountFrame::pointer destAccount; Database& db = ledgerManager.getDatabase(); destAccount = AccountFrame::loadAccount(mCreateAccount.destination, db); if (!destAccount) { if (mCreateAccount.startingBalance < ledgerManager.getMinBalance(0)) { // not over the minBalance to make an account metrics.NewMeter({"op-create-account", "failure", "low-reserve"}, "operation").Mark(); innerResult().code(CREATE_ACCOUNT_LOW_RESERVE); return false; } else { int64_t minBalance = mSourceAccount->getMinimumBalance(ledgerManager); if (mSourceAccount->getAccount().balance < (minBalance + mCreateAccount.startingBalance)) { // they don't have enough to send metrics.NewMeter({"op-create-account", "failure", "underfunded"}, "operation").Mark(); innerResult().code(CREATE_ACCOUNT_UNDERFUNDED); return false; } mSourceAccount->getAccount().balance -= mCreateAccount.startingBalance; mSourceAccount->storeChange(delta, db); destAccount = make_shared<AccountFrame>(mCreateAccount.destination); destAccount->getAccount().seqNum = delta.getHeaderFrame().getStartingSequenceNumber(); destAccount->getAccount().balance = mCreateAccount.startingBalance; destAccount->storeAdd(delta, db); metrics.NewMeter({"op-create-account", "success", "apply"}, "operation").Mark(); innerResult().code(CREATE_ACCOUNT_SUCCESS); return true; } } else { metrics.NewMeter({"op-create-account", "failure", "already-exist"}, "operation").Mark(); innerResult().code(CREATE_ACCOUNT_ALREADY_EXIST); return false; } }
int64_t AccountFrame::getBalanceAboveReserve(LedgerManager const& lm) const { int64_t avail = getBalance() - lm.getMinBalance(mAccountEntry.numSubEntries); if (avail < 0) { // nothing can leave this account if below the reserve // (this can happen if the reserve is raised) avail = 0; } return avail; }
// returns true if successfully updated, // false if balance is not sufficient bool AccountFrame::addNumEntries(int count, LedgerManager const& lm) { int newEntriesCount = mAccountEntry.numSubEntries + count; if (newEntriesCount < 0) { throw std::runtime_error("invalid account state"); } if (getBalance() < lm.getMinBalance(newEntriesCount)) { // balance too low return false; } mAccountEntry.numSubEntries = newEntriesCount; return true; }
bool CreateAccountOpFrame::doApply(LedgerDelta& delta, LedgerManager& ledgerManager) { AccountFrame destAccount; Database& db = ledgerManager.getDatabase(); if (!AccountFrame::loadAccount(mCreateAccount.destination, destAccount, db)) { if (mCreateAccount.startingBalance < ledgerManager.getMinBalance(0)) { // not over the minBalance to make an account innerResult().code(CREATE_ACCOUNT_LOW_RESERVE); return false; } else { int64_t minBalance = mSourceAccount->getMinimumBalance(ledgerManager); if (mSourceAccount->getAccount().balance < (minBalance + mCreateAccount.startingBalance)) { // they don't have enough to send innerResult().code(CREATE_ACCOUNT_UNDERFUNDED); return false; } mSourceAccount->getAccount().balance -= mCreateAccount.startingBalance; mSourceAccount->storeChange(delta, db); destAccount.getAccount().accountID = mCreateAccount.destination; destAccount.getAccount().seqNum = delta.getHeaderFrame().getStartingSequenceNumber(); destAccount.getAccount().balance = mCreateAccount.startingBalance; destAccount.storeAdd(delta, db); innerResult().code(CREATE_ACCOUNT_SUCCESS); return true; } } else { innerResult().code(CREATE_ACCOUNT_ALREADY_EXIST); return false; } }
bool PaymentOpFrame::doApply(LedgerDelta& delta, LedgerManager& ledgerManager) { AccountFrame destAccount; // if sending to self directly, just mark as success if (mPayment.destination == getSourceID() && mPayment.path.empty()) { innerResult().code(PAYMENT_SUCCESS); return true; } Database& db = ledgerManager.getDatabase(); if (!AccountFrame::loadAccount(mPayment.destination, destAccount, db)) { // this tx is creating an account if (mPayment.currency.type() == CURRENCY_TYPE_NATIVE) { if (mPayment.amount < ledgerManager.getMinBalance(0)) { // not over the minBalance to make an account innerResult().code(PAYMENT_LOW_RESERVE); return false; } else { destAccount.getAccount().accountID = mPayment.destination; destAccount.getAccount().seqNum = delta.getHeaderFrame().getStartingSequenceNumber(); destAccount.getAccount().balance = 0; destAccount.storeAdd(delta, db); } } else { // trying to send credit to an unmade account innerResult().code(PAYMENT_NO_DESTINATION); return false; } } return sendNoCreate(destAccount, delta, ledgerManager); }
int64_t AccountFrame::getMinimumBalance(LedgerManager const& lm) const { return lm.getMinBalance(mAccountEntry.numSubEntries); }