From 9d40598b2ba391e7e8302d97669fa48b684dc6d8 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 11 Jul 2012 12:32:06 -0700 Subject: [PATCH 1/6] Cosmetic. --- src/SerializedTypes.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 56268382ae..bd76f5c843 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -260,6 +260,7 @@ std::string STTaggedList::getText() const Json::Value STTaggedList::getJson(int) const { Json::Value ret(Json::arrayValue); + for (std::vector::const_iterator it=value.begin(); it!=value.end(); ++it) { Json::Value elem(Json::arrayValue); @@ -267,6 +268,7 @@ Json::Value STTaggedList::getJson(int) const elem.append(strHex(it->second)); ret.append(elem); } + return ret; } From a3fb732e241f7d7ccc43c3a54fcd33b72198f969 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 13 Jul 2012 15:27:22 -0700 Subject: [PATCH 2/6] Rework offer amount calculation. --- src/Amount.cpp | 67 ++++++++++++++++++++++++------------------- src/Ledger.h | 13 +++++---- src/LedgerIndex.cpp | 5 ++++ src/LedgerNode.cpp | 20 ++++++------- src/SerializedTypes.h | 6 +++- 5 files changed, 65 insertions(+), 46 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index ac987ce567..068e1f8e43 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -737,41 +737,50 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) return (ret << (64 - 8)) | r.getMantissa(); } -STAmount STAmount::getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid) -{ // if someone is offering (offerOut) for (offerIn), and I pay (paid), how much do I get? +// Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds. +// --> saOfferFunds: Limit for saOfferPays +// --> saTakerFunds: Limit for saOfferGets +// --> saOfferPays: Request : this should be reduced as the offer is fullfilled. +// --> saOfferGets: Request : this should be reduced as the offer is fullfilled. +// --> saTakerPays: Total : Used to know the approximate ratio of the exchange. +// --> saTakerGets: Total : Used to know the approximate ratio of the exchange. +// <-- saTakerPaid: Actual +// <-- saTakerGot: Actual +// <-- bRemove: remove offer it is either fullfilled or unfunded +bool STAmount::applyOffer( + const STAmount& saOfferFunds, const STAmount& saTakerFunds, + const STAmount& saOfferPays, const STAmount& saOfferGets, + const STAmount& saTakerPays, const STAmount& saTakerGets, + STAmount& saTakerPaid, STAmount& saTakerGot) +{ + saOfferGets.throwComparable(saTakerPays); - offerIn.throwComparable(paid); + assert(!saOfferFunds.isZero() && !saTakerFunds.isZero()); // Must have funds. + assert(!saOfferGets.isZero() && !saOfferPays.isZero()); // Must not be a null offer. - if (offerIn.isZero() || offerOut.isZero()) - { // If the offer is invalid or empty, you pay nothing and get nothing and the offer is dead - offerIn.zero(); - offerOut.zero(); - paid.zero(); - return STAmount(); - } + // Amount offer can pay out, limited by offer and funds. + STAmount saOfferPaysAvailable = saOfferFunds < saOfferPays ? saOfferFunds : saOfferPays; - // If you pay nothing, you get nothing. Offer is untouched - if (paid.isZero()) return STAmount(); + // Amount offer needs to get to be complete, limited by offer funds. + STAmount saOfferGetsAvailable = + saOfferFunds == saOfferPays + ? saOfferGets // Offer was fully funded, avoid shenanigans. + : divide(multiply(saTakerPays, saOfferPaysAvailable, uint160(1)), saTakerGets, saOfferGets.getCurrency()); - if (paid >= offerIn) - { // If you pay equal to or more than the offer amount, you get the whole offer and pay its input - STAmount ret(offerOut); - paid = offerIn; - offerOut.zero(); - offerIn.zero(); - return ret; - } - - // partial satisfaction of a normal offer - STAmount ret = divide(multiply(paid, offerOut, uint160(1)), offerIn, offerOut.getCurrency()); - offerOut -= ret; - offerIn -= paid; - if (offerOut.isZero() || offerIn.isZero()) + if (saTakerFunds >= saOfferGetsAvailable) { - offerIn.zero(); - offerOut.zero(); + // Taker gets all of offer available. + saTakerPaid = saOfferGetsAvailable; // Taker paid what offer could get. + saTakerGot = saOfferPaysAvailable; // Taker got what offer could pay. + + return true; // No left over offer. } - return ret; + + // Taker only get's a portion of offer. + saTakerPaid = saTakerFunds; // Taker paid all he had. + saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, uint160(1)), saOfferGetsAvailable, saOfferPays.getCurrency()); + + return saTakerGot >= saOfferPaysAvailable; } STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed) diff --git a/src/Ledger.h b/src/Ledger.h index 9811a83516..66f351c42f 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -156,10 +156,10 @@ public: static Ledger::pointer loadByHash(const uint256& ledgerHash); // next/prev function - SLE::pointer getNextSLE(const uint256& hash); // first node >hash - SLE::pointer getNextSLE(const uint256& hash, const uint256& max); // first node >hash, min + SLE::pointer getNextSLE(const uint256& uHash); // first node >hash + SLE::pointer getNextSLE(const uint256& uHash, const uint256& uEnd); // first node >hash, begin // index calculation functions static uint256 getAccountRootIndex(const uint160& uAccountID); @@ -232,8 +232,9 @@ public: // Quality // - static uint256 getQualityIndex(const uint256& uBase, const uint64 uNodeDir=0); - static uint256 getQualityNext(const uint256& uBase); + static uint256 getQualityIndex(const uint256& uBase, const uint64 uNodeDir=0); + static uint256 getQualityNext(const uint256& uBase); + static uint64 getQuality(const uint256& uBase); // // Ripple functions : credit lines diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp index 79ec76bd33..91365ef9b9 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -15,6 +15,11 @@ uint256 Ledger::getQualityIndex(const uint256& uBase, const uint64 uNodeDir) return uNode; } +uint64 Ledger::getQuality(const uint256& uBase) +{ + return be64toh(((uint64*) uBase.end())[-1]); +} + uint256 Ledger::getQualityNext(const uint256& uBase) { static uint256 uNext("10000000000000000"); diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index d7345d1224..bf580452e3 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -46,34 +46,34 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) return lepOKAY; } -SLE::pointer Ledger::getNextSLE(const uint256& hash) +SLE::pointer Ledger::getNextSLE(const uint256& uHash) { - SHAMapItem::pointer node = mAccountStateMap->peekNextItem(hash); + SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); if (!node) return SLE::pointer(); return boost::make_shared(node->peekSerializer(), node->getTag()); } -SLE::pointer Ledger::getNextSLE(const uint256& hash, const uint256& max) +SLE::pointer Ledger::getNextSLE(const uint256& uHash, const uint256& uEnd) { - SHAMapItem::pointer node = mAccountStateMap->peekNextItem(hash); - if ((!node) || (node->getTag() > max)) + SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); + if ((!node) || (node->getTag() > uEnd)) return SLE::pointer(); return boost::make_shared(node->peekSerializer(), node->getTag()); } -SLE::pointer Ledger::getPrevSLE(const uint256& hash) +SLE::pointer Ledger::getPrevSLE(const uint256& uHash) { - SHAMapItem::pointer node = mAccountStateMap->peekPrevItem(hash); + SHAMapItem::pointer node = mAccountStateMap->peekPrevItem(uHash); if (!node) return SLE::pointer(); return boost::make_shared(node->peekSerializer(), node->getTag()); } -SLE::pointer Ledger::getPrevSLE(const uint256& hash, const uint256& min) +SLE::pointer Ledger::getPrevSLE(const uint256& uHash, const uint256& uBegin) { - SHAMapItem::pointer node = mAccountStateMap->peekNextItem(hash); - if ((!node) || (node->getTag() < min)) + SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); + if ((!node) || (node->getTag() < uBegin)) return SLE::pointer(); return boost::make_shared(node->peekSerializer(), node->getTag()); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 3d8bd3f7f5..3739473a6c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -330,7 +330,11 @@ public: // Someone is offering X for Y, I try to pay Z, how much do I get? // And what's left of the offer? And how much do I actually pay? - static STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid); + static bool applyOffer( + const STAmount& saOfferFunds, const STAmount& saTakerFunds, + const STAmount& saOfferPays, const STAmount& saOfferGets, + const STAmount& saTakerPays, const STAmount& saTakerGets, + STAmount& saTakerPaid, STAmount& saTakerGot); // Someone is offering X for Y, I need Z, how much do I pay static STAmount getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed); From 3982a67dbe31e6508f91f8ec4c72de1d56125c9d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 13 Jul 2012 15:31:08 -0700 Subject: [PATCH 3/6] Work on offer backend. --- src/LedgerFormats.cpp | 4 +- src/SerializedObject.h | 8 +- src/TransactionEngine.cpp | 870 ++++++++++++++++++++++++------------- src/TransactionEngine.h | 74 ++-- src/TransactionFormats.cpp | 4 +- 5 files changed, 616 insertions(+), 344 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 0c1e15ef98..7a588be8a3 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -46,8 +46,8 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(AmountIn), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(AmountOut), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 }, { S_FIELD(BookNode), STI_UINT64, SOE_REQUIRED, 0 }, diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 5dfcc4694e..0fbd85e1db 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -30,8 +30,6 @@ enum SOE_Field sfAccount, sfAccountID, sfAmount, - sfAmountIn, - sfAmountOut, sfAuthorizedKey, sfBalance, sfBookNode, @@ -52,6 +50,7 @@ enum SOE_Field sfFlags, sfGenerator, sfGeneratorID, + sfGetsIssuer, sfHash, sfHighID, sfHighLimit, @@ -60,8 +59,6 @@ enum SOE_Field sfIndexNext, sfIndexPrevious, sfInvoiceID, - sfIssuerIn, - sfIssuerOut, sfLastNode, sfLastReceive, sfLastTxn, @@ -81,6 +78,7 @@ enum SOE_Field sfOfferSequence, sfOwnerNode, sfPaths, + sfPaysIssuer, sfPubKey, sfQualityIn, sfQualityOut, @@ -89,6 +87,8 @@ enum SOE_Field sfSignature, sfSigningKey, sfSourceTag, + sfTakerGets, + sfTakerPays, sfTarget, sfTargetLedger, sfTransferRate, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index e5086755ec..0d270927fb 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -91,14 +91,73 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std return iIndex >= 0; } -// <-> accounts: Affected accounts for the transaction. +STAmount TransactionEngine::rippleBalance(const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency) +{ + LedgerStateParms qry = lepNONE; + SLE::pointer sleRippleState = mLedger->getRippleState(qry, Ledger::getRippleStateIndex(uAccountID, uIssuerAccountID, uCurrency)); + + STAmount saBalance = sleRippleState->getIValueFieldAmount(sfBalance); + if (uAccountID < uIssuerAccountID) + saBalance.negate(); // Put balance in low terms. + + return saBalance; +} + +void TransactionEngine::rippleCredit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saCredit) +{ + uint256 uIndex = Ledger::getRippleStateIndex(uAccountID, uIssuerAccountID, uCurrency); + LedgerStateParms qry = lepNONE; + SLE::pointer sleRippleState = mLedger->getRippleState(qry, uIndex); + bool bFlipped = uAccountID > uIssuerAccountID; + + if (!sleRippleState) + { + STAmount saBalance = saCredit; + + sleRippleState = entryCreate(ltRIPPLE_STATE); + + if (!bFlipped) + saBalance.negate(); + + sleRippleState->setIFieldAmount(sfBalance, saBalance); + sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uIssuerAccountID); + sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, uAccountID); + } + else + { + STAmount saBalance = sleRippleState->getIValueFieldAmount(sfBalance); + + if (!bFlipped) + saBalance.negate(); // Put balance in low terms. + + saBalance += saCredit; + + if (!bFlipped) + saBalance.negate(); + + sleRippleState->setIFieldAmount(sfBalance, saBalance); + + entryModify(sleRippleState); + } +} + +void TransactionEngine::rippleDebit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saDebit) +{ + STAmount saCredit = saDebit; + + saCredit.negate(); + + rippleCredit(emEntries, uAccountID, uIssuerAccountID, uCurrency, saCredit); +} + +// <-> emEntries: Affected accounts for the transaction. // <-- uNodeDir: For deletion, present to make dirDelete efficient. // --> uRootIndex: The index of the base of the directory. Nodes are based off of this. // --> uLedgerIndex: Value to add to directory. // We only append. This allow for things that watch append only structure to just monitor from the last node on ward. // Within a node with no deletions order of elements is sequential. Otherwise, order of elements is random. TransactionEngineResult TransactionEngine::dirAdd( - std::vector& accounts, + entryMap& emEntries, uint64& uNodeDir, const uint256& uRootIndex, const uint256& uLedgerIndex) @@ -115,12 +174,10 @@ TransactionEngineResult TransactionEngine::dirAdd( uNodeDir = 0; - sleRoot = boost::make_shared(ltDIR_NODE); + sleRoot = entryCreate(ltDIR_NODE); sleRoot->setIndex(uRootIndex); sleNode = sleRoot; - - accounts.push_back(std::make_pair(taaCREATE, sleRoot)); } else { @@ -150,7 +207,7 @@ TransactionEngineResult TransactionEngine::dirAdd( if (DIR_NODE_MAX != svIndexes.peekValue().size()) { // Add to current node. - accounts.push_back(std::make_pair(taaMODIFY, sleNode)); + entryModify(sleNode); } // Add to new node. else if (!++uNodeDir) @@ -161,25 +218,23 @@ TransactionEngineResult TransactionEngine::dirAdd( { // Have root point to new node. sleRoot->setIFieldU64(sfIndexPrevious, uNodeDir); - accounts.push_back(std::make_pair(taaMODIFY, sleRoot)); + entryModify(sleRoot); // Have old last point to new node, if it was not root. if (uNodePrevious) { // Previous node is not root node. sleNode->setIFieldU64(sfIndexNext, uNodeDir); - accounts.push_back(std::make_pair(taaMODIFY, sleNode)); + entryModify(sleNode); } // Create the new node. svIndexes = STVector256(); - sleNode = boost::make_shared(ltDIR_NODE); + sleNode = entryCreate(ltDIR_NODE); sleNode->setIndex(uNodeIndex); if (uNodePrevious) sleNode->setIFieldU64(sfIndexPrevious, uNodePrevious); - - accounts.push_back(std::make_pair(taaCREATE, sleNode)); } } @@ -193,13 +248,13 @@ TransactionEngineResult TransactionEngine::dirAdd( return terSUCCESS; } -// <-> accounts: Affected accounts for the transaction. +// <-> emEntries: Affected accounts for the transaction. // --> uNodeDir: Node containing entry. // --> uRootIndex: The index of the base of the directory. Nodes are based off of this. // --> uLedgerIndex: Value to add to directory. // Ledger must be in a state for this to work. TransactionEngineResult TransactionEngine::dirDelete( - std::vector& accounts, + entryMap& emEntries, const uint64& uNodeDir, const uint256& uRootIndex, const uint256& uLedgerIndex) @@ -244,7 +299,7 @@ TransactionEngineResult TransactionEngine::dirDelete( { // Node is not being deleted. sleNode->setIFieldV256(sfIndexes, svIndexes); - accounts.push_back(std::make_pair(taaMODIFY, sleNode)); + entryModify(sleNode); } else { @@ -257,7 +312,7 @@ TransactionEngineResult TransactionEngine::dirDelete( uint64 uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious); uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); - accounts.push_back(std::make_pair(taaDELETE, sleNode)); + entryDelete(sleNode); // Fix previous link. if (uNodePrevious) @@ -280,7 +335,7 @@ TransactionEngineResult TransactionEngine::dirDelete( { slePrevious->makeIFieldAbsent(sfIndexNext); } - accounts.push_back(std::make_pair(taaMODIFY, slePrevious)); + entryModify(slePrevious); } else { @@ -320,7 +375,7 @@ TransactionEngineResult TransactionEngine::dirDelete( { sleNext->makeIFieldAbsent(sfIndexNext); } - accounts.push_back(std::make_pair(taaMODIFY, sleNext)); + entryModify(sleNext); } else { @@ -362,11 +417,11 @@ TransactionEngineResult TransactionEngine::dirDelete( if (!uRootPrevious && !uRootNext && vuiIndexes.empty()) { - accounts.push_back(std::make_pair(taaDELETE, sleRoot)); + entryDelete(sleRoot); } else if (bRootDirty) { - accounts.push_back(std::make_pair(taaMODIFY, sleRoot)); + entryModify(sleRoot); } } } @@ -377,7 +432,7 @@ TransactionEngineResult TransactionEngine::dirDelete( } // Set the authorized public ket for an account. May also set the generator map. -TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransaction& txn, std::vector& accounts, bool bMustSetGenerator) +TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, bool bMustSetGenerator) { // // Verify that submitter knows the private key for the generator. @@ -405,12 +460,10 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac { Log(lsTRACE) << "createGenerator: creating generator"; // Create the generator. - sleGen = boost::make_shared(ltGENERATOR_MAP); + sleGen = entryCreate(ltGENERATOR_MAP); sleGen->setIndex(Ledger::getGeneratorIndex(hGeneratorID)); sleGen->setIFieldVL(sfGenerator, vucCipher); - - accounts.push_back(std::make_pair(taaCREATE, sleGen)); } else if (bMustSetGenerator) { @@ -422,13 +475,11 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac } // Set the public key needed to use the account. - SLE::pointer sleDst = accounts[0].second; - uint160 uAuthKeyID = bMustSetGenerator ? hGeneratorID // Claim : txn.getITFieldAccount(sfAuthorizedKey); // PasswordSet - sleDst->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); + sleSrc->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); return terSUCCESS; } @@ -445,6 +496,86 @@ Ledger::pointer TransactionEngine::getTransactionLedger(uint32 targetLedger) return ledger; } +bool TransactionEngine::entryExists(SLE::pointer sleEntry) +{ + return mEntries.find(sleEntry) != mEntries.end(); +} + +SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType) +{ + SLE::pointer sleNew = boost::make_shared(letType); + + mEntries[sleNew] = taaCREATE; + + return sleNew; +} + +void TransactionEngine::entryDelete(SLE::pointer sleEntry) +{ + entryMap::const_iterator it = mEntries.find(sleEntry); + + switch (it == mEntries.end() ? taaNONE : it->second) + { + case taaCREATE: + case taaUNFUNDED: + assert(false); // Unexpected case. + break; + + case taaMODIFY: + case taaNONE: + mEntries[sleEntry] = taaDELETE; // Upgrade + break; + + case taaDELETE: + nothing(); // No change. + break; + } +} + +void TransactionEngine::entryModify(SLE::pointer sleEntry) +{ + entryMap::const_iterator it = mEntries.find(sleEntry); + + switch (it == mEntries.end() ? taaNONE : it->second) + { + case taaUNFUNDED: + case taaDELETE: + assert(false); // Unexpected case. + break; + + case taaNONE: + mEntries[sleEntry] = taaMODIFY; // Upgrade + break; + + case taaCREATE: + case taaMODIFY: + nothing(); // No change. + break; + } +} + +void TransactionEngine::entryUnfunded(SLE::pointer sleEntry) +{ + entryMap::const_iterator it = mEntries.find(sleEntry); + + switch (it == mEntries.end() ? taaNONE : it->second) + { + case taaCREATE: + case taaMODIFY: + case taaDELETE: + assert(false); // Unexpected case. + break; + + case taaNONE: + mEntries[sleEntry] = taaUNFUNDED; // Upgrade + break; + + case taaUNFUNDED: + nothing(); // No change. + break; + } +} + TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn, TransactionEngineParams params, uint32 targetLedger) { @@ -771,24 +902,24 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } } - std::vector accounts; + entryMap emEntries; if (terSUCCESS == result) { - accounts.push_back(std::make_pair(taaMODIFY, sleSrc)); + entryModify(sleSrc); switch(txn.getTxnType()) { case ttACCOUNT_SET: - result = doAccountSet(txn, accounts); + result = doAccountSet(txn, emEntries, sleSrc); break; case ttCLAIM: - result = doClaim(txn, accounts); + result = doClaim(txn, emEntries, sleSrc); break; case ttCREDIT_SET: - result = doCreditSet(txn, accounts, srcAccountID); + result = doCreditSet(txn, emEntries, srcAccountID); break; case ttINVALID: @@ -797,35 +928,35 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran break; case ttINVOICE: - result = doInvoice(txn, accounts); + result = doInvoice(txn, emEntries); break; case ttOFFER_CREATE: - result = doOfferCreate(txn, accounts, srcAccountID); + result = doOfferCreate(txn, emEntries, sleSrc, srcAccountID); break; case ttOFFER_CANCEL: - result = doOfferCancel(txn, accounts, srcAccountID); + result = doOfferCancel(txn, emEntries, srcAccountID); break; case ttNICKNAME_SET: - result = doNicknameSet(txn, accounts, srcAccountID); + result = doNicknameSet(txn, emEntries, sleSrc, srcAccountID); break; case ttPASSWORD_FUND: - result = doPasswordFund(txn, accounts, srcAccountID); + result = doPasswordFund(txn, emEntries, sleSrc, srcAccountID); break; case ttPASSWORD_SET: - result = doPasswordSet(txn, accounts); + result = doPasswordSet(txn, emEntries, sleSrc); break; case ttPAYMENT: - result = doPayment(txn, accounts, srcAccountID); + result = doPayment(txn, emEntries, sleSrc, srcAccountID); break; case ttWALLET_ADD: - result = doWalletAdd(txn, accounts); + result = doWalletAdd(txn, emEntries, sleSrc); break; default: @@ -834,38 +965,102 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } } - if (terSUCCESS == result) - { // Write back the account states and add the transaction to the ledger - for (std::vector::iterator it = accounts.begin(), end = accounts.end(); - it != end; ++it) + bool bWrite = false; + + if (terSUCCESS != result) + { + BOOST_FOREACH(entryMap_value_type it, mEntries) { - if (it->first == taaCREATE) - { - std::cerr << "applyTransaction: taaCREATE: " << it->second->getText() << std::endl; + const SLE::pointer& sleEntry = it.first; - if (mLedger->writeBack(lepCREATE, it->second) & lepERROR) - assert(false); - } - else if (it->first == taaMODIFY) + switch (it.second) { - std::cerr << "applyTransaction: taaMODIFY: " << it->second->getText() << std::endl; - - if (mLedger->writeBack(lepNONE, it->second) & lepERROR) + case taaNONE: assert(false); - } - else if (it->first == taaDELETE) - { - std::cerr << "applyTransaction: taaDELETE: " << it->second->getText() << std::endl; + break; - if (!mLedger->peekAccountStateMap()->delItem(it->second->getIndex())) - assert(false); + case taaUNFUNDED: + { + Log(lsINFO) << "applyTransaction: taaUNFUNDED: " << sleEntry->getText(); + + if (!mLedger->peekAccountStateMap()->delItem(sleEntry->getIndex())) + assert(false); + + bWrite = true; + } + break; + + case taaCREATE: + case taaMODIFY: + case taaDELETE: + nothing(); + break; } } + } + if (terSUCCESS == result) + { // Write back the account states and add the transaction to the ledger + bWrite = true; + + BOOST_FOREACH(entryMap_value_type it, mEntries) + { + const SLE::pointer& sleEntry = it.first; + + switch (it.second) + { + case taaNONE: + assert(false); + break; + + case taaCREATE: + { + Log(lsINFO) << "applyTransaction: taaCREATE: " << sleEntry->getText(); + + if (mLedger->writeBack(lepCREATE, sleEntry) & lepERROR) + assert(false); + } + break; + + case taaMODIFY: + { + Log(lsINFO) << "applyTransaction: taaMODIFY: " << sleEntry->getText(); + + if (mLedger->writeBack(lepNONE, sleEntry) & lepERROR) + assert(false); + } + break; + + case taaDELETE: + { + Log(lsINFO) << "applyTransaction: taaDELETE: " << sleEntry->getText(); + + if (!mLedger->peekAccountStateMap()->delItem(sleEntry->getIndex())) + assert(false); + } + break; + + case taaUNFUNDED: + { + Log(lsINFO) << "applyTransaction: taaUNFUNDED: " << sleEntry->getText(); + + if (!mLedger->peekAccountStateMap()->delItem(sleEntry->getIndex())) + assert(false); + } + break; + } + } + } + + if (bWrite) + { Serializer s; + txn.add(s); + if (!mLedger->addTransaction(txID, s)) assert(false); + if ((params & tepUPDATE_TOTAL) != tepNONE) mLedger->destroyCoins(saPaid.getNValue()); } @@ -875,11 +1070,10 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran return result; } -TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransaction& txn, std::vector& accounts) +TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc) { std::cerr << "doAccountSet>" << std::endl; - SLE::pointer sleSrc = accounts[0].second; uint32 txFlags = txn.getFlags(); // @@ -944,11 +1138,11 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact } TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn, - std::vector& accounts) + entryMap& emEntries, SLE::pointer sleSrc) { std::cerr << "doClaim>" << std::endl; - TransactionEngineResult result = setAuthorized(txn, accounts, true); + TransactionEngineResult result = setAuthorized(txn, emEntries, sleSrc, true); std::cerr << "doClaim<" << std::endl; @@ -956,7 +1150,7 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& } TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransaction& txn, - std::vector&accounts, + entryMap& emEntries, const uint160& uSrcAccountID) { TransactionEngineResult terResult = terSUCCESS; @@ -989,8 +1183,8 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti STAmount saLimitAmount = txn.getITFieldAmount(sfLimitAmount); uint160 uCurrency = saLimitAmount.getCurrency(); - bool bSltD = uSrcAccountID < uDstAccountID; - uint32 uFlags = bSltD ? lsfLowIndexed : lsfHighIndexed; + bool bFlipped = uSrcAccountID > uDstAccountID; + uint32 uFlags = bFlipped ? lsfLowIndexed : lsfHighIndexed; STAmount saBalance(uCurrency); bool bAddIndex = false; bool bDelIndex = false; @@ -1019,7 +1213,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti // Zero balance and eliminating last limit. bDelIndex = true; - terResult = dirDelete(accounts, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); + terResult = dirDelete(emEntries, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); } } #endif @@ -1027,12 +1221,12 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti { bAddIndex = !(sleRippleState->getFlags() & uFlags); - sleRippleState->setIFieldAmount(bSltD ? sfLowLimit : sfHighLimit, saLimitAmount); + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit , saLimitAmount); if (bAddIndex) sleRippleState->setFlag(uFlags); - accounts.push_back(std::make_pair(taaMODIFY, sleRippleState)); + entryModify(sleRippleState); } Log(lsINFO) << "doCreditSet: Modifying ripple line: bAddIndex=" << bAddIndex << " bDelIndex=" << bDelIndex; @@ -1050,7 +1244,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti STAmount saZero(uCurrency); bAddIndex = true; - sleRippleState = boost::make_shared(ltRIPPLE_STATE); + sleRippleState = entryCreate(ltRIPPLE_STATE); sleRippleState->setIndex(Ledger::getRippleStateIndex(uSrcAccountID, uDstAccountID, uCurrency)); Log(lsINFO) << "doCreditSet: Creating ripple line: " @@ -1058,12 +1252,10 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti sleRippleState->setFlag(uFlags); sleRippleState->setIFieldAmount(sfBalance, saZero); // Zero balance in currency. - sleRippleState->setIFieldAmount(bSltD ? sfLowLimit : sfHighLimit, saLimitAmount); - sleRippleState->setIFieldAmount(bSltD ? sfHighLimit : sfLowLimit, saZero); - sleRippleState->setIFieldAccount(bSltD ? sfLowID : sfHighID, uSrcAccountID); - sleRippleState->setIFieldAccount(bSltD ? sfHighID : sfLowID, uDstAccountID); - - accounts.push_back(std::make_pair(taaCREATE, sleRippleState)); + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); + sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, saZero); + sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, uSrcAccountID); + sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID); } if (bAddIndex) @@ -1071,7 +1263,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti uint64 uSrcRef; // Ignored, ripple_state dirs never delete. // XXX Make dirAdd more flexiable to take vector. - terResult = dirAdd(accounts, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); + terResult = dirAdd(emEntries, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); } Log(lsINFO) << "doCreditSet<"; @@ -1079,12 +1271,10 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti return terResult; } -TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransaction& txn, std::vector& accounts, const uint160& uSrcAccountID) +TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID) { std::cerr << "doNicknameSet>" << std::endl; - SLE::pointer sleSrc = accounts[0].second; - uint256 uNickname = txn.getITFieldH256(sfNickname); bool bMinOffer = txn.getITFieldPresent(sfMinimumOffer); STAmount saMinOffer = bMinOffer ? txn.getITFieldAmount(sfAmount) : STAmount(); @@ -1106,14 +1296,14 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac sleNickname->makeIFieldAbsent(sfMinimumOffer); } - accounts.push_back(std::make_pair(taaMODIFY, sleNickname)); + entryModify(sleNickname); } else { // Make a new entry. - // XXX Need to include authorization limiting. + // XXX Need to include authorization limiting for first year. - sleNickname = boost::make_shared(ltNICKNAME); + sleNickname = entryCreate(ltNICKNAME); sleNickname->setIndex(Ledger::getNicknameIndex(uNickname)); std::cerr << "doNicknameSet: Creating nickname node: " << sleNickname->getIndex().ToString() << std::endl; @@ -1122,8 +1312,6 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac if (bMinOffer && !saMinOffer.isZero()) sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); - - accounts.push_back(std::make_pair(taaCREATE, sleNickname)); } std::cerr << "doNicknameSet<" << std::endl; @@ -1131,13 +1319,12 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac return terSUCCESS; } -TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransaction& txn, std::vector& accounts, const uint160& uSrcAccountID) +TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID) { std::cerr << "doPasswordFund>" << std::endl; uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); LedgerStateParms qry = lepNONE; - SLE::pointer sleSrc = accounts[0].second; SLE::pointer sleDst = uSrcAccountID == uDstAccountID ? sleSrc : mLedger->getAccountRoot(qry, uDstAccountID); @@ -1157,7 +1344,8 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa if (uSrcAccountID != uDstAccountID) { std::cerr << "doPasswordFund: Destination modified." << std::endl; - accounts.push_back(std::make_pair(taaMODIFY, sleDst)); + + entryModify(sleDst); } } @@ -1166,12 +1354,10 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa return terSUCCESS; } -TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransaction& txn, std::vector& accounts) +TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc) { std::cerr << "doPasswordSet>" << std::endl; - SLE::pointer sleSrc = accounts[0].second; - if (sleSrc->getFlags() & lsfPasswordSpent) { std::cerr << "doPasswordSet: Delay transaction: Funds already spent." << std::endl; @@ -1181,7 +1367,7 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac sleSrc->setFlag(lsfPasswordSpent); - TransactionEngineResult result = setAuthorized(txn, accounts, false); + TransactionEngineResult result = setAuthorized(txn, emEntries, sleSrc, false); std::cerr << "doPasswordSet<" << std::endl; @@ -1330,7 +1516,7 @@ bool calcPaymentForward(std::vector& pnNodes) // XXX Need to audit for things like setting accountID not having memory. TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn, - std::vector& accounts, + entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID) { // Ripple if source or destination is non-native or if there are paths. @@ -1388,13 +1574,11 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } // Create the account. - sleDst = boost::make_shared(ltACCOUNT_ROOT); + sleDst = entryCreate(ltACCOUNT_ROOT); sleDst->setIndex(Ledger::getAccountRootIndex(uDstAccountID)); sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); - - accounts.push_back(std::make_pair(taaCREATE, sleDst)); } // Destination exists. else if (bCreate) @@ -1406,7 +1590,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } else { - accounts.push_back(std::make_pair(taaMODIFY, sleDst)); + entryModify(sleDst); } bool bRipple = bPaths || bMax || !saDstAmount.isNative(); @@ -1414,7 +1598,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction if (!bRipple) { // Direct XNS payment. - STAmount saSrcXNSBalance = accounts[0].second->getIValueFieldAmount(sfBalance); + STAmount saSrcXNSBalance = sleSrc->getIValueFieldAmount(sfBalance); if (saSrcXNSBalance < saDstAmount) { @@ -1424,8 +1608,8 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return terUNFUNDED; } - accounts[0].second->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); - accounts[1].second->setIFieldAmount(sfBalance, accounts[1].second->getIValueFieldAmount(sfBalance) + saDstAmount); + sleSrc->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); + sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); return terSUCCESS; } @@ -1433,6 +1617,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // // Ripple payment // + // XXX Disallow loops in ripple paths // Try direct ripple first. if (!bNoRippleDirect && uSrcAccountID != uDstAccountID && uSrcCurrency == uDstCurrency) @@ -1498,7 +1683,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction TransactionEngineResult terResult = terSUCCESS; uint64 uSrcRef; // Ignored, ripple_state dirs never delete. - terResult = dirAdd(accounts, + terResult = dirAdd(emEntries, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), // The source ended up owing. sleRippleState->getIndex()); // Adding current entry. @@ -1516,7 +1701,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } sleRippleState->setIFieldAmount(sfBalance, saDstBalance); - accounts.push_back(std::make_pair(taaMODIFY, sleRippleState)); + entryModify(sleRippleState); return terSUCCESS; } @@ -1549,7 +1734,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransaction& txn, - std::vector& accounts) + entryMap& emEntries, SLE::pointer sleSrc) { std::cerr << "WalletAdd>" << std::endl; @@ -1576,7 +1761,6 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti return tenCREATED; } - SLE::pointer sleSrc = accounts[0].second; STAmount saAmount = txn.getITFieldAmount(sfAmount); STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance); @@ -1595,7 +1779,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti sleSrc->setIFieldAmount(sfBalance, saSrcBalance-saAmount); // Create the account. - sleDst = boost::make_shared(ltACCOUNT_ROOT); + sleDst = entryCreate(ltACCOUNT_ROOT); sleDst->setIndex(Ledger::getAccountRootIndex(uDstAccountID)); sleDst->setIFieldAccount(sfAccount, uDstAccountID); @@ -1603,209 +1787,237 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti sleDst->setIFieldAmount(sfBalance, saAmount); sleDst->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); - accounts.push_back(std::make_pair(taaCREATE, sleDst)); - std::cerr << "WalletAdd<" << std::endl; return terSUCCESS; } TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn, - std::vector& accounts) + entryMap& emEntries) { return tenUNKNOWN; } -#ifdef WORK_IN_PROGRESS -// XXX Disallow loops in ripple paths -// XXX Note accounts we visited so as not mark them found unfunded. // Before an offer is place into the ledger, fill as much as possible. -// XXX Also use quality fees when rippling a take. -// XXX Also be careful of taking own offer: delete old offer. -// --> uBookBase: the opposite order book. -TransactionEngineResult TransactionEngine::offerTake( +// --> uBookBase: The order book to take against. +// --> saTakerPays: What the taker wanted (w/ issuer) +// --> saTakerGets: What the taker wanted (w/ issuer) +// --> saTakerFund: What taker can afford +// <-- saTakerPaid: What taker actually paid +// <-- saTakerGot: What taker actually got +TransactionEngineResult TransactionEngine::takeOffers( + entryMap& emEntries, bool bPassive, - uint64 uTakeQuality, const uint256& uBookBase, const uint160& uTakerAccountID, - STAmount& saTakerGets, // With issuer. - STAmount& saTakerPays, // With issuer. - std::vector vspUnfundedFound) + const STAmount& saTakerPays, + const STAmount& saTakerGets, + const STAmount& saTakerFunds, + STAmount& saTakerPaid, + STAmount& saTakerGot) { - uint256 uTipIndex = uBookIndex; - bool bDone = true; - STAmount saSold = 0; // XXX Add in currency - STAmount saOffered = XXX amount to fill. - TransactionEngineResult terResult = tenUNKNOWN; + assert(!saTakerPays.isZero() && !saTakerGets.isZero()); + + uint256 uTipIndex = uBookBase; + uint256 uBookEnd = Ledger::getQualityNext(uBookBase); + uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays); + uint160 uTakerPaysAccountID = saTakerPays.getIssuer(); + uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); + uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); + uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); + TransactionEngineResult terResult = tenUNKNOWN; + + saTakerPaid = 0; + saTakerGot = 0; while (tenUNKNOWN == terResult) { - uTipIndex = Ledger::indexNext(uTipIndex); + SLE::pointer sleOffer; + uint64 uTipQuality; - uint256 uTipBase; - uint64 uTipQuality = Ledger::indexQuality(uTipIndex, uTipBase); - - if (saSold == saAmount) + if (saTakerGets != saTakerGot && saTakerPays != saTakerPaid) { - // Filled order. - terResult = terSUCCESS; + // Taker has needs. + sleOffer = mLedger->getNextSLE(uTipIndex, uBookEnd); + uTipIndex = sleOffer->getIndex(); + uTipQuality = Ledger::getQuality(uTipIndex); } - else if (uTipBase != uBookBase - || uTakeQuality < uTipQuality - || (bPassive && uTakeQuality == uTipQuality)) - { - // No qualifying offer. + if (!sleOffer || uTakeQuality < uTipQuality || (bPassive && uTakeQuality == uTipQuality)) + { + // Done. terResult = terSUCCESS; } else { // Have an offer to consider. - LedgerStateParms qry = lepNONE; - SLE::pointer sleOffer = mLedger->getOffer(qry, uTipIndex); + NewcoinAddress naOfferAccountID = sleOffer->getIValueFieldAccount(sfAccount); + STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); + uint160 uOfferAccountID = naOfferAccountID.getAccountID(); - assert(sleOffer); - if (!sleOffer) + if (uOfferAccountID == uTakerAccountID) { - // Missing ledger entry. - Log(lsINFO) << "offerTake: Missing offer node: " << uTipIndex.ToString(); + // Would take own offer. Consider it unfunded. - terResult = terBAD_LEDGER; + entryUnfunded(sleOffer); + } + else if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. Delete it. + + entryUnfunded(sleOffer); } else { - NewcoinAddress naOfferAccountID = sleOffer->getIValueFieldAccount(sfAccount); - STAmount saOfferTakerGets = sleOffer->getIValueFieldAmount(sfAmountOut); + // Get offer funds available. + STAmount saOfferFunds; + SLE::pointer sleOfferAccount; + SLE::pointer sleOfferFunds; // ledger entry of funding - if (naOfferAccountID == uTakerAccountID) + if (saTakerGets.isNative()) { - // Would take own offer. Consider it unfunded. Delete it. + // Handle getting stamps. - vspUnfundedFound.push_back(sleOffer); - } - else if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= prevLedgerClose) - { - // Offer is expired. Delete it. + LedgerStateParms qry = lepNONE; - vspUnfundedFound.push_back(sleOffer); + sleOfferAccount = mLedger->getAccountRoot(qry, naOfferAccountID); + if (!sleOfferAccount) + { + Log(lsWARNING) << "takeOffers: delay: can't receive stamps from non-existant account"; + + terResult = terNO_ACCOUNT; + } + else + { + saOfferFunds = sleOfferAccount->getIValueFieldAmount(sfBalance); + sleOfferFunds = sleOfferAccount; + } } else { - SLE::pointer sleOfferAccount; - SLE::pointer sleOfferRipplePays; - STAmount saOfferBalance; + // Handling getting ripple. + if (saTakerGets.getIssuer() == uOfferAccountID) + { + // Taker gets offer's IOUs from offerer: fully funded. + + saOfferFunds = saOfferPays; + } + else + { + // offerer's line of credit with offerer pay's issuer + saOfferFunds = rippleBalance(uOfferAccountID, uTakerGetsAccountID, uTakerGetsCurrency); + sleOfferFunds = sleOfferAccount; + } + } + + if (tenUNKNOWN != terResult) + { + nothing(); + } + else if (saOfferFunds.isPositive()) + { + STAmount saSubTakerPaid; + STAmount saSubTakerGot; + + bool bOfferDelete = STAmount::applyOffer( + saOfferFunds, saTakerFunds, + saOfferPays, saOfferGets, + saTakerPays, saTakerGets, + saSubTakerPaid, saSubTakerGot); + + // Adjust offer + if (bOfferDelete) + { + // Offer now fully claimed or now unfunded. + + entryDelete(sleOffer); + } + else + { + sleOffer->setIFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); + sleOffer->setIFieldAmount(sfTakerPays, saOfferGets += saSubTakerPaid); + + entryModify(sleOffer); + } + + // Pay taker (debit offer issuer) if (saTakerGets.isNative()) { - // Handle getting stamps. - LedgerStateParms qry = lepNONE; - SLE::pointer sleOfferAccount = mLedger->getAccountRoot(qry, naOfferAccountID); - if (!sleOfferAccount) - { - Log(lsWARNING) << "offerTake: delay: can't receive stamps from non-existant account"; + sleOfferAccount->setIFieldAmount(sfBalance, + sleOfferAccount->getIValueFieldAmount(sfBalance) - saSubTakerGot); - terResult = terNO_ACCOUNT; - } - else - { - saOfferBalance = sleOfferAccount->getIValueFieldAmount(sfBalance); - } + entryModify(sleOfferAccount); } else { - // Handling getting ripple. - - if (saTakerGets.getIssuer() == naOfferAccountID) - { - // Taker gets offer's IOUs from offerer. Always works - - } - else - { - sleOfferRipplePays = getRippleState(getRippleStateIndex(uSrcAccountID, saTakerGets.getIssuer(), saTakerGets.getCurrency())); - - bool bSltD = uSrcAccountID < uIssuerOutID; - - STAmount saSrcBalance = sleRippleState->getIValueFieldAmount(sfBalance); - if (bSltD) - saSrcBalance.negate(); // Put balance in low terms. - } - STAmount saSrcBalance = sleOfferAccount->getIValueFieldAmount(sfBalance); - - if (saSrcBalance.isZero()) - { - terResult = terUNFUNDED; - } - else - { - STAmount saTakerPaysCur = STAmount::getPay(saOfferTakerGets, saOfferTakerPays, saTakerWants); - STAmount saTakerGetsCur = STAmount::getClaimed(saOfferTakerGets, saOfferTakerPays, saTakerPays); - - saTakerWants -= saTakerGetsCur; - - sleOfferAccount->setIFieldAmount(sfBalance, saSrcBalance - saPaid); - } + rippleDebit(emEntries, uOfferAccountID, uTakerGetsAccountID, uTakerGetsCurrency, saSubTakerGot); } + saTakerGot += saSubTakerGot; - } - // Handle getting IOUs. - else + // Pay offer + if (saTakerPays.isNative()) + { + sleOfferAccount->setIFieldAmount(sfBalance, + sleOfferAccount->getIValueFieldAmount(sfBalance) + saSubTakerPaid); - if (saSrcBalance.isPositive()) - { - - } - == saOoffer is unfunded - else - figure out how much to convert - - note to counter party how much taken - - if took it all - deleteIt + entryModify(sleOfferAccount); + } else - makeChanges + { + rippleCredit(emEntries, uOfferAccountID, uTakerPaysAccountID, uTakerPaysCurrency, saSubTakerPaid); + } + saTakerPaid += saSubTakerPaid; + } + else if (entryExists(sleOfferFunds)) + { + // Offer is unfunded, possibly due to previous balance action. + + entryDelete(sleOffer); // Only delete, if transaction succeeds. + } + else + { + // Offer is unfunded, outright. + + entryUnfunded(sleOffer); // Always delete as was originally unfunded. + } } } - else - { - bDone = true; - } } - return tenUNKNOWN == terResult ? terSUCCESS : terResult; + return terResult; } -#endif TransactionEngineResult TransactionEngine::doOfferCreate( const SerializedTransaction& txn, - std::vector& accounts, + entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID) { uint32 txFlags = txn.getFlags(); bool bPassive = !!(txFlags & tfPassive); - STAmount saAmountIn = txn.getITFieldAmount(sfAmountIn); - STAmount saAmountOut = txn.getITFieldAmount(sfAmountOut); - uint160 uIssuerInID = txn.getITFieldAccount(sfIssuerIn); - uint160 uIssuerOutID = txn.getITFieldAccount(sfIssuerOut); + STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); + STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); + uint160 uPaysIssuerID = txn.getITFieldAccount(sfPaysIssuer); + uint160 uGetsIssuerID = txn.getITFieldAccount(sfGetsIssuer); uint32 uExpiration = txn.getITFieldU32(sfExpiration); bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); uint32 uSequence = txn.getSequence(); // LedgerStateParms qry = lepNONE; - SLE::pointer sleOffer = boost::make_shared(ltOFFER); + SLE::pointer sleOffer = entryCreate(ltOFFER); uint256 uLedgerIndex = Ledger::getOfferIndex(uSrcAccountID, uSequence); Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString(); - uint160 uCurrencyIn = saAmountIn.getCurrency(); - uint160 uCurrencyOut = saAmountOut.getCurrency(); + uint160 uPaysCurrency = saTakerPays.getCurrency(); + uint160 uGetsCurrency = saTakerGets.getCurrency(); + uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); TransactionEngineResult terResult = terSUCCESS; uint64 uOwnerNode; // Delete hint. uint64 uBookNode; // Delete hint. - - uint32 uPrevLedgerTime = 0; // XXX Need previous + STAmount saOfferFunds; if (!bHaveExpiration || !uExpiration) { @@ -1813,80 +2025,60 @@ TransactionEngineResult TransactionEngine::doOfferCreate( terResult = tenBAD_EXPIRATION; } - else if (!bHaveExpiration || uPrevLedgerTime >= uExpiration) + else if (!bHaveExpiration || mLedger->getParentCloseTimeNC() >= uExpiration) { Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; terResult = tenEXPIRED; } - else if (saAmountIn.isNative() && saAmountOut.isNative()) + else if (saTakerPays.isNative() && saTakerGets.isNative()) { Log(lsWARNING) << "doOfferCreate: Malformed offer: stamps for stamps"; terResult = tenBAD_OFFER; } - else if (saAmountIn.isZero() || saAmountOut.isZero()) + else if (saTakerPays.isZero() || saTakerGets.isZero()) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; terResult = tenBAD_OFFER; } - else if (uCurrencyIn == uCurrencyOut && uIssuerInID == uIssuerOutID) + else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID) { Log(lsWARNING) << "doOfferCreate: Malformed offer: no conversion"; terResult = tenREDUNDANT; } - else if (saAmountIn.isNative() != uIssuerInID.isZero() || saAmountOut.isNative() != uIssuerOutID.isZero()) + else if (saTakerPays.isNative() != uPaysIssuerID.isZero() || saTakerGets.isNative() != uGetsIssuerID.isZero()) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer"; terResult = tenBAD_ISSUER; } + else if (!saTakerGets.isNative() && uGetsIssuerID == uSrcAccountID) + { + // Delivering self issued IOUs. + nothing(); + } else { // Make sure signer has funds. - SLE::pointer sleSrc = accounts[0].second; - STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance); + saOfferFunds = saTakerGets.isNative() + ? sleSrc->getIValueFieldAmount(sfBalance) + : rippleBalance(uSrcAccountID, uGetsIssuerID, uGetsCurrency); - if (saAmountOut.isNative() && !saSrcBalance.isZero()) + if (!saOfferFunds.isPositive()) { - // Delivering stamps and has stamps. - nothing(); - } - else if (uIssuerOutID == uSrcAccountID) - { - // Delivering self issued IOUs. - nothing(); - } - else - { - LedgerStateParms qry = lepNONE; - SLE::pointer sleRippleOut = mLedger->getRippleState(qry, Ledger::getRippleStateIndex(uSrcAccountID, uIssuerOutID, uCurrencyOut)); - bool bSltD = uSrcAccountID < uIssuerOutID; + Log(lsWARNING) << "doOfferCreate: delay: offers must be funded"; - STAmount saSrcBalance = sleRippleOut->getIValueFieldAmount(sfBalance); - if (bSltD) - saSrcBalance.negate(); // Put balance in low terms. - - if (saSrcBalance.isPositive()) - { - // Funded. - nothing(); - } - else - { - Log(lsWARNING) << "doOfferCreate: delay: offers must be funded"; - - terResult = terUNFUNDED; - } + terResult = terUNFUNDED; } } if (terSUCCESS == terResult) { LedgerStateParms qry = lepNONE; - SLE::pointer sleRippleIn = mLedger->getAccountRoot(qry, uIssuerInID); + SLE::pointer sleRippleIn = mLedger->getAccountRoot(qry, uPaysIssuerID); if (!sleRippleIn) { Log(lsWARNING) << "doOfferCreate: delay: can't receive IOUs from non-existant issuer"; @@ -1897,50 +2089,106 @@ TransactionEngineResult TransactionEngine::doOfferCreate( if (terSUCCESS == terResult) { -#ifdef WORK_IN_PROGRESS - terResult = offerTake( + STAmount saOfferPaid; + STAmount saOfferGot; + + // Take using the parameters of the offer. + terResult = takeOffers( + emEntries, bPassive, - STAmount::getRate(saAmountIn, saAmountOut), - Ledger::getBookBase(uCurrencyOut, uIssuerOutID, uCurrencyIn, uIssuerInID) + Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID), + uSrcAccountID, + saTakerGets, + saTakerPays, + saOfferFunds, // Limit to spend. + saOfferPaid, // How much was spent. + saOfferGot // How much was got. ); -#endif - } - // XXX Check if some portion of order was not complete. - if (terSUCCESS == terResult) + if (terSUCCESS == terResult) + { + saOfferFunds -= saOfferPaid; // Reduce balance. + + saTakerGets -= saOfferPaid; // Reduce payout to takers by what srcAccount just paid. + saTakerPays -= saOfferGot; // Reduce payin from takers by what offer just got. + + // Adjust funding source. + if (!saOfferPaid.isZero()) + { + nothing(); + } + if (!saTakerGets.isNative() && uGetsIssuerID == uSrcAccountID) + { + // Delivering self-issued IOUs. + nothing(); + } + else if (saTakerGets.isNative()) + { + sleSrc->setIFieldAmount(sfBalance, saOfferFunds - saOfferPaid); + } + else + { + rippleDebit(emEntries, uSrcAccountID, uGetsIssuerID, uGetsCurrency, saOfferPaid); + } + + // Adjust payout target. + if (!saOfferGot.isZero()) + { + nothing(); + } + if (!saTakerPays.isNative() && uPaysIssuerID == uSrcAccountID) + { + // Destroying self-issued IOUs. + nothing(); + } + else if (saTakerGets.isNative()) + { + sleSrc->setIFieldAmount(sfBalance, sleSrc->getIValueFieldAmount(sfBalance) - saOfferGot); + } + else + { + rippleCredit(emEntries, uSrcAccountID, uPaysIssuerID, uPaysCurrency, saOfferGot); + } + } + } + + if (terSUCCESS == terResult + && !saOfferFunds.isZero() // Still funded. + && !saTakerGets.isZero() // Still offering something. + && !saTakerPays.isZero()) // Still wanting something. { + // We need to place the remainder of the offer into its order book. + // Add offer to owner's directory. - terResult = dirAdd(accounts, uOwnerNode, Ledger::getOwnerDirIndex(uSrcAccountID), uLedgerIndex); - } + terResult = dirAdd(emEntries, uOwnerNode, Ledger::getOwnerDirIndex(uSrcAccountID), uLedgerIndex); - if (terSUCCESS == terResult) - { - // Add offer to order book. - terResult = dirAdd( - accounts, - uBookNode, - Ledger::getQualityIndex( - Ledger::getBookBase(uCurrencyIn, uIssuerInID, uCurrencyOut, uIssuerOutID), - STAmount::getRate(saAmountOut, saAmountIn)), - uLedgerIndex); - } + if (terSUCCESS == terResult) + { + // Add offer to order book. + terResult = dirAdd( + emEntries, + uBookNode, + Ledger::getQualityIndex( + Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID), + uRate), // Use original rate. + uLedgerIndex); + } - if (terSUCCESS == terResult) - { - sleOffer->setIndex(uLedgerIndex); + if (terSUCCESS == terResult) + { + sleOffer->setIndex(uLedgerIndex); - sleOffer->setIFieldAccount(sfAccount, uSrcAccountID); - sleOffer->setIFieldU32(sfSequence, uSequence); - sleOffer->setIFieldAmount(sfAmountIn, saAmountIn); - sleOffer->setIFieldAmount(sfAmountOut, saAmountOut); - sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); - sleOffer->setIFieldU64(sfBookNode, uBookNode); - sleOffer->setIFieldU32(sfExpiration, uExpiration); + sleOffer->setIFieldAccount(sfAccount, uSrcAccountID); + sleOffer->setIFieldU32(sfSequence, uSequence); + sleOffer->setIFieldAmount(sfTakerPays, saTakerPays); + sleOffer->setIFieldAmount(sfTakerGets, saTakerGets); + sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); + sleOffer->setIFieldU64(sfBookNode, uBookNode); + sleOffer->setIFieldU32(sfExpiration, uExpiration); - if (bPassive) - sleOffer->setFlag(lsfPassive); - - accounts.push_back(std::make_pair(taaCREATE, sleOffer)); + if (bPassive) + sleOffer->setFlag(lsfPassive); + } } return terResult; @@ -1948,7 +2196,7 @@ TransactionEngineResult TransactionEngine::doOfferCreate( TransactionEngineResult TransactionEngine::doOfferCancel( const SerializedTransaction& txn, - std::vector& accounts, + entryMap& emEntries, const uint160& uSrcAccountID) { uint32 uSequence = txn.getITFieldU32(sfSequence); @@ -1966,14 +2214,14 @@ TransactionEngineResult TransactionEngine::doOfferCancel( uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); uint64 uOwnerNode = sleOffer->getIFieldU64(sfOfferNode); - terResult = dirDelete(accounts, uOwnerNode, ___, uLedgerIndex); + terResult = dirDelete(emEntries, uOwnerNode, ___, uLedgerIndex); if (terSUCCESS == terResult) { - terResult = dirDelete(accounts, uOfferNode, ___, uLedgerIndex); + terResult = dirDelete(emEntries, uOfferNode, ___, uLedgerIndex); } #endif - accounts.push_back(std::make_pair(taaDELETE, sleOffer)); + entryDelete(sleOffer); } else { @@ -1984,19 +2232,19 @@ TransactionEngineResult TransactionEngine::doOfferCancel( } TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn, - std::vector& accounts) + entryMap& emEntries) { return tenUNKNOWN; } TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn, - std::vector& accounts) + entryMap& emEntries) { return tenUNKNOWN; } TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction& txn, - std::vector& accounts) + entryMap& emEntries) { return tenUNKNOWN; } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 36427747fb..5bc249a434 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -89,10 +89,11 @@ enum TransactionEngineParams enum TransactionAccountAction { - taaACCESS, + taaNONE, taaCREATE, taaMODIFY, - taaDELETE + taaDELETE, + taaUNFUNDED, }; typedef std::pair AffectedAccount; @@ -100,14 +101,19 @@ typedef std::pair Affe class TransactionEngine { private: + typedef boost::unordered_map entryMap; + typedef boost::unordered_map::iterator entryMap_iterator; + typedef boost::unordered_map::const_iterator entryMap_const_iterator; + typedef boost::unordered_map::iterator::value_type entryMap_value_type; + TransactionEngineResult dirAdd( - std::vector& accounts, + entryMap& emEntries, uint64& uNodeDir, // Node of entry. const uint256& uRootIndex, const uint256& uLedgerIndex); TransactionEngineResult dirDelete( - std::vector& accounts, + entryMap& emEntries, const uint64& uNodeDir, // Node item is mentioned in. const uint256& uRootIndex, const uint256& uLedgerIndex); // Item being deleted @@ -135,33 +141,51 @@ private: } paymentGroup; #endif - TransactionEngineResult setAuthorized(const SerializedTransaction& txn, std::vector& accounts, bool bMustSetGenerator); + TransactionEngineResult setAuthorized(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, bool bMustSetGenerator); + + TransactionEngineResult takeOffers( + entryMap& emEntries, + bool bPassive, + const uint256& uBookBase, + const uint160& uTakerAccountID, + const STAmount& saTakerPays, + const STAmount& saTakerGets, + const STAmount& saTakerFunds, + STAmount& saTakerPaid, + STAmount& saTakerGot); protected: Ledger::pointer mDefaultLedger, mAlternateLedger; Ledger::pointer mLedger; uint64 mLedgerParentCloseTime; - TransactionEngineResult doAccountSet(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doClaim(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doCreditSet(const SerializedTransaction& txn, std::vector& accounts, - const uint160& uSrcAccountID); - TransactionEngineResult doDelete(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doInvoice(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doOfferCreate(const SerializedTransaction& txn, std::vector& accounts, - const uint160& uSrcAccountID); - TransactionEngineResult doOfferCancel(const SerializedTransaction& txn, std::vector& accounts, - const uint160& uSrcAccountID); - TransactionEngineResult doNicknameSet(const SerializedTransaction& txn, std::vector& accounts, - const uint160& uSrcAccountID); - TransactionEngineResult doPasswordFund(const SerializedTransaction& txn, std::vector& accounts, - const uint160& uSrcAccountID); - TransactionEngineResult doPasswordSet(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doPayment(const SerializedTransaction& txn, std::vector& accounts, - const uint160& uSrcAccountID); - TransactionEngineResult doStore(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doTake(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doWalletAdd(const SerializedTransaction& txn, std::vector& accounts); + entryMap mEntries; + + SLE::pointer entryCreate(LedgerEntryType letType); + void entryDelete(SLE::pointer sleEntry); + void entryModify(SLE::pointer sleEntry); + void entryUnfunded(SLE::pointer sleEntry); + bool entryExists(SLE::pointer sleEntry); + + STAmount rippleBalance(const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency); + + void rippleCredit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saCredit); + void rippleDebit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saDebit); + + TransactionEngineResult doAccountSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); + TransactionEngineResult doClaim(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); + TransactionEngineResult doCreditSet(const SerializedTransaction& txn, entryMap& emEntries, const uint160& uSrcAccountID); + TransactionEngineResult doDelete(const SerializedTransaction& txn, entryMap& emEntries); + TransactionEngineResult doInvoice(const SerializedTransaction& txn, entryMap& emEntries); + TransactionEngineResult doOfferCreate(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doOfferCancel(const SerializedTransaction& txn, entryMap& emEntries, const uint160& uSrcAccountID); + TransactionEngineResult doNicknameSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doPasswordFund(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doPasswordSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); + TransactionEngineResult doPayment(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doStore(const SerializedTransaction& txn, entryMap& emEntries); + TransactionEngineResult doTake(const SerializedTransaction& txn, entryMap& emEntries); + TransactionEngineResult doWalletAdd(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); public: TransactionEngine() { ; } diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 0f23fb7693..4f9675a093 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -56,8 +56,8 @@ TransactionFormat InnerTxnFormats[]= }, { "OfferCreate", ttOFFER_CREATE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(AmountIn), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(AmountOut), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 2 }, { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 4 }, From 81def6601f034cd8279fa625e776e0dbc69c0c21 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 13 Jul 2012 15:32:03 -0700 Subject: [PATCH 4/6] Create transactions offer_create & offer_cancel. --- src/NetworkOPs.cpp | 1 - src/Transaction.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++ src/Transaction.h | 32 +++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index c3769027d3..f523274ba3 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -360,7 +360,6 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis ++ourVC.nodesUsing; ourVC.highNode = theApp->getWallet().getNodePublic(); } - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) { diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 483cc61043..5184bec5d1 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -302,6 +302,75 @@ Transaction::pointer Transaction::sharedNicknameSet( return tResult->setNicknameSet(naPrivateKey, uNickname, bSetOffer, saMinimumOffer, vucSignature); } +// +// OfferCreate +// + +Transaction::pointer Transaction::setOfferCreate( + const NewcoinAddress& naPrivateKey, + bool bPassive, + const STAmount& saTakerPays, + const STAmount& saTakerGets, + uint32 uExpiration) +{ + if (bPassive) + mTransaction->setITFieldU32(sfFlags, tfPassive); + + mTransaction->setITFieldAmount(sfTakerPays, saTakerPays); + mTransaction->setITFieldAmount(sfTakerGets, saTakerGets); + mTransaction->setITFieldAccount(sfPaysIssuer, saTakerPays.getIssuer()); + mTransaction->setITFieldAccount(sfGetsIssuer, saTakerGets.getIssuer()); + mTransaction->setITFieldU32(sfExpiration, uExpiration); + + sign(naPrivateKey); + + return shared_from_this(); +} + +Transaction::pointer Transaction::sharedOfferCreate( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + const STAmount& saFee, + uint32 uSourceTag, + bool bPassive, + const STAmount& saTakerPays, + const STAmount& saTakerGets, + uint32 uExpiration) +{ + pointer tResult = boost::make_shared(ttOFFER_CREATE, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag); + + return tResult->setOfferCreate(naPrivateKey, bPassive, saTakerPays, saTakerGets, uExpiration); +} + +// +// OfferCancel +// + +Transaction::pointer Transaction::setOfferCancel( + const NewcoinAddress& naPrivateKey, + uint32 uSequence) +{ + mTransaction->setITFieldU32(sfSequence, uSequence); + + sign(naPrivateKey); + + return shared_from_this(); +} + +Transaction::pointer Transaction::sharedOfferCancel( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + const STAmount& saFee, + uint32 uSourceTag, + uint32 uSequence) +{ + pointer tResult = boost::make_shared(ttOFFER_CANCEL, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag); + + return tResult->setOfferCancel(naPrivateKey, uSequence); +} + // // PasswordFund // diff --git a/src/Transaction.h b/src/Transaction.h index 02f2562819..f867ffd260 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -78,6 +78,17 @@ private: const STAmount& saMinimumOffer, const std::vector& vucSignature); + Transaction::pointer setOfferCreate( + const NewcoinAddress& naPrivateKey, + bool bPassive, + const STAmount& saTakerPays, + const STAmount& saTakerGets, + uint32 uExpiration); + + Transaction::pointer setOfferCancel( + const NewcoinAddress& naPrivateKey, + uint32 uSequence); + Transaction::pointer setPasswordFund( const NewcoinAddress& naPrivateKey, const NewcoinAddress& naDstAccountID); @@ -200,6 +211,27 @@ public: const STAmount& saSendMax, const STPathSet& saPaths); + // Place an offer. + static Transaction::pointer sharedOfferCreate( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + const STAmount& saFee, + uint32 uSourceTag, + bool bPassive, + const STAmount& saTakerPays, + const STAmount& saTakerGets, + uint32 uExpiration); + + // Cancel an offer + static Transaction::pointer sharedOfferCancel( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + const STAmount& saFee, + uint32 uSourceTag, + uint32 uSequence); + // Add an account to a wallet. static Transaction::pointer sharedWalletAdd( const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, From bbea33f3c27c0a54e7e1ca27b995eaa3103e78ec Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 13 Jul 2012 15:32:32 -0700 Subject: [PATCH 5/6] Implement RPC commands offer_create & offer_cancel. --- src/RPCServer.cpp | 266 ++++++++++++++++++++++++++++++++-------------- src/RPCServer.h | 6 +- src/main.cpp | 2 + 3 files changed, 196 insertions(+), 78 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index b5acd690cf..cc2ccf9300 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -38,41 +38,45 @@ Json::Value RPCServer::RPCError(int iError) const char* pToken; const char* pMessage; } errorInfoA[] = { - { rpcACT_EXISTS, "actExists", "Account already exists." }, - { rpcACT_MALFORMED, "actMalformed", "Account malformed." }, - { rpcACT_NOT_FOUND, "actNotFound", "Account not found." }, - { rpcBAD_SEED, "badSeed", "Disallowed seed." }, - { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, - { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, - { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, - { rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." }, - { rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." }, - { rpcINTERNAL, "internal", "Internal error." }, - { rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." }, - { rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." }, - { rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." }, - { rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." }, - { rpcNICKNAME_MALFORMED,"nicknameMalformed","Nickname is malformed." }, - { rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." }, - { rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." }, - { rpcNOT_IMPL, "notImpl", "Not implemented." }, - { rpcNO_ACCOUNT, "noAccount", "No such account." }, - { rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." }, - { rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." }, - { rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." }, - { rpcNO_NETWORK, "noNetwork", "Network not available." }, - { rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." }, - { rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." }, - { rpcPORT_MALFORMED, "portMalformed", "Port is malformed." }, - { rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." }, - { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, - { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, - { rpcSRC_MISSING, "srcMissing", "Source account does not exist." }, - { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, - { rpcSUCCESS, "success", "Success." }, - { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, - { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown command." }, - { rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." }, + { rpcACT_EXISTS, "actExists", "Account already exists." }, + { rpcACT_MALFORMED, "actMalformed", "Account malformed." }, + { rpcACT_NOT_FOUND, "actNotFound", "Account not found." }, + { rpcBAD_SEED, "badSeed", "Disallowed seed." }, + { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, + { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, + { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, + { rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." }, + { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets ammount malformed." }, + { rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." }, + { rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." }, + { rpcINTERNAL, "internal", "Internal error." }, + { rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." }, + { rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." }, + { rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." }, + { rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." }, + { rpcNICKNAME_MALFORMED, "nicknameMalformed","Nickname is malformed." }, + { rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." }, + { rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." }, + { rpcNOT_IMPL, "notImpl", "Not implemented." }, + { rpcNO_ACCOUNT, "noAccount", "No such account." }, + { rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." }, + { rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." }, + { rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." }, + { rpcNO_NETWORK, "noNetwork", "Network not available." }, + { rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." }, + { rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." }, + { rpcPAYS_ACT_MALFORMED, "paysActMalformed", "Pays account malformed." }, + { rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed." }, + { rpcPORT_MALFORMED, "portMalformed", "Port is malformed." }, + { rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." }, + { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, + { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, + { rpcSRC_MISSING, "srcMissing", "Source account does not exist." }, + { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, + { rpcSUCCESS, "success", "Success." }, + { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, + { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown command." }, + { rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." }, }; int i; @@ -826,14 +830,122 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) return obj; } -Json::Value RPCServer::doOffer(const Json::Value ¶ms) +// offer_create [passive] +Json::Value RPCServer::doOfferCreate(const Json::Value ¶ms) { - return RPCError(rpcNOT_IMPL); + NewcoinAddress naSeed; + NewcoinAddress naSrcAccountID; + STAmount saTakerPays; + STAmount saTakerGets; + NewcoinAddress naTakerPaysID; + NewcoinAddress naTakerGetsID; + + if (!naSeed.setSeedGeneric(params[0u].asString())) + { + return RPCError(rpcBAD_SEED); + } + else if (!naSrcAccountID.setAccountID(params[1u].asString())) + { + return RPCError(rpcSRC_ACT_MALFORMED); + } + else if (!saTakerPays.setValue(params[2u].asString(), params[3u].asString())) + { + return RPCError(rpcPAYS_AMT_MALFORMED); + } + else if (!naTakerPaysID.setAccountID(params[4u].asString())) + { + return RPCError(rpcPAYS_ACT_MALFORMED); + } + else if (!saTakerGets.setValue(params[5u].asString(), params[6u].asString())) + { + return RPCError(rpcGETS_AMT_MALFORMED); + } + else if (!naTakerGetsID.setAccountID(params[7u].asString())) + { + return RPCError(rpcGETS_ACT_MALFORMED); + } + else if (params.size() == 10 && params[9u].asString() != "passive") + { + return RPCError(rpcINVALID_PARAMS); + } + + uint32 uExpiration = lexical_cast_s(params[8u].asString()); + bool bPassive = params.size() == 10; + + saTakerPays.setIssuer(naTakerPaysID.getAccountID()); + saTakerGets.setIssuer(naTakerGetsID.getAccountID()); + + NewcoinAddress naMasterGenerator; + NewcoinAddress naAccountPublic; + NewcoinAddress naAccountPrivate; + AccountState::pointer asSrc; + STAmount saSrcBalance; + Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); + + if (!obj.empty()) + return obj; + + Transaction::pointer trans = Transaction::sharedOfferCreate( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + theConfig.FEE_DEFAULT, + 0, // YYY No source tag + bPassive, + saTakerPays, + saTakerGets, + uExpiration); + + (void) mNetOps->processTransaction(trans); + + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); + + return obj; } +// offer_cancel Json::Value RPCServer::doOfferCancel(const Json::Value ¶ms) { - return RPCError(rpcNOT_IMPL); + NewcoinAddress naSeed; + NewcoinAddress naSrcAccountID; + uint32 uSequence = lexical_cast_s(params[1u].asString()); + + if (!naSeed.setSeedGeneric(params[0u].asString())) + { + return RPCError(rpcBAD_SEED); + } + else if (!naSrcAccountID.setAccountID(params[1u].asString())) + { + return RPCError(rpcSRC_ACT_MALFORMED); + } + + NewcoinAddress naMasterGenerator; + NewcoinAddress naAccountPublic; + NewcoinAddress naAccountPrivate; + AccountState::pointer asSrc; + STAmount saSrcBalance; + Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); + + if (!obj.empty()) + return obj; + + Transaction::pointer trans = Transaction::sharedOfferCancel( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + theConfig.FEE_DEFAULT, + 0, // YYY No source tag + uSequence); + + (void) mNetOps->processTransaction(trans); + + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); + + return obj; } // password_fund [] @@ -1978,49 +2090,49 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params bool mAdminRequired; unsigned int iOptions; } commandsA[] = { - { "account_email_set", &RPCServer::doAccountEmailSet, 2, 3, false, optCurrent }, - { "account_info", &RPCServer::doAccountInfo, 1, 2, false, optCurrent }, - { "account_message_set", &RPCServer::doAccountMessageSet, 3, 3, false, optCurrent }, - { "account_tx", &RPCServer::doAccountTransactions, 2, 3, false, optNetwork }, - { "account_wallet_set", &RPCServer::doAccountWalletSet, 2, 3, false, optCurrent }, - { "connect", &RPCServer::doConnect, 1, 2, true }, - { "data_delete", &RPCServer::doDataDelete, 1, 1, true }, - { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, - { "data_store", &RPCServer::doDataStore, 2, 2, true }, - { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, - { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, - { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, - { "offer", &RPCServer::doOffer, 7, 8, false, optCurrent }, - { "offer_cancel", &RPCServer::doOfferCancel, 3, 3, false, optCurrent }, - { "password_fund", &RPCServer::doPasswordFund, 2, 3, false, optCurrent }, - { "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork }, - { "peers", &RPCServer::doPeers, 0, 0, true }, - { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent|optClosed }, - { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 6, false, optCurrent }, - { "send", &RPCServer::doSend, 3, 7, false, optCurrent }, - { "server_info", &RPCServer::doServerInfo, 0, 0, true }, - { "stop", &RPCServer::doStop, 0, 0, true }, - { "tx", &RPCServer::doTx, 1, 1, true }, + { "account_email_set", &RPCServer::doAccountEmailSet, 2, 3, false, optCurrent }, + { "account_info", &RPCServer::doAccountInfo, 1, 2, false, optCurrent }, + { "account_message_set", &RPCServer::doAccountMessageSet, 3, 3, false, optCurrent }, + { "account_tx", &RPCServer::doAccountTransactions, 2, 3, false, optNetwork }, + { "account_wallet_set", &RPCServer::doAccountWalletSet, 2, 3, false, optCurrent }, + { "connect", &RPCServer::doConnect, 1, 2, true }, + { "data_delete", &RPCServer::doDataDelete, 1, 1, true }, + { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, + { "data_store", &RPCServer::doDataStore, 2, 2, true }, + { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, + { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, + { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, + { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, + { "offer_cancel", &RPCServer::doOfferCancel, 3, 3, false, optCurrent }, + { "password_fund", &RPCServer::doPasswordFund, 2, 3, false, optCurrent }, + { "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork }, + { "peers", &RPCServer::doPeers, 0, 0, true }, + { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent|optClosed }, + { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 6, false, optCurrent }, + { "send", &RPCServer::doSend, 3, 7, false, optCurrent }, + { "server_info", &RPCServer::doServerInfo, 0, 0, true }, + { "stop", &RPCServer::doStop, 0, 0, true }, + { "tx", &RPCServer::doTx, 1, 1, true }, - { "unl_add", &RPCServer::doUnlAdd, 1, 2, true }, - { "unl_delete", &RPCServer::doUnlDelete, 1, 1, true }, - { "unl_list", &RPCServer::doUnlList, 0, 0, true }, - { "unl_load", &RPCServer::doUnlLoad, 0, 0, true }, - { "unl_network", &RPCServer::doUnlNetwork, 0, 0, true }, - { "unl_reset", &RPCServer::doUnlReset, 0, 0, true }, - { "unl_score", &RPCServer::doUnlScore, 0, 0, true }, + { "unl_add", &RPCServer::doUnlAdd, 1, 2, true }, + { "unl_delete", &RPCServer::doUnlDelete, 1, 1, true }, + { "unl_list", &RPCServer::doUnlList, 0, 0, true }, + { "unl_load", &RPCServer::doUnlLoad, 0, 0, true }, + { "unl_network", &RPCServer::doUnlNetwork, 0, 0, true }, + { "unl_reset", &RPCServer::doUnlReset, 0, 0, true }, + { "unl_score", &RPCServer::doUnlScore, 0, 0, true }, - { "validation_create", &RPCServer::doValidationCreate, 0, 1, false }, - { "validation_seed", &RPCServer::doValidationSeed, 0, 1, false }, + { "validation_create", &RPCServer::doValidationCreate, 0, 1, false }, + { "validation_seed", &RPCServer::doValidationSeed, 0, 1, false }, - { "wallet_accounts", &RPCServer::doWalletAccounts, 1, 1, false, optCurrent }, - { "wallet_add", &RPCServer::doWalletAdd, 3, 5, false, optCurrent }, - { "wallet_claim", &RPCServer::doWalletClaim, 2, 4, false, optNetwork }, - { "wallet_create", &RPCServer::doWalletCreate, 3, 4, false, optCurrent }, - { "wallet_propose", &RPCServer::doWalletPropose, 0, 0, false, }, - { "wallet_seed", &RPCServer::doWalletSeed, 0, 1, false, }, + { "wallet_accounts", &RPCServer::doWalletAccounts, 1, 1, false, optCurrent }, + { "wallet_add", &RPCServer::doWalletAdd, 3, 5, false, optCurrent }, + { "wallet_claim", &RPCServer::doWalletClaim, 2, 4, false, optNetwork }, + { "wallet_create", &RPCServer::doWalletCreate, 3, 4, false, optCurrent }, + { "wallet_propose", &RPCServer::doWalletPropose, 0, 0, false, }, + { "wallet_seed", &RPCServer::doWalletSeed, 0, 1, false, }, - { "login", &RPCServer::doLogin, 2, 2, true }, + { "login", &RPCServer::doLogin, 2, 2, true }, }; int i = NUMBER(commandsA); diff --git a/src/RPCServer.h b/src/RPCServer.h index fa6be57e9d..eda4e403b8 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -51,11 +51,15 @@ public: rpcBAD_SEED, rpcDST_ACT_MALFORMED, rpcDST_AMT_MALFORMED, + rpcGETS_ACT_MALFORMED, + rpcGETS_AMT_MALFORMED, rpcHOST_IP_MALFORMED, rpcLGR_IDXS_INVALID, rpcLGR_IDX_MALFORMED, rpcNICKNAME_MALFORMED, rpcNICKNAME_PERM, + rpcPAYS_ACT_MALFORMED, + rpcPAYS_AMT_MALFORMED, rpcPORT_MALFORMED, rpcPUBLIC_MALFORMED, rpcSRC_ACT_MALFORMED, @@ -133,7 +137,7 @@ private: Json::Value doLedger(const Json::Value& params); Json::Value doNicknameInfo(const Json::Value& params); Json::Value doNicknameSet(const Json::Value& params); - Json::Value doOffer(const Json::Value& params); + Json::Value doOfferCreate(const Json::Value& params); Json::Value doOfferCancel(const Json::Value& params); Json::Value doPasswordFund(const Json::Value& params); Json::Value doPasswordSet(const Json::Value& params); diff --git a/src/main.cpp b/src/main.cpp index 75832a912b..bbaeb190d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,6 +50,8 @@ void printHelp(const po::options_description& desc) cout << " ledger [|current|lastclosed] [full]" << endl; cout << " nickname_info " << endl; cout << " nickname_set [] []" << endl; + cout << " offer_create [passive]" << endl; + cout << " offer_cancel " << endl; cout << " password_fund []" << endl; cout << " password_set []" << endl; cout << " peers" << endl; From d3e1b98fe859cf4ea07263dd20b4273617d88177 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 13 Jul 2012 23:01:26 -0700 Subject: [PATCH 6/6] Bug fixes for offer_create and offer_cancel. --- src/LedgerFormats.cpp | 7 +- src/LedgerIndex.cpp | 4 +- src/NewcoinAddress.cpp | 11 +- src/RPCServer.cpp | 2 +- src/SerializedObject.h | 1 + src/Transaction.cpp | 14 +- src/TransactionEngine.cpp | 364 ++++++++++++++++++++----------------- src/TransactionEngine.h | 41 ++--- src/TransactionFormats.cpp | 9 +- 9 files changed, 248 insertions(+), 205 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 7a588be8a3..e1ad188de8 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -48,9 +48,12 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(Directory), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(BookNode), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(PaysIssuer), STI_ACCOUNT, SOE_IFFLAG, 1 }, + { S_FIELD(GetsIssuer), STI_ACCOUNT, SOE_IFFLAG, 2 }, + { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp index 91365ef9b9..ac059297c9 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -48,8 +48,8 @@ uint256 Ledger::getBookBase(const uint160& uCurrencyIn, const uint160& uAccountI bool bOutNative = uCurrencyOut.isZero(); assert(!bInNative || !bOutNative); // Stamps to stamps not allowed. - assert(bInNative == !uAccountIn.isZero()); // Make sure issuer is specified as needed. - assert(bOutNative == !uAccountOut.isZero()); // Make sure issuer is specified as needed. + assert(bInNative == uAccountIn.isZero()); // Make sure issuer is specified as needed. + assert(bOutNative == uAccountOut.isZero()); // Make sure issuer is specified as needed. assert(uCurrencyIn != uCurrencyOut || uAccountIn != uAccountOut); // Currencies or accounts must differ. Serializer s(82); diff --git a/src/NewcoinAddress.cpp b/src/NewcoinAddress.cpp index 88536a33c2..70eca319c7 100644 --- a/src/NewcoinAddress.cpp +++ b/src/NewcoinAddress.cpp @@ -302,7 +302,16 @@ std::string NewcoinAddress::humanAccountID() const bool NewcoinAddress::setAccountID(const std::string& strAccountID) { - return SetString(strAccountID.c_str(), VER_ACCOUNT_ID); + if (strAccountID == "none") + { + SetData(VER_ACCOUNT_ID, std::vector()); + + return true; + } + else + { + return SetString(strAccountID.c_str(), VER_ACCOUNT_ID); + } } void NewcoinAddress::setAccountID(const uint160& hash160) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index cc2ccf9300..d91a13e0cd 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -910,7 +910,7 @@ Json::Value RPCServer::doOfferCancel(const Json::Value ¶ms) { NewcoinAddress naSeed; NewcoinAddress naSrcAccountID; - uint32 uSequence = lexical_cast_s(params[1u].asString()); + uint32 uSequence = lexical_cast_s(params[2u].asString()); if (!naSeed.setSeedGeneric(params[0u].asString())) { diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 0fbd85e1db..884a492e18 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -42,6 +42,7 @@ enum SOE_Field sfCurrencyIn, sfCurrencyOut, sfDestination, + sfDirectory, sfDomain, sfEmailHash, sfExpiration, diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 5184bec5d1..a1fdfc41bd 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -318,9 +318,15 @@ Transaction::pointer Transaction::setOfferCreate( mTransaction->setITFieldAmount(sfTakerPays, saTakerPays); mTransaction->setITFieldAmount(sfTakerGets, saTakerGets); - mTransaction->setITFieldAccount(sfPaysIssuer, saTakerPays.getIssuer()); - mTransaction->setITFieldAccount(sfGetsIssuer, saTakerGets.getIssuer()); - mTransaction->setITFieldU32(sfExpiration, uExpiration); + + if (!saTakerPays.isNative()) + mTransaction->setITFieldAccount(sfPaysIssuer, saTakerPays.getIssuer()); + + if (!saTakerGets.isNative()) + mTransaction->setITFieldAccount(sfGetsIssuer, saTakerGets.getIssuer()); + + if (uExpiration) + mTransaction->setITFieldU32(sfExpiration, uExpiration); sign(naPrivateKey); @@ -351,7 +357,7 @@ Transaction::pointer Transaction::setOfferCancel( const NewcoinAddress& naPrivateKey, uint32 uSequence) { - mTransaction->setITFieldU32(sfSequence, uSequence); + mTransaction->setITFieldU32(sfOfferSequence, uSequence); sign(naPrivateKey); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 0d270927fb..436fa8f9ae 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -103,7 +103,7 @@ STAmount TransactionEngine::rippleBalance(const uint160& uAccountID, const uint1 return saBalance; } -void TransactionEngine::rippleCredit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saCredit) +void TransactionEngine::rippleCredit(const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saCredit) { uint256 uIndex = Ledger::getRippleStateIndex(uAccountID, uIssuerAccountID, uCurrency); LedgerStateParms qry = lepNONE; @@ -114,7 +114,9 @@ void TransactionEngine::rippleCredit(entryMap& emEntries, const uint160& uAccoun { STAmount saBalance = saCredit; - sleRippleState = entryCreate(ltRIPPLE_STATE); + sleRippleState = entryCreate(ltRIPPLE_STATE, uIndex); + + Log(lsINFO) << "rippleCredit: Creating ripple line: " << uIndex.ToString(); if (!bFlipped) saBalance.negate(); @@ -141,23 +143,21 @@ void TransactionEngine::rippleCredit(entryMap& emEntries, const uint160& uAccoun } } -void TransactionEngine::rippleDebit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saDebit) +void TransactionEngine::rippleDebit(const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saDebit) { STAmount saCredit = saDebit; saCredit.negate(); - rippleCredit(emEntries, uAccountID, uIssuerAccountID, uCurrency, saCredit); + rippleCredit(uAccountID, uIssuerAccountID, uCurrency, saCredit); } -// <-> emEntries: Affected accounts for the transaction. // <-- uNodeDir: For deletion, present to make dirDelete efficient. // --> uRootIndex: The index of the base of the directory. Nodes are based off of this. // --> uLedgerIndex: Value to add to directory. // We only append. This allow for things that watch append only structure to just monitor from the last node on ward. // Within a node with no deletions order of elements is sequential. Otherwise, order of elements is random. TransactionEngineResult TransactionEngine::dirAdd( - entryMap& emEntries, uint64& uNodeDir, const uint256& uRootIndex, const uint256& uLedgerIndex) @@ -170,12 +170,9 @@ TransactionEngineResult TransactionEngine::dirAdd( if (!sleRoot) { // No root, make it. - Log(lsTRACE) << "dirAdd: Creating dir root: " << uRootIndex.ToString(); - uNodeDir = 0; - sleRoot = entryCreate(ltDIR_NODE); - sleRoot->setIndex(uRootIndex); + sleRoot = entryCreate(ltDIR_NODE, uRootIndex); sleNode = sleRoot; } @@ -230,8 +227,7 @@ TransactionEngineResult TransactionEngine::dirAdd( // Create the new node. svIndexes = STVector256(); - sleNode = entryCreate(ltDIR_NODE); - sleNode->setIndex(uNodeIndex); + sleNode = entryCreate(ltDIR_NODE, uNodeIndex); if (uNodePrevious) sleNode->setIFieldU64(sfIndexPrevious, uNodePrevious); @@ -241,20 +237,19 @@ TransactionEngineResult TransactionEngine::dirAdd( svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. sleNode->setIFieldV256(sfIndexes, svIndexes); // Save entry. - Log(lsTRACE) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); - Log(lsTRACE) << "dirAdd: appending: Node: " << strHex(uNodeDir); - Log(lsTRACE) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); + Log(lsINFO) << "dirAdd: creating: root: " << uRootIndex.ToString(); + Log(lsINFO) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); + Log(lsINFO) << "dirAdd: appending: Node: " << strHex(uNodeDir); + // Log(lsINFO) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); return terSUCCESS; } -// <-> emEntries: Affected accounts for the transaction. // --> uNodeDir: Node containing entry. // --> uRootIndex: The index of the base of the directory. Nodes are based off of this. // --> uLedgerIndex: Value to add to directory. // Ledger must be in a state for this to work. TransactionEngineResult TransactionEngine::dirDelete( - entryMap& emEntries, const uint64& uNodeDir, const uint256& uRootIndex, const uint256& uLedgerIndex) @@ -432,7 +427,7 @@ TransactionEngineResult TransactionEngine::dirDelete( } // Set the authorized public ket for an account. May also set the generator map. -TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, bool bMustSetGenerator) +TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransaction& txn, SLE::pointer sleSrc, bool bMustSetGenerator) { // // Verify that submitter knows the private key for the generator. @@ -458,11 +453,11 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac SLE::pointer sleGen = mLedger->getGenerator(qry, hGeneratorID); if (!sleGen) { - Log(lsTRACE) << "createGenerator: creating generator"; // Create the generator. - sleGen = entryCreate(ltGENERATOR_MAP); + Log(lsTRACE) << "createGenerator: creating generator"; + + sleGen = entryCreate(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); - sleGen->setIndex(Ledger::getGeneratorIndex(hGeneratorID)); sleGen->setIFieldVL(sfGenerator, vucCipher); } else if (bMustSetGenerator) @@ -501,10 +496,12 @@ bool TransactionEngine::entryExists(SLE::pointer sleEntry) return mEntries.find(sleEntry) != mEntries.end(); } -SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType) +SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint256& uIndex) { SLE::pointer sleNew = boost::make_shared(letType); + sleNew->setIndex(uIndex); + mEntries[sleNew] = taaCREATE; return sleNew; @@ -607,14 +604,14 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } #endif - TransactionEngineResult result = terSUCCESS; + TransactionEngineResult terResult = terSUCCESS; uint256 txID = txn.getTransactionID(); if (!txID) { Log(lsWARNING) << "applyTransaction: invalid transaction id"; - result = tenINVALID; + terResult = tenINVALID; } // @@ -628,21 +625,21 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // XXX This could be a lot cleaner to prevent unnecessary copying. NewcoinAddress naSigningPubKey; - if (terSUCCESS == result) + if (terSUCCESS == terResult) naSigningPubKey = NewcoinAddress::createAccountPublic(txn.peekSigningPubKey()); // Consistency: really signed. - if (terSUCCESS == result && !txn.checkSign(naSigningPubKey)) + if (terSUCCESS == terResult && !txn.checkSign(naSigningPubKey)) { Log(lsWARNING) << "applyTransaction: Invalid transaction: bad signature"; - result = tenINVALID; + terResult = tenINVALID; } STAmount saCost = theConfig.FEE_DEFAULT; // Customize behavoir based on transaction type. - if (terSUCCESS == result) + if (terSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -680,19 +677,19 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttINVALID: Log(lsWARNING) << "applyTransaction: Invalid transaction: ttINVALID transaction type"; - result = tenINVALID; + terResult = tenINVALID; break; default: Log(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type"; - result = tenUNKNOWN; + terResult = tenUNKNOWN; break; } } STAmount saPaid = txn.getTransactionFee(); - if (terSUCCESS == result && (params & tepNO_CHECK_FEE) == tepNONE) + if (terSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE) { if (!saCost.isZero()) { @@ -700,7 +697,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsINFO) << "applyTransaction: insufficient fee"; - result = tenINSUF_FEE_P; + terResult = tenINSUF_FEE_P; } } else @@ -710,26 +707,26 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // Transaction is malformed. Log(lsWARNING) << "applyTransaction: fee not allowed"; - result = tenINSUF_FEE_P; + terResult = tenINSUF_FEE_P; } } } // Get source account ID. uint160 srcAccountID = txn.getSourceAccount().getAccountID(); - if (terSUCCESS == result && !srcAccountID) + if (terSUCCESS == terResult && !srcAccountID) { Log(lsWARNING) << "applyTransaction: bad source id"; - result = tenINVALID; + terResult = tenINVALID; } - if (terSUCCESS != result) + if (terSUCCESS != terResult) { // Avoid unnecessary locking. mLedger = Ledger::pointer(); - return result; + return terResult; } boost::recursive_mutex::scoped_lock sl(mLedger->mLock); @@ -748,7 +745,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsTRACE) << str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") % txn.getSourceAccount().humanAccountID()); - result = terNO_ACCOUNT; + terResult = terNO_ACCOUNT; } else { @@ -757,7 +754,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Check if account cliamed. - if (terSUCCESS == result) + if (terSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -766,7 +763,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsWARNING) << "applyTransaction: Account already claimed."; - result = tenCLAIMED; + terResult = tenCLAIMED; } break; @@ -777,7 +774,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Consistency: Check signature - if (terSUCCESS == result) + if (terSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -790,7 +787,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID(); Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID(); - result = tenBAD_CLAIM_ID; + terResult = tenBAD_CLAIM_ID; } break; @@ -803,7 +800,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID(); Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID(); - result = tenBAD_SET_ID; + terResult = tenBAD_SET_ID; } break; @@ -823,13 +820,13 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { std::cerr << "applyTransaction: Delay: Not authorized to use account." << std::endl; - result = terBAD_AUTH; + terResult = terBAD_AUTH; } else { std::cerr << "applyTransaction: Invalid: Not authorized to use account." << std::endl; - result = terBAD_AUTH_MASTER; + terResult = terBAD_AUTH_MASTER; } break; } @@ -837,7 +834,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // Deduct the fee, so it's not available during the transaction. // Will only write the account back, if the transaction succeeds. - if (terSUCCESS != result || saCost.isZero()) + if (terSUCCESS != terResult || saCost.isZero()) { nothing(); } @@ -849,7 +846,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran % saPaid.getText()) << std::endl; - result = terINSUF_FEE_B; + terResult = terINSUF_FEE_B; } else { @@ -857,33 +854,35 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Validate sequence - if (terSUCCESS != result) + if (terSUCCESS != terResult) { nothing(); } else if (!saCost.isZero()) { uint32 a_seq = sleSrc->getIFieldU32(sfSequence); + Log(lsTRACE) << "Aseq=" << a_seq << ", Tseq=" << t_seq; + if (t_seq != a_seq) { if (a_seq < t_seq) { - Log(lsTRACE) << "applyTransaction: future sequence number"; + Log(lsINFO) << "applyTransaction: future sequence number"; - result = terPRE_SEQ; + terResult = terPRE_SEQ; } else if (mLedger->hasTransaction(txID)) { - std::cerr << "applyTransaction: duplicate sequence number" << std::endl; + Log(lsWARNING) << "applyTransaction: duplicate sequence number"; - result = terALREADY; + terResult = terALREADY; } else { - std::cerr << "applyTransaction: past sequence number" << std::endl; + Log(lsWARNING) << "applyTransaction: past sequence number"; - result = terPAST_SEQ; + terResult = terPAST_SEQ; } } else @@ -893,81 +892,87 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } else { - Log(lsINFO) << "Zero cost transaction"; + Log(lsINFO) << "applyTransaction: Zero cost transaction"; + if (t_seq) { std::cerr << "applyTransaction: bad sequence for pre-paid transaction" << std::endl; - result = terPAST_SEQ; + terResult = terPAST_SEQ; } } - entryMap emEntries; - - if (terSUCCESS == result) + if (terSUCCESS == terResult) { entryModify(sleSrc); switch(txn.getTxnType()) { case ttACCOUNT_SET: - result = doAccountSet(txn, emEntries, sleSrc); + terResult = doAccountSet(txn, sleSrc); break; case ttCLAIM: - result = doClaim(txn, emEntries, sleSrc); + terResult = doClaim(txn, sleSrc); break; case ttCREDIT_SET: - result = doCreditSet(txn, emEntries, srcAccountID); + terResult = doCreditSet(txn, srcAccountID); break; case ttINVALID: std::cerr << "applyTransaction: invalid type" << std::endl; - result = tenINVALID; + terResult = tenINVALID; break; case ttINVOICE: - result = doInvoice(txn, emEntries); + terResult = doInvoice(txn); break; case ttOFFER_CREATE: - result = doOfferCreate(txn, emEntries, sleSrc, srcAccountID); + terResult = doOfferCreate(txn, sleSrc, srcAccountID); break; case ttOFFER_CANCEL: - result = doOfferCancel(txn, emEntries, srcAccountID); + terResult = doOfferCancel(txn, srcAccountID); break; case ttNICKNAME_SET: - result = doNicknameSet(txn, emEntries, sleSrc, srcAccountID); + terResult = doNicknameSet(txn, sleSrc, srcAccountID); break; case ttPASSWORD_FUND: - result = doPasswordFund(txn, emEntries, sleSrc, srcAccountID); + terResult = doPasswordFund(txn, sleSrc, srcAccountID); break; case ttPASSWORD_SET: - result = doPasswordSet(txn, emEntries, sleSrc); + terResult = doPasswordSet(txn, sleSrc); break; case ttPAYMENT: - result = doPayment(txn, emEntries, sleSrc, srcAccountID); + terResult = doPayment(txn, sleSrc, srcAccountID); break; case ttWALLET_ADD: - result = doWalletAdd(txn, emEntries, sleSrc); + terResult = doWalletAdd(txn, sleSrc); break; default: - result = tenUNKNOWN; + terResult = tenUNKNOWN; break; } } + std::string strToken; + std::string strHuman; + + transResultInfo(terResult, strToken, strHuman); + + Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman; + bool bWrite = false; - if (terSUCCESS != result) + if (terSUCCESS != terResult) { BOOST_FOREACH(entryMap_value_type it, mEntries) { @@ -999,7 +1004,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } } - if (terSUCCESS == result) + if (terSUCCESS == terResult) { // Write back the account states and add the transaction to the ledger bWrite = true; @@ -1066,11 +1071,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } mLedger = Ledger::pointer(); + mEntries.clear(); - return result; + return terResult; } -TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc) +TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransaction& txn, SLE::pointer sleSrc) { std::cerr << "doAccountSet>" << std::endl; @@ -1137,21 +1143,18 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact return terSUCCESS; } -TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn, - entryMap& emEntries, SLE::pointer sleSrc) +TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn, SLE::pointer sleSrc) { std::cerr << "doClaim>" << std::endl; - TransactionEngineResult result = setAuthorized(txn, emEntries, sleSrc, true); + TransactionEngineResult terResult = setAuthorized(txn, sleSrc, true); std::cerr << "doClaim<" << std::endl; - return result; + return terResult; } -TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransaction& txn, - entryMap& emEntries, - const uint160& uSrcAccountID) +TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransaction& txn, const uint160& uSrcAccountID) { TransactionEngineResult terResult = terSUCCESS; Log(lsINFO) << "doCreditSet>"; @@ -1213,7 +1216,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti // Zero balance and eliminating last limit. bDelIndex = true; - terResult = dirDelete(emEntries, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); + terResult = dirDelete(uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); } } #endif @@ -1243,12 +1246,10 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti // Create a new ripple line. STAmount saZero(uCurrency); - bAddIndex = true; - sleRippleState = entryCreate(ltRIPPLE_STATE); + bAddIndex = true; + sleRippleState = entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uSrcAccountID, uDstAccountID, uCurrency)); - sleRippleState->setIndex(Ledger::getRippleStateIndex(uSrcAccountID, uDstAccountID, uCurrency)); - Log(lsINFO) << "doCreditSet: Creating ripple line: " - << sleRippleState->getIndex().ToString(); + Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); sleRippleState->setFlag(uFlags); sleRippleState->setIFieldAmount(sfBalance, saZero); // Zero balance in currency. @@ -1263,7 +1264,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti uint64 uSrcRef; // Ignored, ripple_state dirs never delete. // XXX Make dirAdd more flexiable to take vector. - terResult = dirAdd(emEntries, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); + terResult = dirAdd(uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); } Log(lsINFO) << "doCreditSet<"; @@ -1271,7 +1272,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti return terResult; } -TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID) +TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransaction& txn, SLE::pointer sleSrc, const uint160& uSrcAccountID) { std::cerr << "doNicknameSet>" << std::endl; @@ -1303,9 +1304,8 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac // Make a new entry. // XXX Need to include authorization limiting for first year. - sleNickname = entryCreate(ltNICKNAME); + sleNickname = entryCreate(ltNICKNAME, Ledger::getNicknameIndex(uNickname)); - sleNickname->setIndex(Ledger::getNicknameIndex(uNickname)); std::cerr << "doNicknameSet: Creating nickname node: " << sleNickname->getIndex().ToString() << std::endl; sleNickname->setIFieldAccount(sfAccount, uSrcAccountID); @@ -1319,7 +1319,7 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac return terSUCCESS; } -TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID) +TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransaction& txn, SLE::pointer sleSrc, const uint160& uSrcAccountID) { std::cerr << "doPasswordFund>" << std::endl; @@ -1354,7 +1354,7 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa return terSUCCESS; } -TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc) +TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransaction& txn, SLE::pointer sleSrc) { std::cerr << "doPasswordSet>" << std::endl; @@ -1367,11 +1367,11 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac sleSrc->setFlag(lsfPasswordSpent); - TransactionEngineResult result = setAuthorized(txn, emEntries, sleSrc, false); + TransactionEngineResult terResult = setAuthorized(txn, sleSrc, false); std::cerr << "doPasswordSet<" << std::endl; - return result; + return terResult; } #ifdef WORK_IN_PROGRESS @@ -1516,7 +1516,7 @@ bool calcPaymentForward(std::vector& pnNodes) // XXX Need to audit for things like setting accountID not having memory. TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn, - entryMap& emEntries, SLE::pointer sleSrc, + SLE::pointer sleSrc, const uint160& uSrcAccountID) { // Ripple if source or destination is non-native or if there are paths. @@ -1574,9 +1574,8 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } // Create the account. - sleDst = entryCreate(ltACCOUNT_ROOT); + sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setIndex(Ledger::getAccountRootIndex(uDstAccountID)); sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); } @@ -1683,7 +1682,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction TransactionEngineResult terResult = terSUCCESS; uint64 uSrcRef; // Ignored, ripple_state dirs never delete. - terResult = dirAdd(emEntries, + terResult = dirAdd( uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), // The source ended up owing. sleRippleState->getIndex()); // Adding current entry. @@ -1733,8 +1732,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return terBAD_RIPPLE; } -TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransaction& txn, - entryMap& emEntries, SLE::pointer sleSrc) +TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransaction& txn, SLE::pointer sleSrc) { std::cerr << "WalletAdd>" << std::endl; @@ -1779,9 +1777,8 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti sleSrc->setIFieldAmount(sfBalance, saSrcBalance-saAmount); // Create the account. - sleDst = entryCreate(ltACCOUNT_ROOT); + sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setIndex(Ledger::getAccountRootIndex(uDstAccountID)); sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); sleDst->setIFieldAmount(sfBalance, saAmount); @@ -1792,8 +1789,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti return terSUCCESS; } -TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn, - entryMap& emEntries) +TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn) { return tenUNKNOWN; } @@ -1806,7 +1802,6 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction // <-- saTakerPaid: What taker actually paid // <-- saTakerGot: What taker actually got TransactionEngineResult TransactionEngine::takeOffers( - entryMap& emEntries, bool bPassive, const uint256& uBookBase, const uint160& uTakerAccountID, @@ -1839,8 +1834,11 @@ TransactionEngineResult TransactionEngine::takeOffers( { // Taker has needs. sleOffer = mLedger->getNextSLE(uTipIndex, uBookEnd); - uTipIndex = sleOffer->getIndex(); - uTipQuality = Ledger::getQuality(uTipIndex); + if (sleOffer) + { + uTipIndex = sleOffer->getIndex(); + uTipQuality = Ledger::getQuality(uTipIndex); + } } if (!sleOffer || uTakeQuality < uTipQuality || (bPassive && uTakeQuality == uTipQuality)) @@ -1952,7 +1950,7 @@ TransactionEngineResult TransactionEngine::takeOffers( } else { - rippleDebit(emEntries, uOfferAccountID, uTakerGetsAccountID, uTakerGetsCurrency, saSubTakerGot); + rippleDebit(uOfferAccountID, uTakerGetsAccountID, uTakerGetsCurrency, saSubTakerGot); } saTakerGot += saSubTakerGot; @@ -1966,7 +1964,7 @@ TransactionEngineResult TransactionEngine::takeOffers( } else { - rippleCredit(emEntries, uOfferAccountID, uTakerPaysAccountID, uTakerPaysCurrency, saSubTakerPaid); + rippleCredit(uOfferAccountID, uTakerPaysAccountID, uTakerPaysCurrency, saSubTakerPaid); } saTakerPaid += saSubTakerPaid; } @@ -1989,10 +1987,7 @@ TransactionEngineResult TransactionEngine::takeOffers( return terResult; } -TransactionEngineResult TransactionEngine::doOfferCreate( - const SerializedTransaction& txn, - entryMap& emEntries, SLE::pointer sleSrc, - const uint160& uSrcAccountID) +TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransaction& txn, SLE::pointer sleSrc, const uint160& uSrcAccountID) { uint32 txFlags = txn.getFlags(); bool bPassive = !!(txFlags & tfPassive); @@ -2005,27 +2000,28 @@ TransactionEngineResult TransactionEngine::doOfferCreate( uint32 uSequence = txn.getSequence(); // LedgerStateParms qry = lepNONE; - SLE::pointer sleOffer = entryCreate(ltOFFER); - uint256 uLedgerIndex = Ledger::getOfferIndex(uSrcAccountID, uSequence); - Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString(); + SLE::pointer sleOffer = entryCreate(ltOFFER, uLedgerIndex); + + Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString() << " uSequence=" << uSequence; uint160 uPaysCurrency = saTakerPays.getCurrency(); uint160 uGetsCurrency = saTakerGets.getCurrency(); uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); TransactionEngineResult terResult = terSUCCESS; - uint64 uOwnerNode; // Delete hint. - uint64 uBookNode; // Delete hint. STAmount saOfferFunds; + uint256 uDirectory; // Delete hints. + uint64 uOwnerNode; + uint64 uBookNode; - if (!bHaveExpiration || !uExpiration) + if (bHaveExpiration && !uExpiration) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration"; terResult = tenBAD_EXPIRATION; } - else if (!bHaveExpiration || mLedger->getParentCloseTimeNC() >= uExpiration) + else if (bHaveExpiration && mLedger->getParentCloseTimeNC() >= uExpiration) { Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; @@ -2033,7 +2029,7 @@ TransactionEngineResult TransactionEngine::doOfferCreate( } else if (saTakerPays.isNative() && saTakerGets.isNative()) { - Log(lsWARNING) << "doOfferCreate: Malformed offer: stamps for stamps"; + Log(lsWARNING) << "doOfferCreate: Malformed offer: XNS for XNS"; terResult = tenBAD_OFFER; } @@ -2045,7 +2041,7 @@ TransactionEngineResult TransactionEngine::doOfferCreate( } else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID) { - Log(lsWARNING) << "doOfferCreate: Malformed offer: no conversion"; + Log(lsWARNING) << "doOfferCreate: Malformed offer: redundant offer"; terResult = tenREDUNDANT; } @@ -2058,14 +2054,18 @@ TransactionEngineResult TransactionEngine::doOfferCreate( else if (!saTakerGets.isNative() && uGetsIssuerID == uSrcAccountID) { // Delivering self issued IOUs. - nothing(); + + saOfferFunds = saTakerGets; } else { // Make sure signer has funds. saOfferFunds = saTakerGets.isNative() - ? sleSrc->getIValueFieldAmount(sfBalance) - : rippleBalance(uSrcAccountID, uGetsIssuerID, uGetsCurrency); + ? sleSrc->getIValueFieldAmount(sfBalance) + : rippleBalance(uSrcAccountID, uGetsIssuerID, uGetsCurrency); + + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets.isNative()=" << saTakerGets.isNative(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferFunds=" << saOfferFunds.getText(); if (!saOfferFunds.isPositive()) { @@ -2075,13 +2075,16 @@ TransactionEngineResult TransactionEngine::doOfferCreate( } } - if (terSUCCESS == terResult) + Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferFunds=" << saOfferFunds.getText(); + + if (terSUCCESS == terResult && !saTakerPays.isNative()) { - LedgerStateParms qry = lepNONE; - SLE::pointer sleRippleIn = mLedger->getAccountRoot(qry, uPaysIssuerID); - if (!sleRippleIn) + LedgerStateParms qry = lepNONE; + SLE::pointer sleTakerPays = mLedger->getAccountRoot(qry, uPaysIssuerID); + + if (!sleTakerPays) { - Log(lsWARNING) << "doOfferCreate: delay: can't receive IOUs from non-existant issuer"; + Log(lsWARNING) << "doOfferCreate: delay: can't receive IOUs from non-existant issuer: " << NewcoinAddress::createHumanAccountID(uPaysIssuerID); terResult = terNO_ACCOUNT; } @@ -2094,7 +2097,6 @@ TransactionEngineResult TransactionEngine::doOfferCreate( // Take using the parameters of the offer. terResult = takeOffers( - emEntries, bPassive, Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID), uSrcAccountID, @@ -2105,6 +2107,8 @@ TransactionEngineResult TransactionEngine::doOfferCreate( saOfferGot // How much was got. ); + Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult; + if (terSUCCESS == terResult) { saOfferFunds -= saOfferPaid; // Reduce balance. @@ -2113,11 +2117,13 @@ TransactionEngineResult TransactionEngine::doOfferCreate( saTakerPays -= saOfferGot; // Reduce payin from takers by what offer just got. // Adjust funding source. - if (!saOfferPaid.isZero()) + if (saOfferPaid.isZero()) { + Log(lsWARNING) << "doOfferCreate: takeOffers: none paid."; + nothing(); } - if (!saTakerGets.isNative() && uGetsIssuerID == uSrcAccountID) + else if (!saTakerGets.isNative() && uGetsIssuerID == uSrcAccountID) { // Delivering self-issued IOUs. nothing(); @@ -2128,15 +2134,17 @@ TransactionEngineResult TransactionEngine::doOfferCreate( } else { - rippleDebit(emEntries, uSrcAccountID, uGetsIssuerID, uGetsCurrency, saOfferPaid); + rippleDebit(uSrcAccountID, uGetsIssuerID, uGetsCurrency, saOfferPaid); } // Adjust payout target. - if (!saOfferGot.isZero()) + if (saOfferGot.isZero()) { + Log(lsWARNING) << "doOfferCreate: takeOffers: none got."; + nothing(); } - if (!saTakerPays.isNative() && uPaysIssuerID == uSrcAccountID) + else if (!saTakerPays.isNative() && uPaysIssuerID == uSrcAccountID) { // Destroying self-issued IOUs. nothing(); @@ -2147,11 +2155,17 @@ TransactionEngineResult TransactionEngine::doOfferCreate( } else { - rippleCredit(emEntries, uSrcAccountID, uPaysIssuerID, uPaysCurrency, saOfferGot); + rippleCredit(uSrcAccountID, uPaysIssuerID, uPaysCurrency, saOfferGot); } } } + // Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferFunds=" << saOfferFunds.getText(); + // Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getText(); + // Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getText(); + // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); + // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); + if (terSUCCESS == terResult && !saOfferFunds.isZero() // Still funded. && !saTakerGets.isZero() // Still offering something. @@ -2160,30 +2174,41 @@ TransactionEngineResult TransactionEngine::doOfferCreate( // We need to place the remainder of the offer into its order book. // Add offer to owner's directory. - terResult = dirAdd(emEntries, uOwnerNode, Ledger::getOwnerDirIndex(uSrcAccountID), uLedgerIndex); + terResult = dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(uSrcAccountID), uLedgerIndex); if (terSUCCESS == terResult) { - // Add offer to order book. - terResult = dirAdd( - emEntries, - uBookNode, - Ledger::getQualityIndex( + uDirectory = Ledger::getQualityIndex( Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID), - uRate), // Use original rate. - uLedgerIndex); + uRate); // Use original rate. + + // Add offer to order book. + terResult = dirAdd(uBookNode, uDirectory, uLedgerIndex); } if (terSUCCESS == terResult) { - sleOffer->setIndex(uLedgerIndex); + // Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); + // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); + // Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); + // Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); + // Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getCurrencyHuman(); + // Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getCurrencyHuman(); sleOffer->setIFieldAccount(sfAccount, uSrcAccountID); sleOffer->setIFieldU32(sfSequence, uSequence); + sleOffer->setIFieldH256(sfDirectory, uDirectory); sleOffer->setIFieldAmount(sfTakerPays, saTakerPays); sleOffer->setIFieldAmount(sfTakerGets, saTakerGets); sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); sleOffer->setIFieldU64(sfBookNode, uBookNode); + + if (!saTakerPays.isNative()) + sleOffer->setIFieldAccount(sfPaysIssuer, uPaysIssuerID); + + if (!saTakerGets.isNative()) + sleOffer->setIFieldAccount(sfGetsIssuer, uGetsIssuerID); + sleOffer->setIFieldU32(sfExpiration, uExpiration); if (bPassive) @@ -2194,12 +2219,9 @@ TransactionEngineResult TransactionEngine::doOfferCreate( return terResult; } -TransactionEngineResult TransactionEngine::doOfferCancel( - const SerializedTransaction& txn, - entryMap& emEntries, - const uint160& uSrcAccountID) +TransactionEngineResult TransactionEngine::doOfferCancel(const SerializedTransaction& txn, const uint160& uSrcAccountID) { - uint32 uSequence = txn.getITFieldU32(sfSequence); + uint32 uSequence = txn.getITFieldU32(sfOfferSequence); uint256 uLedgerIndex = Ledger::getOfferIndex(uSrcAccountID, uSequence); LedgerStateParms qry = lepNONE; @@ -2208,43 +2230,45 @@ TransactionEngineResult TransactionEngine::doOfferCancel( if (sleOffer) { + Log(lsWARNING) << "doOfferCancel: uSequence=" << uSequence; - terResult = tenUNKNOWN; -#if 0 - uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); - uint64 uOwnerNode = sleOffer->getIFieldU64(sfOfferNode); + uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); + uint64 uBookNode = sleOffer->getIFieldU64(sfBookNode); + uint256 uDirectory = sleOffer->getIFieldH256(sfDirectory); - terResult = dirDelete(emEntries, uOwnerNode, ___, uLedgerIndex); + terResult = dirDelete(uOwnerNode, Ledger::getOwnerDirIndex(uSrcAccountID), uLedgerIndex); + +// if (terSUCCESS == terResult) +// { +// terResult = dirDelete(uBookNode, uDirectory, uLedgerIndex); +// } - if (terSUCCESS == terResult) - { - terResult = dirDelete(emEntries, uOfferNode, ___, uLedgerIndex); - } -#endif entryDelete(sleOffer); } else { + Log(lsWARNING) << "doOfferCancel: offer not found: " + << NewcoinAddress::createHumanAccountID(uSrcAccountID) + << " : " << uSequence + << " : " << uLedgerIndex.ToString(); + terResult = terOFFER_NOT_FOUND; } return terResult; } -TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn, - entryMap& emEntries) +TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn) { return tenUNKNOWN; } -TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn, - entryMap& emEntries) +TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn) { return tenUNKNOWN; } -TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction& txn, - entryMap& emEntries) +TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction& txn) { return tenUNKNOWN; } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 5bc249a434..498bdcc0ac 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -98,6 +98,8 @@ enum TransactionAccountAction typedef std::pair AffectedAccount; +// One instance per ledger. +// Only one transaction applied at a time. class TransactionEngine { private: @@ -107,13 +109,11 @@ private: typedef boost::unordered_map::iterator::value_type entryMap_value_type; TransactionEngineResult dirAdd( - entryMap& emEntries, uint64& uNodeDir, // Node of entry. const uint256& uRootIndex, const uint256& uLedgerIndex); TransactionEngineResult dirDelete( - entryMap& emEntries, const uint64& uNodeDir, // Node item is mentioned in. const uint256& uRootIndex, const uint256& uLedgerIndex); // Item being deleted @@ -141,10 +141,9 @@ private: } paymentGroup; #endif - TransactionEngineResult setAuthorized(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, bool bMustSetGenerator); + TransactionEngineResult setAuthorized(const SerializedTransaction& txn, SLE::pointer sleSrc, bool bMustSetGenerator); TransactionEngineResult takeOffers( - entryMap& emEntries, bool bPassive, const uint256& uBookBase, const uint160& uTakerAccountID, @@ -161,7 +160,7 @@ protected: entryMap mEntries; - SLE::pointer entryCreate(LedgerEntryType letType); + SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); void entryDelete(SLE::pointer sleEntry); void entryModify(SLE::pointer sleEntry); void entryUnfunded(SLE::pointer sleEntry); @@ -169,23 +168,23 @@ protected: STAmount rippleBalance(const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency); - void rippleCredit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saCredit); - void rippleDebit(entryMap& emEntries, const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saDebit); + void rippleCredit(const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saCredit); + void rippleDebit(const uint160& uAccountID, const uint160& uIssuerAccountID, const uint160& uCurrency, const STAmount& saDebit); - TransactionEngineResult doAccountSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); - TransactionEngineResult doClaim(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); - TransactionEngineResult doCreditSet(const SerializedTransaction& txn, entryMap& emEntries, const uint160& uSrcAccountID); - TransactionEngineResult doDelete(const SerializedTransaction& txn, entryMap& emEntries); - TransactionEngineResult doInvoice(const SerializedTransaction& txn, entryMap& emEntries); - TransactionEngineResult doOfferCreate(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); - TransactionEngineResult doOfferCancel(const SerializedTransaction& txn, entryMap& emEntries, const uint160& uSrcAccountID); - TransactionEngineResult doNicknameSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); - TransactionEngineResult doPasswordFund(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); - TransactionEngineResult doPasswordSet(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); - TransactionEngineResult doPayment(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc, const uint160& uSrcAccountID); - TransactionEngineResult doStore(const SerializedTransaction& txn, entryMap& emEntries); - TransactionEngineResult doTake(const SerializedTransaction& txn, entryMap& emEntries); - TransactionEngineResult doWalletAdd(const SerializedTransaction& txn, entryMap& emEntries, SLE::pointer sleSrc); + TransactionEngineResult doAccountSet(const SerializedTransaction& txn, SLE::pointer sleSrc); + TransactionEngineResult doClaim(const SerializedTransaction& txn, SLE::pointer sleSrc); + TransactionEngineResult doCreditSet(const SerializedTransaction& txn, const uint160& uSrcAccountID); + TransactionEngineResult doDelete(const SerializedTransaction& txn); + TransactionEngineResult doInvoice(const SerializedTransaction& txn); + TransactionEngineResult doOfferCreate(const SerializedTransaction& txn, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doOfferCancel(const SerializedTransaction& txn, const uint160& uSrcAccountID); + TransactionEngineResult doNicknameSet(const SerializedTransaction& txn, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doPasswordFund(const SerializedTransaction& txn, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doPasswordSet(const SerializedTransaction& txn, SLE::pointer sleSrc); + TransactionEngineResult doPayment(const SerializedTransaction& txn, SLE::pointer sleSrc, const uint160& uSrcAccountID); + TransactionEngineResult doStore(const SerializedTransaction& txn); + TransactionEngineResult doTake(const SerializedTransaction& txn); + TransactionEngineResult doWalletAdd(const SerializedTransaction& txn, SLE::pointer sleSrc); public: TransactionEngine() { ; } diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 4f9675a093..e2e6ac4274 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -47,10 +47,10 @@ TransactionFormat InnerTxnFormats[]= }, { "NicknameSet", ttNICKNAME_SET, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Nickname), STI_HASH256, SOE_IFFLAG, 8 }, + { S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 }, { S_FIELD(Signature), STI_VL, SOE_IFFLAG, 2 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, + { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, @@ -59,8 +59,9 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 2 }, - { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 4 }, + { S_FIELD(PaysIssuer), STI_ACCOUNT, SOE_IFFLAG, 2 }, + { S_FIELD(GetsIssuer), STI_ACCOUNT, SOE_IFFLAG, 4 }, + { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 8 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } },