From e5ad771708373371bb110109cf3091bf74975525 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 7 Jul 2012 17:46:47 -0700 Subject: [PATCH] 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