From 5cf06d45a03847121898f43f28e7524ddf92ecf0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 00:09:49 -0700 Subject: [PATCH 01/13] Add support for configuring fee_offer. --- src/Config.cpp | 8 +++++++- src/Config.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Config.cpp b/src/Config.cpp index 0ca3ec46cd..f2347cc6f0 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -11,6 +11,7 @@ #define SECTION_FEE_ACCOUNT_CREATE "fee_account_create" #define SECTION_FEE_DEFAULT "fee_default" #define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create" +#define SECTION_FEE_OFFER "fee_offer" #define SECTION_IPS "ips" #define SECTION_NETWORK_QUORUM "network_quorum" #define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water" @@ -31,9 +32,10 @@ #define SECTION_VALIDATORS_SITE "validators_site" // Fees are in XNB. +#define DEFAULT_FEE_DEFAULT 100 #define DEFAULT_FEE_ACCOUNT_CREATE 1000 #define DEFAULT_FEE_NICKNAME_CREATE 1000 -#define DEFAULT_FEE_DEFAULT 100 +#define DEFAULT_FEE_OFFER DEFAULT_FEE_DEFAULT Config theConfig; @@ -140,6 +142,7 @@ void Config::setup(const std::string& strConf) FEE_ACCOUNT_CREATE = DEFAULT_FEE_ACCOUNT_CREATE; FEE_NICKNAME_CREATE = DEFAULT_FEE_NICKNAME_CREATE; + FEE_OFFER = DEFAULT_FEE_OFFER; FEE_DEFAULT = DEFAULT_FEE_DEFAULT; ACCOUNT_PROBE_MAX = 10; @@ -240,6 +243,9 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_FEE_NICKNAME_CREATE, strTemp)) FEE_NICKNAME_CREATE = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_FEE_OFFER, strTemp)) + FEE_OFFER = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_FEE_DEFAULT, strTemp)) FEE_DEFAULT = boost::lexical_cast(strTemp); diff --git a/src/Config.h b/src/Config.h index d5fc3ad732..5793fd81c3 100644 --- a/src/Config.h +++ b/src/Config.h @@ -94,6 +94,7 @@ public: uint64 FEE_DEFAULT; // Default fee. uint64 FEE_ACCOUNT_CREATE; // Fee to create an account. uint64 FEE_NICKNAME_CREATE; // Fee to create a nickname. + uint64 FEE_OFFER; // Rate per day. // Client behavior int ACCOUNT_PROBE_MAX; // How far to scan for accounts. From 4b20162e7f338c9515845339f10d3f1e5a3463d5 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 14:34:42 -0700 Subject: [PATCH 02/13] 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; From e5ad771708373371bb110109cf3091bf74975525 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 17:46:47 -0700 Subject: [PATCH 03/13] Move to new directory format. --- src/Ledger.h | 9 +- src/LedgerFormats.cpp | 9 +- src/LedgerFormats.h | 2 +- src/LedgerIndex.cpp | 150 ++++++++++------- src/LedgerNode.cpp | 48 ++---- src/NetworkOPs.cpp | 61 +++---- src/NetworkOPs.h | 15 +- src/RPCServer.cpp | 22 ++- src/SerializedObject.h | 2 + src/TransactionEngine.cpp | 340 ++++++++++++++++++++++---------------- src/TransactionEngine.h | 5 +- 11 files changed, 368 insertions(+), 295 deletions(-) diff --git a/src/Ledger.h b/src/Ledger.h index c86114f639..2cda039463 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -209,11 +209,16 @@ public: // Directory functions // - static uint256 getDirIndex(const uint256& uBase, const uint64 uNodeDir=0); + static uint256 getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex=0); - SLE::pointer getDirRoot(LedgerStateParms& parms, const uint256& uRootIndex); SLE::pointer getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex); + // + // Quality + // + + static uint256 getQualityIndex(const uint256& uBase, const uint64 uNodeDir=0); + // // Ripple functions : credit lines // diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 855fa344b9..d745c557f2 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -20,16 +20,11 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, - { "DirectoryRoot", ltDIR_ROOT, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(FirstNode), STI_UINT64, SOE_REQUIRED, 0 }, - { S_FIELD(LastNode), STI_UINT64, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, { "DirectoryNode", ltDIR_NODE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Indexes), STI_VECTOR256, SOE_REQUIRED, 0 }, + { S_FIELD(IndexNext), STI_UINT64, SOE_IFFLAG, 1 }, + { S_FIELD(IndexPrevious), STI_UINT64, 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 347e7ce2fc..f3d6fae544 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -8,7 +8,6 @@ enum LedgerEntryType { ltINVALID = -1, ltACCOUNT_ROOT = 'a', - ltDIR_ROOT = 'D', ltDIR_NODE = 'd', ltGENERATOR_MAP = 'g', ltRIPPLE_STATE = 'r', @@ -20,6 +19,7 @@ enum LedgerEntryType enum LedgerNameSpace { spaceAccount = 'a', + spaceDirNode = 'd', spaceGenerator = 'g', spaceNickname = 'n', spaceRipple = 'r', diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp index 6c562605be..a60d522385 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -1,60 +1,26 @@ #include "Ledger.h" +// For an entry put in the 64 bit index or quality. +uint256 Ledger::getQualityIndex(const uint256& uBase, const uint64 uNodeDir) +{ + // Indexes are stored in big endian format: they print as hex as stored. + // Most significant bytes are first. Least significant bytes repesent adjcent entries. + // We place uNodeDir in the 8 right most bytes to be adjcent. + // Want uNodeDir in big endian format so ++ goes to the next entry for indexes. + uint256 uNode(uBase); + + ((uint64*) uNode.end())[-1] = htobe64(uNodeDir); + + return uNode; +} + uint256 Ledger::getAccountRootIndex(const uint160& uAccountID) { - Serializer s; + Serializer s(22); - s.add16(spaceAccount); - s.add160(uAccountID); - - return s.getSHA512Half(); -} - -// What is important: -// --> uNickname: is a Sha256 -// <-- SHA512/2: for consistency and speed in generating indexes. -uint256 Ledger::getNicknameIndex(const uint256& uNickname) -{ - Serializer s; - - s.add16(spaceNickname); - s.add256(uNickname); - - return s.getSHA512Half(); -} - -uint256 Ledger::getGeneratorIndex(const uint160& uGeneratorID) -{ - Serializer s; - - s.add16(spaceGenerator); - s.add160(uGeneratorID); - - return s.getSHA512Half(); -} - -uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency) -{ - uint160 uAID = naA.getAccountID(); - uint160 uBID = naB.getAccountID(); - bool bAltB = uAID < uBID; - Serializer s; - - s.add16(spaceRipple); - s.add160(bAltB ? uAID : uBID); - s.add160(bAltB ? uBID : uAID); - s.add160(uCurrency); - - return s.getSHA512Half(); -} - -uint256 Ledger::getRippleDirIndex(const uint160& uAccountID) -{ - Serializer s; - - s.add16(spaceRippleDir); - s.add160(uAccountID); + s.add16(spaceAccount); // 2 + s.add160(uAccountID); // 20 return s.getSHA512Half(); } @@ -78,26 +44,92 @@ uint256 Ledger::getBookBase(const uint160& uCurrencyIn, const uint160& uAccountI s.add160(uAccountIn); // 20 s.add160(uAccountOut); // 20 - return getDirIndex(s.getSHA512Half()); // Return with index 0. + return getQualityIndex(s.getSHA512Half()); // Return with quality 0. +} + +uint256 Ledger::getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex) +{ + if (uNodeIndex) + { + Serializer s(42); + + s.add16(spaceDirNode); // 2 + s.add256(uDirRoot); // 32 + s.add64(uNodeIndex); // 8 + + return s.getSHA512Half(); + } + else + { + return uDirRoot; + } +} + +uint256 Ledger::getGeneratorIndex(const uint160& uGeneratorID) +{ + Serializer s(22); + + s.add16(spaceGenerator); // 2 + s.add160(uGeneratorID); // 20 + + return s.getSHA512Half(); +} + +// What is important: +// --> uNickname: is a Sha256 +// <-- SHA512/2: for consistency and speed in generating indexes. +uint256 Ledger::getNicknameIndex(const uint256& uNickname) +{ + Serializer s(34); + + s.add16(spaceNickname); // 2 + s.add256(uNickname); // 32 + + return s.getSHA512Half(); } uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence) { - Serializer s; + Serializer s(26); - s.add16(spaceOffer); - s.add160(uAccountID); - s.add32(uSequence); + s.add16(spaceOffer); // 2 + s.add160(uAccountID); // 20 + s.add32(uSequence); // 4 return s.getSHA512Half(); } uint256 Ledger::getOfferDirIndex(const uint160& uAccountID) { - Serializer s; + Serializer s(22); - s.add16(spaceOfferDir); - s.add160(uAccountID); + s.add16(spaceOfferDir); // 2 + s.add160(uAccountID); // 20 + + return s.getSHA512Half(); +} + +uint256 Ledger::getRippleDirIndex(const uint160& uAccountID) +{ + Serializer s(22); + + s.add16(spaceRippleDir); // 2 + s.add160(uAccountID); // 20 + + return s.getSHA512Half(); +} + +uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency) +{ + uint160 uAID = naA.getAccountID(); + uint160 uBID = naB.getAccountID(); + bool bAltB = uAID < uBID; + Serializer s(62); + + s.add16(spaceRipple); // 2 + s.add160(bAltB ? uAID : uBID); // 20 + s.add160(bAltB ? uBID : uAID); // 20 + s.add160(uCurrency); // 20 return s.getSHA512Half(); } diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index ba965386cf..4704fed722 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -29,7 +29,8 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) if (create) { assert(!mAccountStateMap->hasItem(entry->getIndex())); - if(!mAccountStateMap->addGiveItem(item, false)) + + if (!mAccountStateMap->addGiveItem(item, false)) { assert(false); return lepERROR; @@ -68,7 +69,7 @@ SLE::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID, SLE::pointer sle = boost::make_shared(account->peekSerializer(), nodeID); - if(sle->getType() != let) + if (sle->getType() != let) { // maybe it's a currency or something parms = parms | lepWRONGTYPE; return SLE::pointer(); @@ -92,6 +93,17 @@ SLE::pointer Ledger::getAccountRoot(LedgerStateParms& parms, const NewcoinAddres return getAccountRoot(parms, naAccountID.getAccountID()); } +// +// Directory +// + +SLE::pointer Ledger::getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex) +{ + ScopedLock l(mAccountStateMap->Lock()); + + return getASNode(parms, uNodeIndex, ltDIR_NODE); +} + // // Generator Map // @@ -137,36 +149,4 @@ SLE::pointer Ledger::getRippleState(LedgerStateParms& parms, const uint256& uNod return getASNode(parms, uNode, ltRIPPLE_STATE); } -// -// Directory -// - -// For a directory entry put in the 64 bit index or quality. -uint256 Ledger::getDirIndex(const uint256& uBase, const uint64 uNodeDir) -{ - // Indexes are stored in big endian format: they print as hex as stored. - // Most significant bytes are first. Least significant bytes repesent adjcent entries. - // We place uNodeDir in the 8 right most bytes to be adjcent. - // Want uNodeDir in big endian format so ++ goes to the next entry for indexes. - uint256 uNode(uBase); - - ((uint64*) uNode.end())[-1] = htobe64(uNodeDir); - - return uNode; -} - -SLE::pointer Ledger::getDirRoot(LedgerStateParms& parms, const uint256& uRootIndex) -{ - ScopedLock l(mAccountStateMap->Lock()); - - return getASNode(parms, uRootIndex, ltDIR_ROOT); -} - -SLE::pointer Ledger::getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex) -{ - ScopedLock l(mAccountStateMap->Lock()); - - return getASNode(parms, uNodeIndex, ltDIR_NODE); -} - // vim:ts=4 diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index df93174650..88b7af0cab 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -98,7 +98,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, return trans; } - Log(lsDEBUG) << "Status other than success " << r ; + Log(lsDEBUG) << "Status other than success " << r; if ((mMode != omFULL) && (mMode != omTRACKING) && (theApp->isNew(trans->getID()))) { newcoin::TMTransaction tx; @@ -171,53 +171,32 @@ SLE::pointer NetworkOPs::getGenerator(const uint256& uLedger, const uint160& uGe // // <-- false : no entrieS -bool NetworkOPs::getDirInfo( - const uint256& uLedger, - const uint256& uBase, - uint256& uDirLineNodeFirst, - uint256& uDirLineNodeLast) +STVector256 NetworkOPs::getDirNodeInfo( + const uint256& uLedger, + const uint256& uNodeIndex, + uint64& uNodePrevious, + uint64& uNodeNext) { - uint256 uRootIndex = Ledger::getDirIndex(uBase, 0); - LedgerStateParms lspRoot = lepNONE; - SLE::pointer sleRoot = mLedgerMaster->getLedgerByHash(uLedger)->getDirRoot(lspRoot, uRootIndex); - - if (sleRoot) - { - Log(lsDEBUG) << "getDirInfo: root index: " << uRootIndex.ToString() ; - - Log(lsTRACE) << "getDirInfo: first: " << strHex(sleRoot->getIFieldU64(sfFirstNode)) ; - Log(lsTRACE) << "getDirInfo: last: " << strHex(sleRoot->getIFieldU64(sfLastNode)) ; - - uDirLineNodeFirst = Ledger::getDirIndex(uBase, sleRoot->getIFieldU64(sfFirstNode)); - uDirLineNodeLast = Ledger::getDirIndex(uBase, sleRoot->getIFieldU64(sfLastNode)); - - Log(lsTRACE) << "getDirInfo: first: " << uDirLineNodeFirst.ToString() ; - Log(lsTRACE) << "getDirInfo: last: " << uDirLineNodeLast.ToString() ; - } - else - { - Log(lsINFO) << "getDirInfo: root index: NOT FOUND: " << uRootIndex.ToString() ; - } - - return !!sleRoot; -} - -STVector256 NetworkOPs::getDirNode(const uint256& uLedger, const uint256& uDirLineNode) -{ - STVector256 svIndexes; - + STVector256 svIndexes; LedgerStateParms lspNode = lepNONE; - SLE::pointer sleNode = mLedgerMaster->getLedgerByHash(uLedger)->getDirNode(lspNode, uDirLineNode); + SLE::pointer sleNode = mLedgerMaster->getLedgerByHash(uLedger)->getDirNode(lspNode, uNodeIndex); if (sleNode) { - Log(lsWARNING) << "getDirNode: node index: " << uDirLineNode.ToString() ; + Log(lsDEBUG) << "getDirNodeInfo: node index: " << uNodeIndex.ToString(); - svIndexes = sleNode->getIFieldV256(sfIndexes); + Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(sleNode->getIFieldU64(sfIndexPrevious)); + Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(sleNode->getIFieldU64(sfIndexNext)); + + uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious); + uNodeNext = sleNode->getIFieldU64(sfIndexNext); + + Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(uNodePrevious); + Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(uNodeNext); } else { - Log(lsINFO) << "getDirNode: node index: NOT FOUND: " << uDirLineNode.ToString() ; + Log(lsINFO) << "getDirNodeInfo: node index: NOT FOUND: " << uNodeIndex.ToString(); } return svIndexes; @@ -473,7 +452,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger) { // set the newledger as our last closed ledger -- this is abnormal code - Log(lsERROR) << "ABNORMAL Switching last closed ledger to " << newLedger->getHash().GetHex() ; + Log(lsERROR) << "ABNORMAL Switching last closed ledger to " << newLedger->getHash().GetHex(); if (mConsensus) { @@ -499,7 +478,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger) int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger) { - Log(lsINFO) << "Ledger close time for ledger " << closingLedger->getLedgerSeq() ; + Log(lsINFO) << "Ledger close time for ledger " << closingLedger->getLedgerSeq(); Log(lsINFO) << " LCL is " << closingLedger->getParentHash().GetHex(); Ledger::pointer prevLedger = mLedgerMaster->getLedgerByHash(closingLedger->getParentHash()); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 754f81964b..9458af50b3 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -109,9 +109,8 @@ public: // Directory functions // - bool getDirInfo(const uint256& uLedger, const uint256& uBase, - uint256& uDirNodeFirst, uint256& uDirNodeLast); - STVector256 getDirNode(const uint256& uLedger, const uint256& uDirLineNode); + STVector256 getDirNodeInfo(const uint256& uLedger, const uint256& uRootIndex, + uint64& uNodePrevious, uint64& uNodeNext); // // Nickname functions @@ -123,8 +122,14 @@ public: // Ripple functions // - bool getDirLineInfo(const uint256& uLedger, const NewcoinAddress& naAccount, uint256& uDirLineNodeFirst, uint256& uDirLineNodeLast) - { return getDirInfo(uLedger, Ledger::getRippleDirIndex(naAccount.getAccountID()), uDirLineNodeFirst, uDirLineNodeLast); } + bool getDirLineInfo(const uint256& uLedger, const NewcoinAddress& naAccount, uint256& uRootIndex) + { + LedgerStateParms lspNode = lepNONE; + + uRootIndex = Ledger::getRippleDirIndex(naAccount.getAccountID()); + + return !!mLedgerMaster->getLedgerByHash(uLedger)->getDirNode(lspNode, uRootIndex); + } RippleState::pointer getRippleState(const uint256& uLedger, const uint256& uIndex); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index c99f734f71..db71fb62c7 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -559,14 +559,17 @@ Json::Value RPCServer::doAccountLines(const Json::Value ¶ms) ret["account"] = naAccount.humanAccountID(); // We access a committed ledger and need not worry about changes. - uint256 uDirLineNodeFirst; - uint256 uDirLineNodeLast; + uint256 uRootIndex; - if (mNetOps->getDirLineInfo(uCurrent, naAccount, uDirLineNodeFirst, uDirLineNodeLast)) + if (mNetOps->getDirLineInfo(uCurrent, naAccount, uRootIndex)) { - for (; uDirLineNodeFirst <= uDirLineNodeLast; uDirLineNodeFirst++) + bool bDone = false; + + while (!bDone) { - STVector256 svRippleNodes = mNetOps->getDirNode(uCurrent, uDirLineNodeFirst); + uint64 uNodePrevious; + uint64 uNodeNext; + STVector256 svRippleNodes = mNetOps->getDirNodeInfo(uCurrent, uRootIndex, uNodePrevious, uNodeNext); BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) { @@ -602,6 +605,15 @@ Json::Value RPCServer::doAccountLines(const Json::Value ¶ms) std::cerr << "doAccountLines: Bad index: " << uNode.ToString() << std::endl; } } + + if (uNodeNext) + { + uCurrent = Ledger::getDirNodeIndex(uRootIndex, uNodeNext); + } + else + { + bDone = true; + } } } ret["lines"] = jsonLines; diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 00957ba320..628219a4c3 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -55,6 +55,8 @@ enum SOE_Field sfHighLimit, sfIdentifier, sfIndexes, + sfIndexNext, + sfIndexPrevious, sfInvoiceID, sfIssuerIn, sfIssuerOut, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 533d4c9e56..98078a6443 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -30,8 +30,8 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { 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_OFFER, "tenBAD_OFFER", "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." }, @@ -51,6 +51,7 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { tenUNKNOWN, "tenUNKNOWN", "The transactions requires logic not implemented yet" }, { terALREADY, "terALREADY", "The exact transaction was already in this ledger" }, { terBAD_AUTH, "terBAD_AUTH", "Transaction's public key is not authorized." }, + { terBAD_LEDGER, "terBAD_LEDGER", "Ledger in unexpected state." }, { terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." }, { terBAD_SEQ, "terBAD_SEQ", "This sequence number should be zero for prepaid transactions." }, { terCREATED, "terCREATED", "Can not create a previously created account." }, @@ -58,9 +59,9 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee" }, { terINSUF_FEE_T, "terINSUF_FEE_T", "fee insufficient now (account doesn't exist, network load)" }, - { terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a dir node." }, - { terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "?" }, - { terNODE_NO_ROOT, "terNODE_NO_ROOT", "?" }, + { terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a directory node." }, + { terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "Could not remove node from a directory." }, + { terNODE_NO_ROOT, "terNODE_NO_ROOT", "Directory doesn't exist." }, { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" }, { 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." }, @@ -92,123 +93,126 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std // <-> accounts: Affected accounts for the transaction. // <-- uNodeDir: For deletion, present to make dirDelete efficient. -// --> uBase: The index of the base of the directory. Nodes are based off of this. +// --> 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, uint64& uNodeDir, - const uint256& uBase, + const uint256& uRootIndex, const uint256& uLedgerIndex) { - // Get the root. - uint256 uRootIndex = Ledger::getDirIndex(uBase, 0); + SLE::pointer sleNode; + STVector256 svIndexes; LedgerStateParms lspRoot = lepNONE; - SLE::pointer sleRoot = mLedger->getDirRoot(lspRoot, uRootIndex); - bool bRootNew; + SLE::pointer sleRoot = mLedger->getDirNode(lspRoot, uRootIndex); - // Get the last node index. - if (sleRoot) + if (!sleRoot) { - bRootNew = false; - uNodeDir = sleRoot->getIFieldU64(sfLastNode); - } - else - { - bRootNew = true; - uNodeDir = 1; + // No root, make it. + Log(lsTRACE) << "dirAdd: Creating dir root: " << uRootIndex.ToString(); - sleRoot = boost::make_shared(ltDIR_ROOT); + uNodeDir = 0; + sleRoot = boost::make_shared(ltDIR_NODE); sleRoot->setIndex(uRootIndex); - Log(lsTRACE) << "dirAdd: Creating dir index: " << sleRoot->getIndex().ToString(); - sleRoot->setIFieldU64(sfFirstNode, uNodeDir); - sleRoot->setIFieldU64(sfLastNode, uNodeDir); - - Log(lsTRACE) << "dirAdd: first & last: " << strHex(uNodeDir); + sleNode = sleRoot; accounts.push_back(std::make_pair(taaCREATE, sleRoot)); } - - // Get the last node. - uint256 uNodeIndex = Ledger::getDirIndex(uBase, uNodeDir); - LedgerStateParms lspNode = lepNONE; - SLE::pointer sleNode = bRootNew ? SLE::pointer() : mLedger->getDirNode(lspNode, uNodeIndex); - - if (sleNode) + else { - STVector256 svIndexes; + uNodeDir = sleRoot->getIFieldU64(sfIndexPrevious); + + uint64 uNodePrevious = uNodeDir; + uint256 uNodeIndex; + + if (uNodeDir) + { + // Try adding to non-root. + uNodeIndex = Ledger::getDirNodeIndex(uRootIndex, uNodeDir); + lspRoot = lepNONE; + sleNode = mLedger->getDirNode(lspRoot, uNodeIndex); + } + else + { + // Try adding to root. + uNodeIndex = uRootIndex; + } svIndexes = sleNode->getIFieldV256(sfIndexes); + if (DIR_NODE_MAX != svIndexes.peekValue().size()) { - // Last node is not full, append. - - Log(lsTRACE) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); - Log(lsTRACE) << "dirAdd: appending: Node: " << strHex(uNodeDir); - Log(lsTRACE) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); - - svIndexes.peekValue().push_back(uLedgerIndex); - sleNode->setIFieldV256(sfIndexes, svIndexes); - + // Add to current node. accounts.push_back(std::make_pair(taaMODIFY, sleNode)); } - // Last node is full, add a new node. + // Add to new node. else if (!++uNodeDir) { return terDIR_FULL; } else { - // Record new last node. - sleNode = SLE::pointer(); - - Log(lsTRACE) << "dirAdd: last: " << strHex(uNodeDir); - - sleRoot->setIFieldU64(sfLastNode, uNodeDir); - + // Have root point to new node. + sleRoot->setIFieldU64(sfIndexPrevious, uNodeDir); accounts.push_back(std::make_pair(taaMODIFY, 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)); + } + + // Create the new node. + svIndexes = STVector256(); + sleNode = boost::make_shared(ltDIR_NODE); + sleNode->setIndex(uNodeIndex); + + if (uNodePrevious) + sleNode->setIFieldU64(sfIndexPrevious, uNodePrevious); + + accounts.push_back(std::make_pair(taaCREATE, sleNode)); } } - if (!sleNode) - { - // Add to last node, which is empty. - sleNode = boost::make_shared(ltDIR_NODE); - sleNode->setIndex(uNodeIndex); + Log(lsTRACE) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); + Log(lsTRACE) << "dirAdd: appending: Node: " << strHex(uNodeDir); + Log(lsTRACE) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); - Log(lsTRACE) << "dirAdd: Creating dir node: " << sleNode->getIndex().ToString(); - - STVector256 svIndexes; - - svIndexes.peekValue().push_back(uLedgerIndex); - sleNode->setIFieldV256(sfIndexes, svIndexes); - - accounts.push_back(std::make_pair(taaCREATE, sleNode)); - } + svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. + sleNode->setIFieldV256(sfIndexes, svIndexes); // Save entry. return terSUCCESS; } // <-> accounts: Affected accounts for the transaction. // --> uNodeDir: Node containing entry. -// --> uBase: The index of the base of the directory. Nodes are based off of this. +// --> 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, const uint64& uNodeDir, - const uint256& uBase, + const uint256& uRootIndex, const uint256& uLedgerIndex) { uint64 uNodeCur = uNodeDir; - uint256 uNodeIndex = Ledger::getDirIndex(uBase, uNodeCur); + uint256 uNodeIndex = Ledger::getDirNodeIndex(uRootIndex, uNodeCur); LedgerStateParms lspNode = lepNONE; SLE::pointer sleNode = mLedger->getDirNode(lspNode, uNodeIndex); + assert(sleNode); + if (!sleNode) { Log(lsWARNING) << "dirDelete: no such node"; - return terNODE_NOT_FOUND; + + return terBAD_LEDGER; } else { @@ -217,93 +221,151 @@ TransactionEngineResult TransactionEngine::dirDelete( std::vector::iterator it; it = std::find(vuiIndexes.begin(), vuiIndexes.end(), uLedgerIndex); + + assert(vuiIndexes.end() != it); if (vuiIndexes.end() == it) { Log(lsWARNING) << "dirDelete: node not mentioned"; - return terNODE_NOT_MENTIONED; + + return terBAD_LEDGER; } else { - // Get root information - LedgerStateParms lspRoot = lepNONE; - SLE::pointer sleRoot = mLedger->getDirRoot(lspRoot, Ledger::getDirIndex(uBase, 0)); - - if (!sleRoot) - { - Log(lsWARNING) << "dirDelete: root node is missing"; - return terNODE_NO_ROOT; - } - - uint64 uFirstNodeOrig = sleRoot->getIFieldU64(sfFirstNode); - uint64 uLastNodeOrig = sleRoot->getIFieldU64(sfLastNode); - uint64 uFirstNode = uFirstNodeOrig; - uint64 uLastNode = uLastNodeOrig; - // Remove the element. if (vuiIndexes.size() > 1) - { *it = vuiIndexes[vuiIndexes.size()-1]; - } + vuiIndexes.resize(vuiIndexes.size()-1); - sleNode->setIFieldV256(sfIndexes, svIndexes); - - if (!vuiIndexes.empty() || (uFirstNode != uNodeCur && uLastNode != uNodeCur)) + if (vuiIndexes.size() > 0) { // Node is not being deleted. + sleNode->setIFieldV256(sfIndexes, svIndexes); accounts.push_back(std::make_pair(taaMODIFY, sleNode)); } - - while (uFirstNode && svIndexes.peekValue().empty() - && (uFirstNode == uNodeCur || uLastNode == uNodeCur)) - { - // Current node is empty and first or last, delete it. - accounts.push_back(std::make_pair(taaDELETE, sleNode)); - - if (uFirstNode == uLastNode) - { - // Complete deletion. - uFirstNode = 0; - } - else - { - if (uFirstNode == uNodeCur) - { - // Advance first node - ++uNodeCur; - ++uFirstNode; - } - else - { - // Rewind last node - --uNodeCur; - --uLastNode; - } - - // Get replacement node. - lspNode = lepNONE; - sleNode = mLedger->getDirNode(lspNode, Ledger::getDirIndex(uBase, uNodeCur)); - svIndexes = sleNode->getIFieldV256(sfIndexes); - } - } - - if (uFirstNode == uFirstNodeOrig && uLastNode == uLastNodeOrig) - { - // Dir is fine. - nothing(); - } - else if (uFirstNode) - { - // Update root's pointer pointers. - sleRoot->setIFieldU64(sfFirstNode, uFirstNode); - sleRoot->setIFieldU64(sfLastNode, uLastNode); - - accounts.push_back(std::make_pair(taaMODIFY, sleRoot)); - } else { - // Delete the root. - accounts.push_back(std::make_pair(taaDELETE, sleRoot)); + bool bRootDirty = false; + SLE::pointer sleRoot; + + // May be able to delete nodes. + if (uNodeCur) + { + uint64 uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious); + uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); + + accounts.push_back(std::make_pair(taaDELETE, sleNode)); + + // Fix previous link. + if (uNodePrevious) + { + LedgerStateParms lspPrevious = lepNONE; + SLE::pointer slePrevious = mLedger->getDirNode(lspPrevious, Ledger::getDirNodeIndex(uRootIndex, uNodePrevious)); + + assert(slePrevious); + if (!slePrevious) + { + Log(lsWARNING) << "dirDelete: previous node is missing"; + + return terBAD_LEDGER; + } + else if (uNodeNext) + { + slePrevious->setIFieldU64(sfIndexNext, uNodeNext); + } + else + { + slePrevious->makeIFieldAbsent(sfIndexNext); + } + accounts.push_back(std::make_pair(taaMODIFY, slePrevious)); + } + else + { + // Read root. + bRootDirty = true; + + sleRoot = mLedger->getDirNode(lspNode, uRootIndex); + + if (uNodeNext) + { + sleRoot->setIFieldU64(sfIndexNext, uNodeNext); + } + else + { + sleRoot->makeIFieldAbsent(sfIndexNext); + } + } + + // Fix next link. + if (uNodeNext) + { + LedgerStateParms lspNext = lepNONE; + SLE::pointer sleNext = mLedger->getDirNode(lspNext, Ledger::getDirNodeIndex(uRootIndex, uNodeNext)); + + assert(sleNext); + if (!sleNext) + { + Log(lsWARNING) << "dirDelete: next node is missing"; + + return terBAD_LEDGER; + } + else if (uNodeNext) + { + sleNext->setIFieldU64(sfIndexNext, uNodeNext); + } + else + { + sleNext->makeIFieldAbsent(sfIndexNext); + } + accounts.push_back(std::make_pair(taaMODIFY, sleNext)); + } + else + { + // Read root. + bRootDirty = true; + + sleRoot = mLedger->getDirNode(lspNode, uRootIndex); + + if (uNodePrevious) + { + sleRoot->setIFieldU64(sfIndexPrevious, uNodePrevious); + } + else + { + sleRoot->makeIFieldAbsent(sfIndexPrevious); + } + } + + if (bRootDirty) + { + // Need to update sleRoot; + uNodeCur = 0; + + // If we might be able to delete root, load it. + if (!uNodePrevious && !uNodeNext) + vuiIndexes = svIndexes.peekValue(); + } + } + else + { + bRootDirty = true; + } + + if (!uNodeCur) + { + // Looking at root node. + uint64 uRootPrevious = sleNode->getIFieldU64(sfIndexPrevious); + uint64 uRootNext = sleNode->getIFieldU64(sfIndexNext); + + if (!uRootPrevious && !uRootNext && vuiIndexes.empty()) + { + accounts.push_back(std::make_pair(taaDELETE, sleRoot)); + } + else if (bRootDirty) + { + accounts.push_back(std::make_pair(taaMODIFY, sleRoot)); + } + } } } @@ -1758,7 +1820,7 @@ TransactionEngineResult TransactionEngine::doOffer( if (terSUCCESS == terResult) { terResult = dirAdd(accounts, uOfferNode, - Ledger::getDirIndex( + Ledger::getQualityIndex( Ledger::getBookBase(uCurrencyIn, uIssuerIn, uCurrencyOut, uIssuerOut), STAmount::getRate(saAmountOut, saAmountIn)), uLedgerIndex); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 80debf6ec5..5fb1804248 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -52,6 +52,7 @@ enum TransactionEngineResult // Conflict with ledger database: Fee claimed // Might succeed if not conflict is not caused by transaction ordering. terBAD_AUTH, + terBAD_LEDGER, terBAD_RIPPLE, terBAD_SEQ, terCREATED, @@ -102,13 +103,13 @@ private: TransactionEngineResult dirAdd( std::vector& accounts, uint64& uNodeDir, // Node of entry. - const uint256& uBase, + const uint256& uRootIndex, const uint256& uLedgerIndex); TransactionEngineResult dirDelete( std::vector& accounts, const uint64& uNodeDir, // Node item is mentioned in. - const uint256& uBase, // Key of item. + const uint256& uRootIndex, const uint256& uLedgerIndex); // Item being deleted #ifdef WORK_IN_PROGRESS From 9e04ae76fc4d720767ed81048e4b950b51e9cf09 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 17:59:21 -0700 Subject: [PATCH 04/13] Change protocol version. --- src/Version.h | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Version.h b/src/Version.h index 27cec8c5a2..0a9dc3bda4 100644 --- a/src/Version.h +++ b/src/Version.h @@ -1,26 +1,31 @@ - +#ifndef __VERSIONS__ +#define __VERSIONS__ +// // Versions +// -#ifndef SERVER_VERSION_MAJOR +// Version of this software: +#define SERVER_VERSION_MAJOR 0 +#define SERVER_VERSION_MINOR 1 +#define SERVER_VERSION_SUB "-a" +#define SERVER_NAME "NewCoin" -#define SERVER_VERSION_MAJOR 0 -#define SERVER_VERSION_MINOR 1 -#define SERVER_VERSION_SUB "-a" -#define SERVER_NAME "NewCoin" - -#define SV_STRINGIZE(x) SV_STRINGIZE2(x) -#define SV_STRINGIZE2(x) #x -#define SERVER_VERSION \ +#define SV_STRINGIZE(x) SV_STRINGIZE2(x) +#define SV_STRINGIZE2(x) #x +#define SERVER_VERSION \ (SERVER_NAME "-" SV_STRINGIZE(SERVER_VERSION_MAJOR) "." SV_STRINGIZE(SERVER_VERSION_MINOR) SERVER_VERSION_SUB) -#define PROTO_VERSION_MAJOR 0 -#define PROTO_VERSION_MINOR 1 +// Version we prefer to speak: +#define PROTO_VERSION_MAJOR 0 +#define PROTO_VERSION_MINOR 2 -#define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 1 +// Version we wil speak to: +#define MIN_PROTO_MAJOR 0 +#define MIN_PROTO_MINOR 2 #define MAKE_VERSION_INT(maj,min) ((maj << 16) | min) #define GET_VERSION_MAJOR(ver) (ver >> 16) #define GET_VERSION_MINOR(ver) (ver & 0xff) #endif +// vim:ts=4 From 74fdafb6888ca9dfc27daf4b4687b0cc9461a06d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 19:42:30 -0700 Subject: [PATCH 05/13] Fix for dirAdd. --- src/TransactionEngine.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 98078a6443..271fcb31a5 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -180,13 +180,13 @@ 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(); - svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. - sleNode->setIFieldV256(sfIndexes, svIndexes); // Save entry. - return terSUCCESS; } From a0422631a20b555c661c445791f8781b3cde8820 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 19:43:20 -0700 Subject: [PATCH 06/13] Add getJson() for STVector256. --- src/SerializedObject.cpp | 13 +++++++++++++ src/SerializedTypes.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 8f465936f6..6fbd45e63f 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -1,6 +1,7 @@ #include "SerializedObject.h" +#include #include #include "../json/writer.h" @@ -654,6 +655,18 @@ Json::Value STObject::getJson(int options) const return ret; } +Json::Value STVector256::getJson(int options) const +{ + Json::Value ret(Json::arrayValue); + + BOOST_FOREACH(std::vector::const_iterator::value_type vEntry, mValue) + { + ret.append(vEntry.ToString()); + } + + return ret; +} + static SOElement testSOElements[2][16] = { // field, name, id, type, flags { diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 04462f2452..5953faed2f 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -640,6 +640,8 @@ public: void setValue(const STVector256& v) { mValue = v.mValue; } void setValue(const std::vector& v) { mValue = v; } + + Json::Value getJson(int) const; }; #endif From 7ff41d62a1625d421575a3958c9f7c0011405683 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 19:44:52 -0700 Subject: [PATCH 07/13] Breaking Json API, return versions as chars. --- src/RPCServer.cpp | 18 +++++++++--------- src/SerializedLedger.cpp | 8 +++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index db71fb62c7..560e1cf845 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -487,18 +487,18 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) // Get info on account. - uint256 uClosed = mNetOps->getClosedLedger(); - Json::Value jClosed = accountFromString(uClosed, naAccount, bIndex, strIdent, iIndex); + uint256 uAccepted = mNetOps->getClosedLedger(); + Json::Value jAccepted = accountFromString(uAccepted, naAccount, bIndex, strIdent, iIndex); - if (jClosed.empty()) + if (jAccepted.empty()) { - AccountState::pointer asClosed = mNetOps->getAccountState(uClosed, naAccount); + AccountState::pointer asAccepted = mNetOps->getAccountState(uAccepted, naAccount); - if (asClosed) - asClosed->addJson(jClosed); + if (asAccepted) + asAccepted->addJson(jAccepted); } - ret["closed"] = jClosed; + ret["accepted"] = jAccepted; uint256 uCurrent = mNetOps->getCurrentLedger(); Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); @@ -514,7 +514,7 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) ret["current"] = jCurrent; #if 0 - if (!jClosed && !asCurrent) + if (!jAccepted && !asCurrent) { ret["account"] = naAccount.humanAccountID(); ret["status"] = "NotFound"; @@ -528,7 +528,7 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) // account_lines || [] Json::Value RPCServer::doAccountLines(const Json::Value ¶ms) { -// uint256 uClosed = mNetOps->getClosedLedger(); +// uint256 uAccepted = mNetOps->getClosedLedger(); uint256 uCurrent = mNetOps->getCurrentLedger(); std::string strIdent = params[0u].asString(); diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 0dac98c623..372e9cd730 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -57,9 +57,11 @@ std::string SerializedLedgerEntry::getText() const Json::Value SerializedLedgerEntry::getJson(int options) const { Json::Value ret(mObject.getJson(options)); - ret["type"] = mFormat->t_name; - ret["index"] = mIndex.GetHex(); - ret["version"] = mVersion.getText(); + + ret["type"] = mFormat->t_name; + ret["index"] = mIndex.GetHex(); + ret["version"] = std::string(1, mVersion); + return ret; } From 6be83c09db322a3e0254eb9fb7ee260a81669d2c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Jul 2012 17:12:20 -0700 Subject: [PATCH 08/13] Add SLE next/prev functions. --- src/Ledger.h | 6 ++++++ src/LedgerNode.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Ledger.h b/src/Ledger.h index 482fb27ba3..e175a18209 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -153,6 +153,12 @@ public: static Ledger::pointer loadByIndex(uint32 ledgerIndex); 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 + // index calculation functions static uint256 getAccountRootIndex(const uint160& uAccountID); diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index d059b9c3e7..84be09053b 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -43,6 +43,38 @@ LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) return lepOKAY; } +SLE::pointer Ledger::getNextSLE(const uint256& hash) +{ + SHAMapItem::pointer node = mAccountStateMap->peekNextItem(hash); + if (!node) + return SLE::pointer(); + return boost::make_shared(node->peekSerializer(), node->getTag()); +} + +SLE::pointer Ledger::getNextSLE(const uint256& hash, const uint256& max) +{ + SHAMapItem::pointer node = mAccountStateMap->peekNextItem(hash); + if ((!node) || (node->getTag() > max)) + return SLE::pointer(); + return boost::make_shared(node->peekSerializer(), node->getTag()); +} + +SLE::pointer Ledger::getPrevSLE(const uint256& hash) +{ + SHAMapItem::pointer node = mAccountStateMap->peekPrevItem(hash); + if (!node) + return SLE::pointer(); + return boost::make_shared(node->peekSerializer(), node->getTag()); +} + +SLE::pointer Ledger::getPrevSLE(const uint256& hash, const uint256& min) +{ + SHAMapItem::pointer node = mAccountStateMap->peekNextItem(hash); + if ((!node) || (node->getTag() < min)) + return SLE::pointer(); + return boost::make_shared(node->peekSerializer(), node->getTag()); +} + SLE::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID, LedgerEntryType let ) { From cbc4212150153c2e4f78fe2ba18dcadf8384c43b Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 9 Jul 2012 17:37:20 -0700 Subject: [PATCH 09/13] Remove transaction transit_set. --- src/RPCServer.cpp | 72 --------------------------------------------- src/Transaction.cpp | 37 ----------------------- src/Transaction.h | 17 ----------- src/main.cpp | 1 - 4 files changed, 127 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 560e1cf845..3c27ac2429 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1294,77 +1294,6 @@ Json::Value RPCServer::doServerInfo(const Json::Value& params) return ret; } -// transit_set -Json::Value RPCServer::doTransitSet(const Json::Value& params) -{ - NewcoinAddress naSeed; - NewcoinAddress naSrcAccountID; - std::string sTransitRate; - std::string sTransitStart; - std::string sTransitExpire; - uint32 uTransitRate; - uint32 uTransitStart; - uint32 uTransitExpire; - uint256 uLedger = mNetOps->getCurrentLedger(); - - if (params.size() >= 6) - sTransitRate = params[6u].asString(); - - if (params.size() >= 7) - sTransitStart = params[7u].asString(); - - if (params.size() >= 8) - sTransitExpire = params[8u].asString(); - - if (!naSeed.setSeedGeneric(params[0u].asString())) - { - return RPCError(rpcBAD_SEED); - } - else if (!naSrcAccountID.setAccountID(params[1u].asString())) - { - return RPCError(rpcSRC_ACT_MALFORMED); - } - else - { - NewcoinAddress naMasterGenerator; - NewcoinAddress naAccountPublic; - NewcoinAddress naAccountPrivate; - AccountState::pointer asSrc; - STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, - saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); - - if (!obj.empty()) - return obj; - - uTransitRate = 0; - uTransitStart = 0; - uTransitExpire = 0; - - Transaction::pointer trans = Transaction::sharedTransitSet( - naAccountPublic, naAccountPrivate, - naSrcAccountID, - asSrc->getSeq(), - theConfig.FEE_DEFAULT, - 0, // YYY No source tag - uTransitRate, - uTransitStart, - uTransitExpire); - - (void) mNetOps->processTransaction(trans); - - obj["transaction"] = trans->getSTransaction()->getJson(0); - obj["status"] = trans->getStatus(); - obj["seed"] = naSeed.humanSeed(); - obj["srcAccountID"] = naSrcAccountID.humanAccountID(); - obj["transitRate"] = uTransitRate; - obj["transitStart"] = uTransitStart; - obj["transitExpire"] = uTransitExpire; - - return obj; - } -} - Json::Value RPCServer::doTx(const Json::Value& params) { // tx @@ -2061,7 +1990,6 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "send", &RPCServer::doSend, 3, 7, false, optCurrent }, { "server_info", &RPCServer::doServerInfo, 0, 0, true }, { "stop", &RPCServer::doStop, 0, 0, true }, - { "transit_set", &RPCServer::doTransitSet, 5, 5, true, optCurrent }, { "tx", &RPCServer::doTx, 1, 1, true }, { "unl_add", &RPCServer::doUnlAdd, 1, 2, true }, diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 95d4d27720..483cc61043 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -413,43 +413,6 @@ Transaction::pointer Transaction::sharedPayment( return tResult->setPayment(naPrivateKey, naDstAccountID, saAmount, saSendMax, saPaths); } -// -// TransitSet -// - -Transaction::pointer Transaction::setTransitSet( - const NewcoinAddress& naPrivateKey, - uint32 uTransitRate, - uint32 uTransitStart, - uint32 uTransitExpire) -{ - if (uTransitRate) - mTransaction->setITFieldU32(sfTransitRate, uTransitRate); - if (uTransitStart) - mTransaction->setITFieldU32(sfTransitStart, uTransitStart); - if (uTransitExpire) - mTransaction->setITFieldU32(sfTransitExpire, uTransitExpire); - - sign(naPrivateKey); - - return shared_from_this(); -} - -Transaction::pointer Transaction::sharedTransitSet( - const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, - const NewcoinAddress& naSourceAccount, - uint32 uSeq, - const STAmount& saFee, - uint32 uSourceTag, - uint32 uTransitRate, - uint32 uTransitStart, - uint32 uTransitExpire) -{ - pointer tResult = boost::make_shared(ttTRANSIT_SET, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag); - - return tResult->setTransitSet(naPrivateKey, uTransitRate, uTransitStart, uTransitExpire); -} - // // WalletAdd // diff --git a/src/Transaction.h b/src/Transaction.h index 2f34f1b20c..02f2562819 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -96,12 +96,6 @@ private: const STAmount& saSendMax, const STPathSet& spPaths); - Transaction::pointer setTransitSet( - const NewcoinAddress& naPrivateKey, - uint32 uTransitRate, - uint32 uTransitStart, - uint32 uTransitExpire); - Transaction::pointer setWalletAdd( const NewcoinAddress& naPrivateKey, const STAmount& saAmount, @@ -206,17 +200,6 @@ public: const STAmount& saSendMax, const STPathSet& saPaths); - // Set transit fees. - static Transaction::pointer sharedTransitSet( - const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, - const NewcoinAddress& naSourceAccount, - uint32 uSeq, - const STAmount& saFee, - uint32 uSourceTag, - uint32 uTransitRate, - uint32 uTransitStart, - uint32 uTransitExpire); - // Add an account to a wallet. static Transaction::pointer sharedWalletAdd( const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, diff --git a/src/main.cpp b/src/main.cpp index aa9e3d7b67..0962728b69 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,7 +57,6 @@ void printHelp(const po::options_description& desc) cout << " peers" << endl; cout << " send [] [] []" << endl; cout << " stop" << endl; - cout << " transit_set " << endl; cout << " tx " << endl; cout << " unl_add | []" << endl; cout << " unl_delete |" << endl; From 3462ab0f0780da0c2c2af0d153e3624a06fe6527 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 9 Jul 2012 17:38:03 -0700 Subject: [PATCH 10/13] Work towards ripple and offers. --- src/Amount.cpp | 51 +++-- src/Ledger.h | 19 +- src/LedgerFormats.cpp | 5 +- src/LedgerFormats.h | 2 +- src/LedgerIndex.cpp | 4 +- src/SerializedObject.h | 7 +- src/SerializedTypes.h | 8 +- src/TransactionEngine.cpp | 418 +++++++++++++++++++++++-------------- src/TransactionEngine.h | 4 +- src/TransactionFormats.cpp | 22 +- src/TransactionFormats.h | 3 +- 11 files changed, 333 insertions(+), 210 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index a3831035f9..dcce9a8bd8 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -256,10 +256,11 @@ STAmount::STAmount(const char* name, int64 value) : SerializedType(name), mOffse void STAmount::setValue(const STAmount &a) { - mCurrency = a.mCurrency; - mValue = a.mValue; - mOffset = a.mOffset; - mIsNative = a.mIsNative; + mCurrency = a.mCurrency; + mIssuer = a.mIssuer; + mValue = a.mValue; + mOffset = a.mOffset; + mIsNative = a.mIsNative; mIsNegative = a.mIsNegative; } @@ -455,11 +456,13 @@ STAmount STAmount::operator-(void) const STAmount& STAmount::operator=(const STAmount& a) { - mValue = a.mValue; - mOffset = a.mOffset; - mCurrency = a.mCurrency; - mIsNative = a.mIsNative; + mValue = a.mValue; + mOffset = a.mOffset; + mIssuer = a.mIssuer; + mCurrency = a.mCurrency; + mIsNative = a.mIsNative; mIsNegative = a.mIsNegative; + return *this; } @@ -469,6 +472,7 @@ STAmount& STAmount::operator=(uint64 v) mValue = v; mIsNegative = false; if (!mIsNative) canonicalize(); + return *this; } @@ -477,6 +481,7 @@ STAmount& STAmount::operator+=(uint64 v) if (mIsNative) setSNValue(getSNValue() + static_cast(v)); else *this += STAmount(mCurrency, v); + return *this; } @@ -485,6 +490,7 @@ STAmount& STAmount::operator-=(uint64 v) if (mIsNative) setSNValue(getSNValue() - static_cast(v)); else *this -= STAmount(mCurrency, v); + return *this; } @@ -697,15 +703,24 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16 else return STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14); } +// Convert an offer into an index amount so they sort by rate. +// A taker will take the best, lowest, rate first. +// (e.g. a taker will prefer pay 1 get 3 over pay 1 get 2. +// --> offerOut: takerGets: How much the offerer is selling to the taker. +// --> offerIn: takerPays: How much the offerer is receiving from the taker. +// <-- uRate: normalize(offerIn/offerOut) +// A lower rate is better for the person taking the order. +// The taker gets more for less with a lower rate. uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) -{ // Convert an offer into an index amount so they sort (lower is better) - // offerOut = how much comes out of the offer, from the offeror to the taker - // offerIn = how much goes into the offer, from the taker to the offeror +{ if (offerOut.isZero()) throw std::runtime_error("Worthless offer"); STAmount r = divide(offerIn, offerOut, uint160(1)); + assert((r.getExponent() >= -100) && (r.getExponent() <= 155)); + uint64 ret = r.getExponent() + 100; + return (ret << (64 - 8)) | r.getMantissa(); } @@ -746,11 +761,19 @@ STAmount STAmount::getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& p return ret; } -STAmount STAmount::getNeeded(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed) +STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed) { // Someone wants to get (needed) out of the offer, how much should they pay in? - if (offerOut.isZero()) return STAmount(offerIn.getCurrency()); - if (needed >= offerOut) return needed; + if (offerOut.isZero()) + return STAmount(offerIn.getCurrency()); + + if (needed >= offerOut) + { + // They need more than offered, pay full amount. + return needed; + } + STAmount ret = divide(multiply(needed, offerIn, uint160(1)), offerOut, offerIn.getCurrency()); + return (ret > offerIn) ? offerIn : ret; } diff --git a/src/Ledger.h b/src/Ledger.h index 2cda039463..93d0d2ff34 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -65,6 +65,7 @@ private: uint256 mHash, mParentHash, mTransHash, mAccountHash; uint64 mTotCoins; uint64 mCloseTime; // when this ledger closes + uint64 mParentCloseTime; uint32 mLedgerSeq; uint16 mLedgerInterval; bool mClosed, mValidHash, mAccepted, mImmutable; @@ -119,6 +120,7 @@ public: uint64 getTotalCoins() const { return mTotCoins; } void destroyCoins(uint64 fee) { mTotCoins -= fee; } uint64 getCloseTimeNC() const { return mCloseTime; } + uint64 getParentCloseTimeNC() const { return mParentCloseTime; } uint32 getLedgerSeq() const { return mLedgerSeq; } uint16 getInterval() const { return mLedgerInterval; } @@ -200,17 +202,24 @@ public: SLE::pointer getOffer(LedgerStateParms& parms, const uint160& uAccountID, uint32 uSequence) { return getOffer(parms, getOfferIndex(uAccountID, uSequence)); } - + // The index of an offer. static uint256 getOfferIndex(const uint160& uAccountID, uint32 uSequence); - static uint256 getOfferDirIndex(const uint160& uAccountID); + // + // Owner functions + // + + // All items controlled by an account are here: offers + static uint256 getOwnerDirIndex(const uint160& uAccountID); // // Directory functions - // + // Directories are doubly linked lists of nodes. + // Given a directory root and and index compute the index of a node. static uint256 getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex=0); + // Return a node: root or normal SLE::pointer getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex); // @@ -223,12 +232,12 @@ public: // Ripple functions : credit lines // + // Index of node which is the ripple state between to accounts for a currency. static uint256 getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency); static uint256 getRippleStateIndex(const uint160& uiA, const uint160& uiB, const uint160& uCurrency) { return getRippleStateIndex(NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency); } - static uint256 getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB) - { return getRippleStateIndex(naA, naB, uint160()); } + // Directory of lines indexed by an account (not all lines are indexed) static uint256 getRippleDirIndex(const uint160& uAccountID); RippleState::pointer getRippleState(const uint256& uNode); diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index d745c557f2..0c1e15ef98 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -16,7 +16,8 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 }, { S_FIELD(WalletLocator), STI_HASH256, SOE_IFFLAG, 4 }, { S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 8 }, - { S_FIELD(TransitRate), STI_UINT32, SOE_IFFLAG, 16 }, + { S_FIELD(TransferRate), STI_UINT32, SOE_IFFLAG, 16 }, + { S_FIELD(Domain), STI_VL, SOE_IFFLAG, 32 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, @@ -49,7 +50,7 @@ LedgerEntryFormat LedgerFormats[]= { 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(BookNode), STI_UINT64, SOE_REQUIRED, 0 }, { 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 f3d6fae544..230e557c48 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -25,7 +25,7 @@ enum LedgerNameSpace spaceRipple = 'r', spaceRippleDir = 'R', spaceOffer = 'o', // Entry for an offer. - spaceOfferDir = 'O', // Directory of an account's offers. + spaceOwnerDir = 'O', // Directory of things owned by an account. spaceBookDir = 'B', // Directory of order books. spaceBond = 'b', spaceInvoice = 'i', diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp index a60d522385..0d2071a0ff 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -99,11 +99,11 @@ uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence) return s.getSHA512Half(); } -uint256 Ledger::getOfferDirIndex(const uint160& uAccountID) +uint256 Ledger::getOwnerDirIndex(const uint160& uAccountID) { Serializer s(22); - s.add16(spaceOfferDir); // 2 + s.add16(spaceOwnerDir); // 2 s.add160(uAccountID); // 20 return s.getSHA512Half(); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 628219a4c3..5dfcc4694e 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -34,6 +34,7 @@ enum SOE_Field sfAmountOut, sfAuthorizedKey, sfBalance, + sfBookNode, sfBorrowExpire, sfBorrowRate, sfBorrowStart, @@ -43,6 +44,7 @@ enum SOE_Field sfCurrencyIn, sfCurrencyOut, sfDestination, + sfDomain, sfEmailHash, sfExpiration, sfExtensions, @@ -76,7 +78,6 @@ enum SOE_Field sfNextTransitRate, sfNextTransitStart, sfNickname, - sfOfferNode, sfOfferSequence, sfOwnerNode, sfPaths, @@ -90,9 +91,7 @@ enum SOE_Field sfSourceTag, sfTarget, sfTargetLedger, - sfTransitExpire, - sfTransitRate, - sfTransitStart, + sfTransferRate, sfVersion, sfWalletLocator, diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 5953faed2f..9b97202850 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -207,6 +207,7 @@ class STAmount : public SerializedType protected: uint160 mCurrency; + uint160 mIssuer; // Only for access, not compared. uint64 mValue; int mOffset; @@ -282,7 +283,10 @@ public: void negate() { if (!isZero()) mIsNegative = !mIsNegative; } void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; mIsNegative = false; } - const uint160& getCurrency() const { return mCurrency; } + const uint160& getIssuer() const { return mIssuer; } + void setIssuer(const uint160& uIssuer) { mIssuer = uIssuer; } + + const uint160& getCurrency() const { return mCurrency; } bool setValue(const std::string& sAmount, const std::string& sCurrency); void setValue(const STAmount &); @@ -329,7 +333,7 @@ public: static STAmount getClaimed(STAmount& offerOut, STAmount& offerIn, STAmount& paid); // Someone is offering X for Y, I need Z, how much do I pay - static STAmount getNeeded(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed); + static STAmount getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed); // Native currency conversions, to/from display format static uint64 convertToDisplayAmount(const STAmount& internalAmount, uint64 totalNow, uint64 totalInit); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 271fcb31a5..448e0ecbf8 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -61,12 +61,12 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { terINSUF_FEE_T, "terINSUF_FEE_T", "fee insufficient now (account doesn't exist, network load)" }, { terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a directory node." }, { terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "Could not remove node from a directory." }, - { terNODE_NO_ROOT, "terNODE_NO_ROOT", "Directory doesn't exist." }, + { terNODE_NO_ROOT, "terNODE_NO_ROOT", "Directory doesn't exist." }, { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" }, { 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." }, + { 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" }, @@ -452,7 +452,8 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran TransactionEngineParams params, Ledger::pointer ledger) { Log(lsTRACE) << "applyTransaction>"; - mLedger = ledger; + mLedger = ledger; + mLedgerParentCloseTime = mLedger->getParentCloseTimeNC(); #ifdef DEBUG if (1) @@ -536,10 +537,9 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttACCOUNT_SET: case ttCREDIT_SET: case ttINVOICE: - case ttOFFER: + case ttOFFER_CREATE: case ttOFFER_CANCEL: case ttPASSWORD_FUND: - case ttTRANSIT_SET: case ttWALLET_ADD: nothing(); break; @@ -797,8 +797,8 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran result = doInvoice(txn, accounts); break; - case ttOFFER: - result = doOffer(txn, accounts, srcAccountID); + case ttOFFER_CREATE: + result = doOfferCreate(txn, accounts, srcAccountID); break; case ttOFFER_CANCEL: @@ -821,10 +821,6 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran result = doPayment(txn, accounts, srcAccountID); break; - case ttTRANSIT_SET: - result = doTransitSet(txn, accounts); - break; - case ttWALLET_ADD: result = doWalletAdd(txn, accounts); break; @@ -1549,125 +1545,6 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return terBAD_RIPPLE; } -TransactionEngineResult TransactionEngine::doTransitSet(const SerializedTransaction& st, std::vector&) -{ - std::cerr << "doTransitSet>" << std::endl; -#if 0 - SLE::pointer sleSrc = accounts[0].second; - - bool bTxnTransitRate = st->getIFieldPresent(sfTransitRate); - bool bTxnTransitStart = st->getIFieldPresent(sfTransitStart); - bool bTxnTransitExpire = st->getIFieldPresent(sfTransitExpire); - uint32 uTxnTransitRate = bTxnTransitRate ? st->getIFieldU32(sfTransitRate) : 0; - uint32 uTxnTransitStart = bTxnTransitStart ? st->getIFieldU32(sfTransitStart) : 0; - uint32 uTxnTransitExpire = bTxnTransitExpire ? st->getIFieldU32(sfTransitExpire) : 0; - - bool bActTransitRate = sleSrc->getIFieldPresent(sfTransitRate); - bool bActTransitExpire = sleSrc->getIFieldPresent(sfTransitExpire); - bool bActNextTransitRate = sleSrc->getIFieldPresent(sfNextTransitRate); - bool bActNextTransitStart = sleSrc->getIFieldPresent(sfNextTransitStart); - bool bActNextTransitExpire = sleSrc->getIFieldPresent(sfNextTransitExpire); - uint32 uActTransitRate = bActTransitRate ? sleSrc->getIFieldU32(sfTransitRate) : 0; - uint32 uActTransitExpire = bActTransitExpire ? sleSrc->getIFieldU32(sfTransitExpire) : 0; - uint32 uActNextTransitRate = bActNextTransitRate ? sleSrc->getIFieldU32(sfNextTransitRate) : 0; - uint32 uActNextTransitStart = bActNextTransitStart ? sleSrc->getIFieldU32(sfNextTransitStart) : 0; - uint32 uActNextTransitExpire = bActNextTransitExpire ? sleSrc->getIFieldU32(sfNextTransitExpire) : 0; - - // - // Update view - // - - bool bNoCurrent = !bActTransitRate; - bool bCurrentExpired = - bActTransitExpire // Current can expire - && bActNextTransitStart // Have a replacement - && uActTransitExpire <= uLedger; // Current is expired - - // Replace current with next if need. - if (bNoCurrent // No current. - && bActNextTransitRate // Have next. - && uActNextTransitStart <= uLedger) // Next has started. - { - // Make next current. - uActTransitRate = uActNextTransitRate; - bActTransitExpire = bActNextTransitStart; - uActTransitExpire = uActNextTransitExpire; - - // Remove next. - uActNextTransitStart = 0; - } - - // - // Determine new transaction deposition. - // - - bool bBetterThanCurrent = - !no current - || ( - Expires same or later than current - Start before or same as current - Fee same or less than current - ) - - bool bBetterThanNext = - !no next - || ( - Expires same or later than next - Start before or same as next - Fee same or less than next - ) - - bool bBetterThanBoth = - bBetterThanCurrent && bBetterThanNext - - bool bCurrentBlocks = - !bBetterThanCurrent - && overlaps with current - - bool bNextBlocks = - !bBetterThanNext - && overlaps with next - - if (bBetterThanBoth) - { - // Erase both and install. - - // If not starting now, install as next. - } - else if (bCurrentBlocks || bNextBlocks) - { - // Invalid ignore - } - else if (bBetterThanCurrent) - { - // Install over current - } - else if (bBetterThanNext) - { - // Install over next - } - else - { - // Error. - } - - return tenTRANSIT_WORSE; - - // Set current. - uDstTransitRate = uTxnTransitRate; - uDstTransitExpire = uTxnTransitExpire; // 0 for never expire. - - // Set future. - uDstNextTransitRate = uTxnTransitRate; - uDstNextTransitStart = uTxnTransitStart; - uDstNextTransitExpire = uTxnTransitExpire; // 0 for never expire. - - if (txn.getITFieldPresent(sfCurrency)) -#endif - std::cerr << "doTransitSet<" << std::endl; - return tenINVALID; -} - TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransaction& txn, std::vector& accounts) { @@ -1736,10 +1613,168 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction return tenUNKNOWN; } -// XXX Needs to take offers. -// XXX Use bPassive when taking. -// XXX Also use quality when rippling a take. -TransactionEngineResult TransactionEngine::doOffer( +#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( + bool bPassive, + uint64 uTakeQuality, + const uint256& uBookBase, + const uint160& uTakerAccountID, + STAmount& saTakerGets, // With issuer. + STAmount& saTakerPays, // With issuer. + std::vector vspUnfundedFound) +{ + uint256 uTipIndex = uBookIndex; + bool bDone = true; + STAmount saSold = 0; // XXX Add in currency + STAmount saOffered = XXX amount to fill. + TransactionEngineResult terResult = tenUNKNOWN; + + while (tenUNKNOWN == terResult) + { + uTipIndex = Ledger::indexNext(uTipIndex); + + uint256 uTipBase; + uint64 uTipQuality = Ledger::indexQuality(uTipIndex, uTipBase); + + if (saSold == saAmount) + { + // Filled order. + terResult = terSUCCESS; + } + else if (uTipBase != uBookBase + || uTakeQuality < uTipQuality + || (bPassive && uTakeQuality == uTipQuality)) + { + // No qualifying offer. + + terResult = terSUCCESS; + } + else + { + // Have an offer to consider. + LedgerStateParms qry = lepNONE; + SLE::pointer sleOffer = mLedger->getOffer(qry, uTipIndex); + + assert(sleOffer); + if (!sleOffer) + { + // Missing ledger entry. + Log(lsINFO) << "offerTake: Missing offer node: " << uTipIndex.ToString(); + + terResult = terBAD_LEDGER; + } + else + { + NewcoinAddress naOfferAccountID = sleOffer->getIValueFieldAccount(sfAccount); + STAmount saOfferTakerGets = sleOffer->getIValueFieldAmount(sfAmountOut); + + if (naOfferAccountID == uTakerAccountID) + { + // Would take own offer. Consider it unfunded. Delete it. + + vspUnfundedFound.push_back(sleOffer); + } + else if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= prevLedgerClose) + { + // Offer is expired. Delete it. + + vspUnfundedFound.push_back(sleOffer); + } + else + { + SLE::pointer sleOfferAccount; + SLE::pointer sleOfferRipplePays; + STAmount saOfferBalance; + + 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"; + + terResult = terNO_ACCOUNT; + } + else + { + saOfferBalance = sleOfferAccount->getIValueFieldAmount(sfBalance); + } + } + 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); + } + } + + } + // Handle getting IOUs. + else + + 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 + else + makeChanges + } + } + else + { + bDone = true; + } + } + + return tenUNKNOWN == terResult ? terSUCCESS : terResult; +} +#endif + +TransactionEngineResult TransactionEngine::doOfferCreate( const SerializedTransaction& txn, std::vector& accounts, const uint160& uSrcAccountID) @@ -1748,8 +1783,8 @@ TransactionEngineResult TransactionEngine::doOffer( bool bPassive = !!(txFlags & tfPassive); STAmount saAmountIn = txn.getITFieldAmount(sfAmountIn); STAmount saAmountOut = txn.getITFieldAmount(sfAmountOut); - uint160 uIssuerIn = txn.getITFieldAccount(sfIssuerIn); - uint160 uIssuerOut = txn.getITFieldAccount(sfIssuerOut); + uint160 uIssuerInID = txn.getITFieldAccount(sfIssuerIn); + uint160 uIssuerOutID = txn.getITFieldAccount(sfIssuerOut); uint32 uExpiration = txn.getITFieldU32(sfExpiration); bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); uint32 uSequence = txn.getSequence(); @@ -1758,72 +1793,133 @@ TransactionEngineResult TransactionEngine::doOffer( SLE::pointer sleOffer = boost::make_shared(ltOFFER); uint256 uLedgerIndex = Ledger::getOfferIndex(uSrcAccountID, uSequence); - Log(lsINFO) << "doOffer: Creating offer node: " << uLedgerIndex.ToString(); + Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString(); uint160 uCurrencyIn = saAmountIn.getCurrency(); uint160 uCurrencyOut = saAmountOut.getCurrency(); - TransactionEngineResult terResult; + TransactionEngineResult terResult = terSUCCESS; uint64 uOwnerNode; // Delete hint. - uint64 uOfferNode; // Delete hint. - // uint64 uBookNode; // Delete hint. + uint64 uBookNode; // Delete hint. uint32 uPrevLedgerTime = 0; // XXX Need previous if (!bHaveExpiration || !uExpiration) { - Log(lsWARNING) << "doOffer: Malformed offer: bad expiration"; + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration"; terResult = tenBAD_EXPIRATION; } else if (!bHaveExpiration || uPrevLedgerTime >= uExpiration) { - Log(lsWARNING) << "doOffer: Expired transaction: offer expired"; + Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; terResult = tenEXPIRED; } else if (saAmountIn.isNative() && saAmountOut.isNative()) { - Log(lsWARNING) << "doOffer: Malformed offer: stamps for stamps"; + Log(lsWARNING) << "doOfferCreate: Malformed offer: stamps for stamps"; terResult = tenBAD_OFFER; } else if (saAmountIn.isZero() || saAmountOut.isZero()) { - Log(lsWARNING) << "doOffer: Malformed offer: bad amount"; + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; terResult = tenBAD_OFFER; } - else if (uCurrencyIn == uCurrencyOut && uIssuerIn == uIssuerOut) + else if (uCurrencyIn == uCurrencyOut && uIssuerInID == uIssuerOutID) { - Log(lsWARNING) << "doOffer: Malformed offer: no conversion"; + Log(lsWARNING) << "doOfferCreate: Malformed offer: no conversion"; terResult = tenREDUNDANT; } - else if (uCurrencyIn.isZero() == uIssuerIn.isZero() && uCurrencyOut.isZero() == uIssuerOut.isZero()) + else if (saAmountIn.isNative() != uIssuerInID.isZero() || saAmountOut.isNative() != uIssuerOutID.isZero()) { - Log(lsWARNING) << "doOffer: Malformed offer: bad issuer"; + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer"; terResult = tenBAD_ISSUER; } + else + { + // Make sure signer has funds. + SLE::pointer sleSrc = accounts[0].second; + STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance); - // XXX check currencies and accounts - // XXX check funded - // XXX check output credit line exists - // XXX when deleting a credit line, delete outstanding offers + if (saAmountOut.isNative() && !saSrcBalance.isZero()) + { + // 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; - // XXX Only place the offer if a portion is not filled. + STAmount saSrcBalance = sleRippleOut->getIValueFieldAmount(sfBalance); + if (bSltD) + saSrcBalance.negate(); // Put balance in low terms. - if (terSUCCESS == terResult) - terResult = dirAdd(accounts, uOwnerNode, Ledger::getOfferDirIndex(uSrcAccountID), uLedgerIndex); + if (saSrcBalance.isPositive()) + { + // Funded. + nothing(); + } + else + { + Log(lsWARNING) << "doOfferCreate: delay: offers must be funded"; + + terResult = terUNFUNDED; + } + } + } if (terSUCCESS == terResult) { - terResult = dirAdd(accounts, uOfferNode, - Ledger::getQualityIndex( - Ledger::getBookBase(uCurrencyIn, uIssuerIn, uCurrencyOut, uIssuerOut), - STAmount::getRate(saAmountOut, saAmountIn)), - uLedgerIndex); + LedgerStateParms qry = lepNONE; + SLE::pointer sleRippleIn = mLedger->getAccountRoot(qry, uIssuerInID); + if (!sleRippleIn) + { + Log(lsWARNING) << "doOfferCreate: delay: can't receive IOUs from non-existant issuer"; + + terResult = terNO_ACCOUNT; + } + } + + if (terSUCCESS == terResult) + { +#ifdef WORK_IN_PROGRESS + terResult = offerTake( + bPassive, + STAmount::getRate(saAmountIn, saAmountOut), + Ledger::getBookBase(uCurrencyOut, uIssuerOutID, uCurrencyIn, uIssuerInID) + ); +#endif + } + // XXX Check if some portion of order was not complete. + + if (terSUCCESS == terResult) + { + // Add offer to owner's directory. + terResult = dirAdd(accounts, 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) @@ -1835,7 +1931,7 @@ TransactionEngineResult TransactionEngine::doOffer( sleOffer->setIFieldAmount(sfAmountIn, saAmountIn); sleOffer->setIFieldAmount(sfAmountOut, saAmountOut); sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); - sleOffer->setIFieldU64(sfOfferNode, uOfferNode); + sleOffer->setIFieldU64(sfBookNode, uBookNode); sleOffer->setIFieldU32(sfExpiration, uExpiration); if (bPassive) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 5fb1804248..d8dec7e466 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -140,6 +140,7 @@ private: 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); @@ -147,7 +148,7 @@ 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 doOfferCreate(const SerializedTransaction& txn, std::vector& accounts, const uint160& uSrcAccountID); TransactionEngineResult doOfferCancel(const SerializedTransaction& txn, std::vector& accounts, const uint160& uSrcAccountID); @@ -160,7 +161,6 @@ protected: const uint160& uSrcAccountID); TransactionEngineResult doStore(const SerializedTransaction& txn, std::vector& accounts); TransactionEngineResult doTake(const SerializedTransaction& txn, std::vector& accounts); - TransactionEngineResult doTransitSet(const SerializedTransaction& txn, std::vector& accounts); TransactionEngineResult doWalletAdd(const SerializedTransaction& txn, std::vector& accounts); public: diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 6809bfec5e..0f23fb7693 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -7,10 +7,11 @@ TransactionFormat InnerTxnFormats[]= { { "AccountSet", ttACCOUNT_SET, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 1 }, - { S_FIELD(WalletLocator), STI_HASH256, SOE_IFFLAG, 2 }, - { S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 4 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 8 }, + { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, + { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 }, + { S_FIELD(WalletLocator), STI_HASH256, SOE_IFFLAG, 4 }, + { S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 8 }, + { S_FIELD(Domain), STI_VL, SOE_IFFLAG, 16 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, @@ -53,7 +54,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, - { "Offer", ttOFFER, { + { "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 }, @@ -63,7 +64,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, - { "OfferCancel", ttOFFER, { + { "OfferCancel", ttOFFER_CANCEL, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(OfferSequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, @@ -98,15 +99,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, - { "TransitSet", ttTRANSIT_SET, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(TransitRate), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(TransitStart), STI_UINT32, SOE_IFFLAG, 2 }, - { S_FIELD(TransitExpire), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 8 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, { "WalletAdd", ttWALLET_ADD, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index b1967ecb75..7994fdee84 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -13,10 +13,9 @@ enum TransactionType ttPASSWORD_FUND = 4, ttPASSWORD_SET = 5, ttNICKNAME_SET = 6, - ttOFFER = 7, + ttOFFER_CREATE = 7, ttOFFER_CANCEL = 8, ttCREDIT_SET = 20, - ttTRANSIT_SET = 21, ttINVOICE = 10, }; From d6f18a9195d2038c15af88cfb0282e7563e05c79 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 9 Jul 2012 18:01:36 -0700 Subject: [PATCH 11/13] Add operator+() to uint256. --- src/uint256.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/uint256.h b/src/uint256.h index a13c814dc3..2529705f32 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -138,6 +138,20 @@ public: return ret; } + base_uint& operator+=(const base_uint& b) + { + uint64 carry = 0; + + for (int i = 0; i < WIDTH; i++) + { + uint64 n = carry + pn[i] + b.pn[i]; + pn[i] = n & 0xffffffff; + carry = n >> 32; + } + + return *this; + } + std::size_t hash_combine(std::size_t& seed) const { for (int i = 0; i < WIDTH; ++i) From 96b314c78cd9f22704ab6de59a5ef8af6396d74d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 9 Jul 2012 18:01:52 -0700 Subject: [PATCH 12/13] Add getQualityNext. --- src/Ledger.h | 1 + src/LedgerIndex.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/Ledger.h b/src/Ledger.h index 41ac04b86e..9811a83516 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -233,6 +233,7 @@ public: // static uint256 getQualityIndex(const uint256& uBase, const uint64 uNodeDir=0); + static uint256 getQualityNext(const uint256& uBase); // // Ripple functions : credit lines diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp index 0d2071a0ff..79ec76bd33 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -15,6 +15,17 @@ uint256 Ledger::getQualityIndex(const uint256& uBase, const uint64 uNodeDir) return uNode; } +uint256 Ledger::getQualityNext(const uint256& uBase) +{ + static uint256 uNext("10000000000000000"); + + uint256 uResult = uBase; + + uResult += uNext; + + return uResult; +} + uint256 Ledger::getAccountRootIndex(const uint160& uAccountID) { Serializer s(22); From 164350658f8e43132f383f9b21c91062e9084be6 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 9 Jul 2012 21:10:51 -0700 Subject: [PATCH 13/13] Rename RPC commands to ripple_lines_get and ripple_line_set. --- src/RPCServer.cpp | 332 +++++++++++++++++++++++----------------------- src/RPCServer.h | 4 +- src/main.cpp | 4 +- 3 files changed, 170 insertions(+), 170 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 3c27ac2429..68aab99bf0 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -525,107 +525,6 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) return ret; } -// account_lines || [] -Json::Value RPCServer::doAccountLines(const Json::Value ¶ms) -{ -// uint256 uAccepted = mNetOps->getClosedLedger(); - uint256 uCurrent = mNetOps->getCurrentLedger(); - - std::string strIdent = params[0u].asString(); - bool bIndex; - int iIndex = 2 == params.size()? lexical_cast_s(params[1u].asString()) : 0; - - NewcoinAddress naAccount; - - Json::Value ret; - - ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); - - if (!ret.empty()) - return ret; - - // Get info on account. - ret = Json::Value(Json::objectValue); - - ret["account"] = naAccount.humanAccountID(); - if (bIndex) - ret["index"] = iIndex; - - AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount); - if (as) - { - Json::Value jsonLines = Json::Value(Json::objectValue); - - ret["account"] = naAccount.humanAccountID(); - - // We access a committed ledger and need not worry about changes. - uint256 uRootIndex; - - if (mNetOps->getDirLineInfo(uCurrent, naAccount, uRootIndex)) - { - bool bDone = false; - - while (!bDone) - { - uint64 uNodePrevious; - uint64 uNodeNext; - STVector256 svRippleNodes = mNetOps->getDirNodeInfo(uCurrent, uRootIndex, uNodePrevious, uNodeNext); - - BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) - { - NewcoinAddress naAccountPeer; - STAmount saBalance; - STAmount saLimit; - STAmount saLimitPeer; - - RippleState::pointer rsLine = mNetOps->getRippleState(uCurrent, uNode); - - if (rsLine) - { - rsLine->setViewAccount(naAccount); - - naAccountPeer = rsLine->getAccountIDPeer(); - saBalance = rsLine->getBalance(); - saLimit = rsLine->getLimit(); - saLimitPeer = rsLine->getLimitPeer(); - - Json::Value jPeer = Json::Value(Json::objectValue); - - jPeer["node"] = uNode.ToString(); - - jPeer["balance"] = saBalance.getText(); - jPeer["currency"] = saBalance.getCurrencyHuman(); - jPeer["limit"] = saLimit.getJson(0); - jPeer["limit_peer"] = saLimitPeer.getJson(0); - - jsonLines[naAccountPeer.humanAccountID()] = jPeer; - } - else - { - std::cerr << "doAccountLines: Bad index: " << uNode.ToString() << std::endl; - } - } - - if (uNodeNext) - { - uCurrent = Ledger::getDirNodeIndex(uRootIndex, uNodeNext); - } - else - { - bDone = true; - } - } - } - ret["lines"] = jsonLines; - } - else - { - ret["status"] = "NotFound"; - } - - return ret; -} - // account_message_set Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; @@ -759,69 +658,6 @@ Json::Value RPCServer::doConnect(const Json::Value& params) return "connecting"; } -// credit_set [] [] -Json::Value RPCServer::doCreditSet(const Json::Value& params) -{ - NewcoinAddress naSeed; - NewcoinAddress naSrcAccountID; - NewcoinAddress naDstAccountID; - STAmount saLimitAmount; - uint256 uLedger = mNetOps->getCurrentLedger(); - uint32 uAcceptRate = params.size() >= 6 ? lexical_cast_s(params[5u].asString()) : 0; - - if (!naSeed.setSeedGeneric(params[0u].asString())) - { - return RPCError(rpcBAD_SEED); - } - else if (!naSrcAccountID.setAccountID(params[1u].asString())) - { - return RPCError(rpcSRC_ACT_MALFORMED); - } - else if (!naDstAccountID.setAccountID(params[2u].asString())) - { - return RPCError(rpcDST_ACT_MALFORMED); - } - else if (!saLimitAmount.setValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "")) - { - return RPCError(rpcSRC_AMT_MALFORMED); - } - else - { - NewcoinAddress naMasterGenerator; - NewcoinAddress naAccountPublic; - NewcoinAddress naAccountPrivate; - AccountState::pointer asSrc; - STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, - saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); - - if (!obj.empty()) - return obj; - - Transaction::pointer trans = Transaction::sharedCreditSet( - naAccountPublic, naAccountPrivate, - naSrcAccountID, - asSrc->getSeq(), - theConfig.FEE_DEFAULT, - 0, // YYY No source tag - naDstAccountID, - saLimitAmount, - uAcceptRate); - - (void) mNetOps->processTransaction(trans); - - obj["transaction"] = trans->getSTransaction()->getJson(0); - obj["status"] = trans->getStatus(); - obj["seed"] = naSeed.humanSeed(); - obj["srcAccountID"] = naSrcAccountID.humanAccountID(); - obj["dstAccountID"] = naDstAccountID.humanAccountID(); - obj["limitAmount"] = saLimitAmount.getText(); - obj["acceptRate"] = uAcceptRate; - - return obj; - } -} - // data_delete Json::Value RPCServer::doDataDelete(const Json::Value& params) { @@ -1154,6 +990,170 @@ Json::Value RPCServer::doPeers(const Json::Value& params) return obj; } +// ripple_line_set [] [] +Json::Value RPCServer::doRippleLineSet(const Json::Value& params) +{ + NewcoinAddress naSeed; + NewcoinAddress naSrcAccountID; + NewcoinAddress naDstAccountID; + STAmount saLimitAmount; + uint256 uLedger = mNetOps->getCurrentLedger(); + uint32 uAcceptRate = params.size() >= 6 ? lexical_cast_s(params[5u].asString()) : 0; + + if (!naSeed.setSeedGeneric(params[0u].asString())) + { + return RPCError(rpcBAD_SEED); + } + else if (!naSrcAccountID.setAccountID(params[1u].asString())) + { + return RPCError(rpcSRC_ACT_MALFORMED); + } + else if (!naDstAccountID.setAccountID(params[2u].asString())) + { + return RPCError(rpcDST_ACT_MALFORMED); + } + else if (!saLimitAmount.setValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "")) + { + return RPCError(rpcSRC_AMT_MALFORMED); + } + else + { + NewcoinAddress naMasterGenerator; + NewcoinAddress naAccountPublic; + NewcoinAddress naAccountPrivate; + AccountState::pointer asSrc; + STAmount saSrcBalance; + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); + + if (!obj.empty()) + return obj; + + Transaction::pointer trans = Transaction::sharedCreditSet( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + theConfig.FEE_DEFAULT, + 0, // YYY No source tag + naDstAccountID, + saLimitAmount, + uAcceptRate); + + (void) mNetOps->processTransaction(trans); + + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); + obj["seed"] = naSeed.humanSeed(); + obj["srcAccountID"] = naSrcAccountID.humanAccountID(); + obj["dstAccountID"] = naDstAccountID.humanAccountID(); + obj["limitAmount"] = saLimitAmount.getText(); + obj["acceptRate"] = uAcceptRate; + + return obj; + } +} + +// ripple_lines_get || [] +Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) +{ +// uint256 uAccepted = mNetOps->getClosedLedger(); + uint256 uCurrent = mNetOps->getCurrentLedger(); + + std::string strIdent = params[0u].asString(); + bool bIndex; + int iIndex = 2 == params.size()? lexical_cast_s(params[1u].asString()) : 0; + + NewcoinAddress naAccount; + + Json::Value ret; + + ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + + if (!ret.empty()) + return ret; + + // Get info on account. + ret = Json::Value(Json::objectValue); + + ret["account"] = naAccount.humanAccountID(); + if (bIndex) + ret["index"] = iIndex; + + AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount); + if (as) + { + Json::Value jsonLines = Json::Value(Json::objectValue); + + ret["account"] = naAccount.humanAccountID(); + + // We access a committed ledger and need not worry about changes. + uint256 uRootIndex; + + if (mNetOps->getDirLineInfo(uCurrent, naAccount, uRootIndex)) + { + bool bDone = false; + + while (!bDone) + { + uint64 uNodePrevious; + uint64 uNodeNext; + STVector256 svRippleNodes = mNetOps->getDirNodeInfo(uCurrent, uRootIndex, uNodePrevious, uNodeNext); + + BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) + { + NewcoinAddress naAccountPeer; + STAmount saBalance; + STAmount saLimit; + STAmount saLimitPeer; + + RippleState::pointer rsLine = mNetOps->getRippleState(uCurrent, uNode); + + if (rsLine) + { + rsLine->setViewAccount(naAccount); + + naAccountPeer = rsLine->getAccountIDPeer(); + saBalance = rsLine->getBalance(); + saLimit = rsLine->getLimit(); + saLimitPeer = rsLine->getLimitPeer(); + + Json::Value jPeer = Json::Value(Json::objectValue); + + jPeer["node"] = uNode.ToString(); + + jPeer["balance"] = saBalance.getText(); + jPeer["currency"] = saBalance.getCurrencyHuman(); + jPeer["limit"] = saLimit.getJson(0); + jPeer["limit_peer"] = saLimitPeer.getJson(0); + + jsonLines[naAccountPeer.humanAccountID()] = jPeer; + } + else + { + std::cerr << "doAccountLines: Bad index: " << uNode.ToString() << std::endl; + } + } + + if (uNodeNext) + { + uCurrent = Ledger::getDirNodeIndex(uRootIndex, uNodeNext); + } + else + { + bDone = true; + } + } + } + ret["lines"] = jsonLines; + } + else + { + ret["status"] = "NotFound"; + } + + return ret; +} + // send regular_seed paying_account account_id amount [currency] [send_max] [send_currency] Json::Value RPCServer::doSend(const Json::Value& params) { @@ -1970,12 +1970,10 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params } commandsA[] = { { "account_email_set", &RPCServer::doAccountEmailSet, 2, 3, false, optCurrent }, { "account_info", &RPCServer::doAccountInfo, 1, 2, false, optCurrent }, - { "account_lines", &RPCServer::doAccountLines, 1, 2, false, optCurrent|optClosed }, { "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 }, - { "credit_set", &RPCServer::doCreditSet, 4, 6, false, optCurrent }, { "data_delete", &RPCServer::doDataDelete, 1, 1, true }, { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, @@ -1987,6 +1985,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "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 }, diff --git a/src/RPCServer.h b/src/RPCServer.h index c57871d753..fa6be57e9d 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -123,12 +123,10 @@ private: Json::Value doAccountEmailSet(const Json::Value ¶ms); Json::Value doAccountInfo(const Json::Value& params); - Json::Value doAccountLines(const Json::Value ¶ms); Json::Value doAccountMessageSet(const Json::Value ¶ms); Json::Value doAccountTransactions(const Json::Value& params); Json::Value doAccountWalletSet(const Json::Value ¶ms); Json::Value doConnect(const Json::Value& params); - Json::Value doCreditSet(const Json::Value& params); Json::Value doDataDelete(const Json::Value& params); Json::Value doDataFetch(const Json::Value& params); Json::Value doDataStore(const Json::Value& params); @@ -140,6 +138,8 @@ private: Json::Value doPasswordFund(const Json::Value& params); Json::Value doPasswordSet(const Json::Value& params); Json::Value doPeers(const Json::Value& params); + Json::Value doRippleLinesGet(const Json::Value ¶ms); + Json::Value doRippleLineSet(const Json::Value& params); Json::Value doSend(const Json::Value& params); Json::Value doServerInfo(const Json::Value& params); Json::Value doSessionClose(const Json::Value& params); diff --git a/src/main.cpp b/src/main.cpp index 0962728b69..75832a912b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,11 +41,9 @@ void printHelp(const po::options_description& desc) cout << " account_email_set []" << endl; cout << " account_info |" << endl; cout << " account_info || []" << endl; - cout << " account_lines |" << endl; cout << " account_message_set " << endl; cout << " account_wallet_set []" << endl; cout << " connect []" << endl; - cout << " credit_set []" << endl; cout << " data_delete " << endl; cout << " data_fetch " << endl; cout << " data_store " << endl; @@ -55,6 +53,8 @@ void printHelp(const po::options_description& desc) cout << " password_fund []" << endl; cout << " password_set []" << endl; cout << " peers" << endl; + cout << " ripple_lines_get || []" << endl; + cout << " ripple_line_set []" << endl; cout << " send [] [] []" << endl; cout << " stop" << endl; cout << " tx " << endl;