From 399fd830d76c04b85ea94e8e0a57ac34c3452ccc Mon Sep 17 00:00:00 2001 From: Marko Mitic Date: Fri, 9 May 2014 19:20:17 +0200 Subject: [PATCH] AccountDeleteTransactor implemented. --- Builds/VisualStudio2013/RippleD.vcxproj | 3 + .../VisualStudio2013/RippleD.vcxproj.filters | 3 + src/ripple_app/ripple_app_pt9.cpp | 2 +- .../transactors/AccountDeleteTransactor.cpp | 210 ++++++++++++++++++ .../transactors/AccountDeleteTransactor.h | 2 +- src/ripple_data/protocol/TxFormats.cpp | 2 +- 6 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 src/ripple_app/transactors/AccountDeleteTransactor.cpp diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 523878d01..65c46d9ba 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -1308,6 +1308,9 @@ true true + + true + true true diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 734db10c2..c184436f5 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -1497,6 +1497,9 @@ [2] Old Ripple\ripple_app\transactors + + [2] Old Ripple\ripple_app\transactors + diff --git a/src/ripple_app/ripple_app_pt9.cpp b/src/ripple_app/ripple_app_pt9.cpp index 6ee215a48..d1afd48a6 100644 --- a/src/ripple_app/ripple_app_pt9.cpp +++ b/src/ripple_app/ripple_app_pt9.cpp @@ -28,7 +28,7 @@ #include "transactors/PaymentTransactor.cpp" #include "transactors/RegularKeySetTransactor.cpp" #include "transactors/AccountSetTransactor.cpp" -//#include "transactors/AccountDeleteTransactor.cpp" //TODO +#include "transactors/AccountDeleteTransactor.cpp" #include "transactors/WalletAddTransactor.cpp" #include "transactors/TrustSetTransactor.cpp" #include "transactors/InflationTransactor.cpp" diff --git a/src/ripple_app/transactors/AccountDeleteTransactor.cpp b/src/ripple_app/transactors/AccountDeleteTransactor.cpp new file mode 100644 index 000000000..dca53dd35 --- /dev/null +++ b/src/ripple_app/transactors/AccountDeleteTransactor.cpp @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { + +SETUP_LOG(AccountDeleteTransactor) + + +static void offerAdder(std::list& offersList, SLE::ref offer) +{ + if (offer->getType() == ltOFFER) + { + offersList.push_front(offer->getIndex()); + } +} + + +TER AccountDeleteTransactor::doApply () +{ + + WriteLog (lsINFO, AccountDeleteTransactor) << "AccountDelete>"; + + + if (!mSigMaster) + { + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Invalid: Not authorized to delete account."; + + return temBAD_AUTH_MASTER; + } + + if (!mTxn.isFieldPresent(sfDestination)) + { + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Malformed transaction: Destination is not set."; + + return temDST_NEEDED; + } + + const RippleAddress aDestination = mTxn.getFieldAccount(sfDestination); + const uint160 uDestinationID = aDestination.getAccountID(); + + if (uDestinationID == mTxnAccountID) + { + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Malformed transaction: Destination is source account."; + + return temDST_IS_SRC; + } + + + if (!mEngine->getLedger()->hasAccount(aDestination)) + { + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Malformed transaction: Destination account doesn't exist."; + + // TODO: allow sending to unexisting account? Should we crate new one? + return tecNO_DST; + } + + SLE::pointer sleDst = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(aDestination)); + + if ((sleDst->getFlags() & lsfRequireDestTag) && !mTxn.isFieldPresent(sfDestinationTag)) + { + WriteLog(lsINFO, AccountDeleteTransactor) << "Payment: Malformed transaction: DestinationTag required."; + + return tefDST_TAG_NEEDED; + } + + + /// Manage account IOUs + auto pAccItem = AccountItem::pointer(new RippleState()); + AccountItems stellarLines(mTxnAccountID, mEngine->getLedger(), pAccItem); + + // Don't delete account if if has outstanding IOUs + BOOST_FOREACH(AccountItem::ref item, stellarLines.getItems()) + { + RippleState* line = (RippleState*)item.get(); + + const STAmount& saBalance = line->getBalance(); + + if (saBalance.isNegative()){ + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Invalid: Not authorized to delete account."; + + return temBAD_AMOUNT; + } + + } + + auto lesNodes = mEngine->getNodes(); + + // Transfer IOUs + BOOST_FOREACH(AccountItem::ref item, stellarLines.getItems()) + { + RippleState* line = (RippleState*)item.get(); + SLE::pointer sleLine = line->getSLE(); + const STAmount& saBalance = line->getBalance(); + + if (saBalance.isPositive()) + { + const uint160 iouIssuerId = line->getAccountIDPeer(); + const uint160 uCurrencyId = saBalance.getCurrency(); + const uint256 uTrustLineIndex = Ledger::getRippleStateIndex(mTxnAccountID, iouIssuerId, uCurrencyId); + + + SLE::pointer sleDestinationTrustLine = mEngine->entryCache(ltRIPPLE_STATE, uTrustLineIndex); + + if (sleDestinationTrustLine) + { // trust line exists, increase balance + RippleState* destTrustLine = (RippleState*)pAccItem->makeItem(uDestinationID, sleDestinationTrustLine).get(); + + if (line->getAuthPeer() == true && destTrustLine->getAuthPeer() == false) + { + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Invalid: Destination not authorized to hold IOUs."; + + //TODO right return code? + return terNO_AUTH; + } + + const STAmount& destBalance = sleDestinationTrustLine->getFieldAmount(sfBalance); + + sleDestinationTrustLine->setFieldAmount(sfBalance, destBalance + saBalance); + mEngine->entryModify(sleDestinationTrustLine); + + } + else + { // create new trustline with no trust and set balance + + const bool bHigh = uDestinationID > iouIssuerId; + const STAmount trustAmount{ uCurrencyId, uDestinationID, 0 }; // Don't set trust for (unassuming) destination + + lesNodes.trustCreate(bHigh, + uDestinationID, + iouIssuerId, + uTrustLineIndex, + sleDst, + false, + false, + saBalance, + trustAmount); + + } + } + + uint160 uAccountID = sleLine->getFirstOwner().getAccountID(); + uint160 uAccountPeerID = sleLine->getSecondOwner().getAccountID(); + + uint160& uHighAccountID = uAccountID > uAccountPeerID ? uAccountID : uAccountPeerID; + uint160& uLowAccountID = uAccountID < uAccountPeerID ? uAccountID : uAccountPeerID; + + + TER terResult = lesNodes.trustDelete(sleLine, uLowAccountID, uHighAccountID); + + if (terResult != tesSUCCESS){ + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Deleting trust line failed: " << transHuman(terResult); + } + + } + + + mEngine->entryModify(sleDst); + + + + // Transfer stellars + + STAmount saMoveBalance = mSourceBalance; + mSourceBalance.zero(); + mTxnAccount->setFieldAmount(sfBalance, mSourceBalance); + sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saMoveBalance); + + assert(mTxnAccount->getFieldAmount(sfBalance).isZero() == true); + + + // Delete account offers + + std::list offersList; + + mEngine->getLedger()->visitAccountItems(mTxnAccountID, BIND_TYPE(&offerAdder, boost::ref(offersList), P_1)); + + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Deleting " << offersList.size() << " account offers"; + + BOOST_FOREACH(const uint256 offerIndex, offersList) + { + auto terResult = lesNodes.offerDelete(offerIndex); + + if (terResult != tesSUCCESS){ + WriteLog(lsINFO, AccountDeleteTransactor) << "AccountDelete: Deleting offer failed: " << transHuman(terResult); + } + } + + offersList.clear(); + + + return tesSUCCESS; +} + +} diff --git a/src/ripple_app/transactors/AccountDeleteTransactor.h b/src/ripple_app/transactors/AccountDeleteTransactor.h index 5340f7377..780857bfc 100644 --- a/src/ripple_app/transactors/AccountDeleteTransactor.h +++ b/src/ripple_app/transactors/AccountDeleteTransactor.h @@ -27,7 +27,7 @@ class AccountDeleteTransactor : public Transactor public: AccountDeleteTransactor(const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn, params, engine) {} - TER doApply() { return tefINTERNAL; } // TODO + TER doApply(); }; } diff --git a/src/ripple_data/protocol/TxFormats.cpp b/src/ripple_data/protocol/TxFormats.cpp index 727e4ed2f..77c5715bd 100644 --- a/src/ripple_data/protocol/TxFormats.cpp +++ b/src/ripple_data/protocol/TxFormats.cpp @@ -33,7 +33,7 @@ TxFormats::TxFormats () add("AccountDelete", ttACCOUNT_DELETE) << SOElement (sfDestination, SOE_REQUIRED) - // TODO + << SOElement (sfDestinationTag, SOE_OPTIONAL) ; add ("TrustSet", ttTRUST_SET)