From 4b20162e7f338c9515845339f10d3f1e5a3463d5 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 14:34:42 -0700 Subject: [PATCH] Work in progress on offers and ripple. --- src/Ledger.h | 20 ++- src/LedgerFormats.cpp | 15 +- src/LedgerFormats.h | 44 +++--- src/LedgerIndex.cpp | 72 ++++----- src/LedgerNode.cpp | 14 ++ src/SerializedObject.h | 10 +- src/Serializer.h | 1 - src/TransactionEngine.cpp | 300 ++++++++++++++++++++++++++++++++++++- src/TransactionEngine.h | 33 +++- src/TransactionFormats.cpp | 10 +- src/TransactionFormats.h | 5 +- 11 files changed, 447 insertions(+), 77 deletions(-) diff --git a/src/Ledger.h b/src/Ledger.h index 482fb27ba3..c86114f639 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -184,16 +184,26 @@ public: static uint256 getNicknameIndex(const uint256& uNickname); + // + // Order book functions + // + + // Order book dirs have a base so we can use next to step through them in quality order. + static uint256 getBookBase(const uint160& uCurrencyIn, const uint160& uAccountIn, + const uint160& uCurrencyOut, const uint160& uAccountOut); + // // Offer functions // - static uint160 getOfferBase(const uint160& currencyIn, const uint160& accountIn, - const uint160& currencyOut, const uint160& accountOut); + SLE::pointer getOffer(LedgerStateParms& parms, const uint256& uIndex); + SLE::pointer getOffer(LedgerStateParms& parms, const uint160& uAccountID, uint32 uSequence) + { return getOffer(parms, getOfferIndex(uAccountID, uSequence)); } - static uint256 getOfferIndex(const uint160& offerBase, uint64 rate, int skip = 0); - static int getOfferSkip(const uint256& offerId); + static uint256 getOfferIndex(const uint160& uAccountID, uint32 uSequence); + + static uint256 getOfferDirIndex(const uint160& uAccountID); // // Directory functions @@ -205,7 +215,7 @@ public: SLE::pointer getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex); // - // Ripple functions + // Ripple functions : credit lines // static uint256 getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency); diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 711c9c258e..855fa344b9 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -46,6 +46,18 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, + { "Offer", ltOFFER, { + { 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(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(OfferNode), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + }, { "RippleState", ltRIPPLE_STATE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, @@ -53,7 +65,8 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(LowLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(HighID), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(HighLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(AcceptRate), STI_UINT32, SOE_IFFLAG, 1 }, + { S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 1 }, + { S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index 53da1d617f..347e7ce2fc 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -6,38 +6,42 @@ // Used as the type of a transaction or the type of a ledger entry. enum LedgerEntryType { - ltINVALID = -1, - ltACCOUNT_ROOT, - ltDIR_ROOT, - ltDIR_NODE, - ltGENERATOR_MAP, - ltRIPPLE_STATE, - ltNICKNAME + ltINVALID = -1, + ltACCOUNT_ROOT = 'a', + ltDIR_ROOT = 'D', + ltDIR_NODE = 'd', + ltGENERATOR_MAP = 'g', + ltRIPPLE_STATE = 'r', + ltNICKNAME = 'n', + ltOFFER = 'o', }; // Used as a prefix for computing ledger indexes (keys). enum LedgerNameSpace { - spaceAccount = 0, - spaceGenerator = 1, - spaceNickname = 2, - spaceRipple = 3, - spaceRippleDir = 4, - spaceOffer = 5, - spaceOfferDir = 6, - spaceBond = 7, - spaceInvoice = 8, - spaceMultiSig = 9, + spaceAccount = 'a', + spaceGenerator = 'g', + spaceNickname = 'n', + spaceRipple = 'r', + spaceRippleDir = 'R', + spaceOffer = 'o', // Entry for an offer. + spaceOfferDir = 'O', // Directory of an account's offers. + spaceBookDir = 'B', // Directory of order books. + spaceBond = 'b', + spaceInvoice = 'i', }; enum LedgerSpecificFlags { + // ltACCOUNT_ROOT + lsfPasswordSpent = 0x00010000, // True if password set fee is spent. + + // ltOFFER + lsfPassive = 0x00010000, + // ltRIPPLE_STATE lsfLowIndexed = 0x00010000, lsfHighIndexed = 0x00020000, - - // ltACCOUNT_ROOT - lsfPasswordSpent = 0x00010000, // True if password set fee is spent. }; struct LedgerEntryFormat diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp index 0bf18f1c88..6c562605be 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -59,55 +59,47 @@ uint256 Ledger::getRippleDirIndex(const uint160& uAccountID) return s.getSHA512Half(); } -uint160 Ledger::getOfferBase(const uint160& currencyIn, const uint160& accountIn, - const uint160& currencyOut, const uint160& accountOut) +uint256 Ledger::getBookBase(const uint160& uCurrencyIn, const uint160& uAccountIn, + const uint160& uCurrencyOut, const uint160& uAccountOut) { - bool inNative = currencyIn.isZero(); - bool outNative = currencyOut.isZero(); + bool bInNative = uCurrencyIn.isZero(); + bool bOutNative = uCurrencyOut.isZero(); - if (inNative && outNative) - throw std::runtime_error("native to native offer"); + 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(uCurrencyIn != uCurrencyOut || uAccountIn != uAccountOut); // Currencies or accounts must differ. - Serializer s(80); + Serializer s(82); - if (inNative) - { - if (!currencyIn) throw std::runtime_error("native currencies are untied"); - s.add32(0); // prevent collisions by ensuring different lengths - } - else - { - if (!!currencyIn) throw std::runtime_error("national currencies must be tied"); - s.add160(currencyIn); - s.add160(accountIn); - } + s.add16(spaceBookDir); // 2 + s.add160(uCurrencyIn); // 20 + s.add160(uCurrencyOut); // 20 + s.add160(uAccountIn); // 20 + s.add160(uAccountOut); // 20 - if (outNative) - { - if (!currencyOut) throw std::runtime_error("native currencies are untied"); - } - else - { - if (!!currencyOut) throw std::runtime_error("national currencies must be tied"); - s.add160(currencyOut); - s.add160(accountOut); - } - - return s.getRIPEMD160(); + return getDirIndex(s.getSHA512Half()); // Return with index 0. } -uint256 Ledger::getOfferIndex(const uint160& offerBase, uint64 rate, int skip) -{ // the node for an offer index - Serializer s; - s.add160(offerBase); - s.add64(rate); - s.add32(skip); - return s.get256(0); +uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence) +{ + Serializer s; + + s.add16(spaceOffer); + s.add160(uAccountID); + s.add32(uSequence); + + return s.getSHA512Half(); } -int Ledger::getOfferSkip(const uint256& offerId) -{ // how far ahead we skip if an index node is full - return *offerId.begin(); +uint256 Ledger::getOfferDirIndex(const uint160& uAccountID) +{ + Serializer s; + + s.add16(spaceOfferDir); + s.add160(uAccountID); + + return s.getSHA512Half(); } // vim:ts=4 diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index d059b9c3e7..ba965386cf 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -6,6 +6,8 @@ #include "utils.h" #include "Log.h" +// XXX Use shared locks where possible? + LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) { ScopedLock l(mAccountStateMap->Lock()); @@ -112,6 +114,18 @@ SLE::pointer Ledger::getNickname(LedgerStateParms& parms, const uint256& uNickna return getASNode(parms, uNickname, ltNICKNAME); } +// +// Offer +// + + +SLE::pointer Ledger::getOffer(LedgerStateParms& parms, const uint256& uIndex) +{ + ScopedLock l(mAccountStateMap->Lock()); + + return getASNode(parms, uIndex, ltOFFER); +} + // // Ripple State // diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 0918db000f..00957ba320 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -44,7 +44,7 @@ enum SOE_Field sfCurrencyOut, sfDestination, sfEmailHash, - sfExpireLedger, + sfExpiration, sfExtensions, sfFirstNode, sfFlags, @@ -56,6 +56,8 @@ enum SOE_Field sfIdentifier, sfIndexes, sfInvoiceID, + sfIssuerIn, + sfIssuerOut, sfLastNode, sfLastReceive, sfLastTxn, @@ -72,9 +74,13 @@ enum SOE_Field sfNextTransitRate, sfNextTransitStart, sfNickname, - sfOfferCurrency, + sfOfferNode, + sfOfferSequence, + sfOwnerNode, sfPaths, sfPubKey, + sfQualityIn, + sfQualityOut, sfSendMax, sfSequence, sfSignature, diff --git a/src/Serializer.h b/src/Serializer.h index a0962c43a4..ab39a1c30d 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -107,7 +107,6 @@ public: void reserve(size_t n) { mData.reserve(n); } void resize(size_t n) { mData.resize(n); } size_t capacity() const { return mData.capacity(); } - bool operator==(const std::vector& v) { return v == mData; } bool operator!=(const std::vector& v) { return v != mData; } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index d21010c4ce..533d4c9e56 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -28,7 +28,10 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { tenBAD_AMOUNT, "tenBAD_AMOUNT", "Can only send positive amounts." }, { tenBAD_AUTH_MASTER, "tenBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, { tenBAD_CLAIM_ID, "tenBAD_CLAIM_ID", "Malformed." }, + { tenBAD_EXPIRATION, "tenBAD_EXPIRATION", "Malformed." }, { tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." }, + { tenBAD_OFFER, "tenBAD_OFFER", "Malformed." }, + { tenBAD_ISSUER, "tenBAD_ISSUER", "Malformed." }, { tenBAD_RIPPLE, "tenBAD_RIPPLE", "Ledger prevents ripple from succeeding." }, { tenBAD_SET_ID, "tenBAD_SET_ID", "Malformed." }, { tenCLAIMED, "tenCLAIMED", "Can not claim a previously claimed account." }, @@ -36,6 +39,7 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { tenCREATEXNS, "tenCREATEXNS", "Can not specify non XNS for Create." }, { tenDST_IS_SRC, "tenDST_IS_SRC", "Destination may not be source." }, { tenDST_NEEDED, "tenDST_NEEDED", "Destination not specified." }, + { tenEXPIRED, "tenEXPIRED", "Won't add an expired offer." }, { tenEXPLICITXNS, "tenEXPLICITXNS", "XNS is used by default, don't specify it." }, { tenFAILED, "tenFAILED", "Something broke horribly" }, { tenGEN_IN_USE, "tenGEN_IN_USE", "Generator already in use." }, @@ -61,6 +65,7 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { terNO_DST, "terNO_DST", "The destination does not exist" }, { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, { terNO_PATH, "terNO_PATH", "No path existed or met transaction/balance requirements" }, + { terOFFER_NOT_FOUND, "terOFFER_NOT_FOUND", "Can not cancel offer." }, { terOVER_LIMIT, "terOVER_LIMIT", "Over limit." }, { terPAST_LEDGER, "terPAST_LEDGER", "The transaction expired and can't be applied" }, { terPAST_SEQ, "terPAST_SEQ", "This sequence number has already past" }, @@ -470,6 +475,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttCREDIT_SET: case ttINVOICE: case ttOFFER: + case ttOFFER_CANCEL: case ttPASSWORD_FUND: case ttTRANSIT_SET: case ttWALLET_ADD: @@ -730,7 +736,11 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran break; case ttOFFER: - result = doOffer(txn, accounts); + result = doOffer(txn, accounts, srcAccountID); + break; + + case ttOFFER_CANCEL: + result = doOfferCancel(txn, accounts, srcAccountID); break; case ttNICKNAME_SET: @@ -1117,6 +1127,146 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac return result; } +#ifdef WORK_IN_PROGRESS +TransactionEngineResult calcOfferFill(SAAmount& saSrc, paymentNode& pnSrc, paymentNode& pnDst) +{ + TransactionEngineResult terResult; + + if (!saSrc.isZero()) + { + + } + + return bSuccess; +} + +// Find offers to satisfy pnDst. +// --> pnDst.saWanted: currency and amount wanted +// --> pnSrc.saIOURedeem.mCurrency: use this before saIOUIssue, limit to use. +// --> pnSrc.saIOUIssue.mCurrency: use this after saIOURedeem, limit to use. +// <-- pnDst.saReceive +// <-- pnDst.saIOUForgive +// <-- pnDst.saIOUAccept +// <-- terResult : terSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. +// <-> usOffersDeleteAlways: +// <-> usOffersDeleteOnSuccess: +TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bool bAllowPartial) +{ + TransactionEngineResult terResult; + + terResult = calcOfferFill(pnSrc.saIOURedeem, pnSrc, pnDst, bAllowPartial); + + if (terSUCCESS == terResult) + { + terResult = calcOfferFill(pnSrc.saIOUIssue, pnSrc, pnDst, bAllowPartial) + } + + if (terSUCCESS == terResult && !bAllowPartial) + { + STAmount saTotal = pnSrc.saIOURedeem; + saTotal += pnSrc.saIOUIssue; + + if (saTotal != saWanted) + terResult = terINSUF_PATH; + } + + return terResult; +} + +// From the destination work towards the source calculating how much must be asked for. +// --> bAllowPartial: If false, can fail if can't meet requirements. +// <-- bSuccess: true=success, false=insufficient funds. +// <-> pnNodes: +// --> [end]saWanted.mAmount +// --> [all]saWanted.mCurrency +// --> [all]saAccount +// <-> [0]saWanted.mAmount : --> limit, <-- actual +bool calcPaymentReverse(std::vector& pnNodes, bool bAllowPartial) +{ + bool bDone = false; + bool bSuccess = false; + + // path: dst .. src + + while (!bDone) + { + if (cur->saWanted.isZero()) + { + // Must want something. + terResult = terINVALID; + bDone = true; + } + else if (cur->saWanted.isNative()) + { + if (prv->how == direct) + { + // Stamp transfer desired. + if (prv->prev()) + { + // More entries before stamp transfer. + terResult = terINVALID; + bDone = true; + } + else if (prv->account->saBalance() >= cur->saWanted) + { + // Transfer stamps. + prv->saSend = cur->saWanted; + bDone = true; + bSuccess = true; + } + else + { + // Insufficient funds for transfer + bDone = true; + } + } + else + { + // Must convert to stamps via offer. + if (calcOfferFill(prv, cur, bAllowPartial)) + { + + } + else + { + bDone = false; + } + } + } + else + { + // Rippling. + + } + } +} + +// From the source work toward the destination calculate how much is transfered at each step and finally. +// <-> pnNodes: +// --> [0]saWanted.mAmount +// --> [all]saWanted.saSend +// --> [all]saWanted.IOURedeem +// --> [all]saWanted.IOUIssue +// --> [all]saAccount +bool calcPaymentForward(std::vector& pnNodes) +{ + cur = src; + + if (!cur->saSend.isZero()) + { + // Sending stamps - always final step. + assert(!cur->next); + nxt->saReceive = cur->saSend; + bDone = true; + } + else + { + // Rippling. + + } +} +#endif + // XXX Need to audit for things like setting accountID not having memory. TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn, std::vector& accounts, @@ -1524,10 +1674,152 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction return tenUNKNOWN; } -TransactionEngineResult TransactionEngine::doOffer(const SerializedTransaction& txn, - std::vector& accounts) +// XXX Needs to take offers. +// XXX Use bPassive when taking. +// XXX Also use quality when rippling a take. +TransactionEngineResult TransactionEngine::doOffer( + const SerializedTransaction& txn, + std::vector& accounts, + const uint160& uSrcAccountID) { - return tenUNKNOWN; + uint32 txFlags = txn.getFlags(); + bool bPassive = !!(txFlags & tfPassive); + STAmount saAmountIn = txn.getITFieldAmount(sfAmountIn); + STAmount saAmountOut = txn.getITFieldAmount(sfAmountOut); + uint160 uIssuerIn = txn.getITFieldAccount(sfIssuerIn); + uint160 uIssuerOut = txn.getITFieldAccount(sfIssuerOut); + uint32 uExpiration = txn.getITFieldU32(sfExpiration); + bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); + uint32 uSequence = txn.getSequence(); + + // LedgerStateParms qry = lepNONE; + SLE::pointer sleOffer = boost::make_shared(ltOFFER); + + uint256 uLedgerIndex = Ledger::getOfferIndex(uSrcAccountID, uSequence); + Log(lsINFO) << "doOffer: Creating offer node: " << uLedgerIndex.ToString(); + + uint160 uCurrencyIn = saAmountIn.getCurrency(); + uint160 uCurrencyOut = saAmountOut.getCurrency(); + + TransactionEngineResult terResult; + uint64 uOwnerNode; // Delete hint. + uint64 uOfferNode; // Delete hint. + // uint64 uBookNode; // Delete hint. + + uint32 uPrevLedgerTime = 0; // XXX Need previous + + if (!bHaveExpiration || !uExpiration) + { + Log(lsWARNING) << "doOffer: Malformed offer: bad expiration"; + + terResult = tenBAD_EXPIRATION; + } + else if (!bHaveExpiration || uPrevLedgerTime >= uExpiration) + { + Log(lsWARNING) << "doOffer: Expired transaction: offer expired"; + + terResult = tenEXPIRED; + } + else if (saAmountIn.isNative() && saAmountOut.isNative()) + { + Log(lsWARNING) << "doOffer: Malformed offer: stamps for stamps"; + + terResult = tenBAD_OFFER; + } + else if (saAmountIn.isZero() || saAmountOut.isZero()) + { + Log(lsWARNING) << "doOffer: Malformed offer: bad amount"; + + terResult = tenBAD_OFFER; + } + else if (uCurrencyIn == uCurrencyOut && uIssuerIn == uIssuerOut) + { + Log(lsWARNING) << "doOffer: Malformed offer: no conversion"; + + terResult = tenREDUNDANT; + } + else if (uCurrencyIn.isZero() == uIssuerIn.isZero() && uCurrencyOut.isZero() == uIssuerOut.isZero()) + { + Log(lsWARNING) << "doOffer: Malformed offer: bad issuer"; + + terResult = tenBAD_ISSUER; + } + + // XXX check currencies and accounts + // XXX check funded + // XXX check output credit line exists + // XXX when deleting a credit line, delete outstanding offers + + // XXX Only place the offer if a portion is not filled. + + if (terSUCCESS == terResult) + terResult = dirAdd(accounts, uOwnerNode, Ledger::getOfferDirIndex(uSrcAccountID), uLedgerIndex); + + if (terSUCCESS == terResult) + { + terResult = dirAdd(accounts, uOfferNode, + Ledger::getDirIndex( + Ledger::getBookBase(uCurrencyIn, uIssuerIn, uCurrencyOut, uIssuerOut), + STAmount::getRate(saAmountOut, saAmountIn)), + 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(sfOfferNode, uOfferNode); + sleOffer->setIFieldU32(sfExpiration, uExpiration); + + if (bPassive) + sleOffer->setFlag(lsfPassive); + + accounts.push_back(std::make_pair(taaCREATE, sleOffer)); + } + + return terResult; +} + +TransactionEngineResult TransactionEngine::doOfferCancel( + const SerializedTransaction& txn, + std::vector& accounts, + const uint160& uSrcAccountID) +{ + uint32 uSequence = txn.getITFieldU32(sfSequence); + uint256 uLedgerIndex = Ledger::getOfferIndex(uSrcAccountID, uSequence); + + LedgerStateParms qry = lepNONE; + SLE::pointer sleOffer = mLedger->getOffer(qry, uLedgerIndex); + TransactionEngineResult terResult; + + if (sleOffer) + { + + terResult = tenUNKNOWN; +#if 0 + uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); + uint64 uOwnerNode = sleOffer->getIFieldU64(sfOfferNode); + + terResult = dirDelete(accounts, uOwnerNode, ___, uLedgerIndex); + + if (terSUCCESS == terResult) + { + terResult = dirDelete(accounts, uOfferNode, ___, uLedgerIndex); + } +#endif + accounts.push_back(std::make_pair(taaDELETE, sleOffer)); + } + else + { + terResult = terOFFER_NOT_FOUND; + } + + return terResult; } TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn, diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index f7f70b8122..80debf6ec5 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -19,7 +19,10 @@ enum TransactionEngineResult tenBAD_ADD_AUTH, tenBAD_AMOUNT, tenBAD_CLAIM_ID, + tenBAD_EXPIRATION, tenBAD_GEN_AUTH, + tenBAD_ISSUER, + tenBAD_OFFER, tenBAD_SET_ID, tenCREATEXNS, tenDST_IS_SRC, @@ -33,6 +36,7 @@ enum TransactionEngineResult tenBAD_AUTH_MASTER, tenBAD_RIPPLE, tenCREATED, + tenEXPIRED, tenMSG_SET, terALREADY, @@ -62,6 +66,7 @@ enum TransactionEngineResult terNO_DST, terNO_LINE_NO_ZERO, terNO_PATH, + terOFFER_NOT_FOUND, terOVER_LIMIT, terPAST_LEDGER, terPAST_SEQ, @@ -106,6 +111,29 @@ private: const uint256& uBase, // Key of item. const uint256& uLedgerIndex); // Item being deleted +#ifdef WORK_IN_PROGRESS + typedef struct { + STAmount saWanted; // What this node wants from upstream. + + STAmount saIOURedeem; // What this node will redeem downstream. + STAmount saIOUIssue; // What this node will issue downstream. + STAmount saSend; // Amount of stamps this node will send. + + STAmount saIOUForgive; // Amount of IOUs to forgive. + STAmount saIOUAccept; // Amount of IOUs to accept. + STAmount saRecieve; // Amount stamps to receive. + + STAccount saAccount; + } paymentNode; + + typedef struct { + boost::unordered_set<....> offersDeletedAlways; + boost::unordered_set<....> offersDeletedOnSuccess; + std::vector vpnNodes; + bool bAllowPartial; + } paymentGroup; +#endif + TransactionEngineResult setAuthorized(const SerializedTransaction& txn, std::vector& accounts, bool bMustSetGenerator); protected: @@ -118,7 +146,10 @@ protected: const uint160& uSrcAccountID); TransactionEngineResult doDelete(const SerializedTransaction& txn, std::vector& accounts); TransactionEngineResult doInvoice(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doOffer(const SerializedTransaction& txn, std::vector& accounts); + TransactionEngineResult doOffer(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, diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index cddcafcf6c..6809bfec5e 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -59,8 +59,14 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(AmountOut), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 2 }, - { S_FIELD(ExpireLedger), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 8 }, + { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 4 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + }, + { "OfferCancel", ttOFFER, { + { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, + { S_FIELD(OfferSequence), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index 1f5b63d203..b1967ecb75 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -13,10 +13,11 @@ enum TransactionType ttPASSWORD_FUND = 4, ttPASSWORD_SET = 5, ttNICKNAME_SET = 6, + ttOFFER = 7, + ttOFFER_CANCEL = 8, ttCREDIT_SET = 20, ttTRANSIT_SET = 21, ttINVOICE = 10, - ttOFFER = 11, }; struct TransactionFormat @@ -39,6 +40,8 @@ const int TransactionMaxLen = 1048576; const uint32 tfCreateAccount = 0x00010000; const uint32 tfNoRippleDirect = 0x00020000; +const uint32 tfPassive = 0x00010000; + const uint32 tfUnsetEmailHash = 0x00010000; const uint32 tfUnsetWalletLocator = 0x00020000;