diff --git a/src/Amount.cpp b/src/Amount.cpp index a3831035f..dcce9a8bd 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/Config.cpp b/src/Config.cpp index 0ca3ec46c..f2347cc6f 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 d5fc3ad73..5793fd81c 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. diff --git a/src/Ledger.h b/src/Ledger.h index d5565f622..c9c5c5951 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -65,7 +65,7 @@ private: uint256 mHash, mParentHash, mTransHash, mAccountHash; uint64 mTotCoins; uint64 mCloseTime; // when this ledger should close / did close - uint64 mPrevClose; // when the previous ledger closed + uint64 mParentCloseTime; uint32 mLedgerSeq; bool mClosed, mValidHash, mAccepted, mImmutable; @@ -118,6 +118,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; } // close time functions @@ -189,36 +190,59 @@ 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); + // The index of an offer. + static uint256 getOfferIndex(const uint160& uAccountID, uint32 uSequence); - static int getOfferSkip(const uint256& offerId); + // + // 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. - static uint256 getDirIndex(const uint256& uBase, const uint64 uNodeDir=0); + // Given a directory root and and index compute the index of a node. + static uint256 getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex=0); - SLE::pointer getDirRoot(LedgerStateParms& parms, const uint256& uRootIndex); + // Return a node: root or normal SLE::pointer getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex); // - // Ripple functions + // Quality // + static uint256 getQualityIndex(const uint256& uBase, const uint64 uNodeDir=0); + static uint256 getQualityNext(const uint256& uBase); + + // + // 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 711c9c258..0c1e15ef9 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -16,20 +16,16 @@ 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(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(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 } } }, { "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 } } }, @@ -46,6 +42,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(BookNode), 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 +61,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 53da1d617..230e557c4 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_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', + spaceDirNode = 'd', + spaceGenerator = 'g', + spaceNickname = 'n', + spaceRipple = 'r', + spaceRippleDir = 'R', + spaceOffer = 'o', // Entry for an offer. + spaceOwnerDir = 'O', // Directory of things owned by an account. + 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 0bf18f1c8..79ec76bd3 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -1,12 +1,87 @@ #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::getQualityNext(const uint256& uBase) +{ + static uint256 uNext("10000000000000000"); + + uint256 uResult = uBase; + + uResult += uNext; + + return uResult; +} + uint256 Ledger::getAccountRootIndex(const uint160& uAccountID) { - Serializer s; + Serializer s(22); - s.add16(spaceAccount); - s.add160(uAccountID); + s.add16(spaceAccount); // 2 + s.add160(uAccountID); // 20 + + return s.getSHA512Half(); +} + +uint256 Ledger::getBookBase(const uint160& uCurrencyIn, const uint160& uAccountIn, + const uint160& uCurrencyOut, const uint160& uAccountOut) +{ + bool bInNative = uCurrencyIn.isZero(); + bool bOutNative = uCurrencyOut.isZero(); + + assert(!bInNative || !bOutNative); // Stamps to stamps not allowed. + assert(bInNative == !uAccountIn.isZero()); // Make sure issuer is specified as needed. + assert(bOutNative == !uAccountOut.isZero()); // Make sure issuer is specified as needed. + assert(uCurrencyIn != uCurrencyOut || uAccountIn != uAccountOut); // Currencies or accounts must differ. + + Serializer s(82); + + s.add16(spaceBookDir); // 2 + s.add160(uCurrencyIn); // 20 + s.add160(uCurrencyOut); // 20 + s.add160(uAccountIn); // 20 + s.add160(uAccountOut); // 20 + + 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(); } @@ -16,20 +91,41 @@ uint256 Ledger::getAccountRootIndex(const uint160& uAccountID) // <-- SHA512/2: for consistency and speed in generating indexes. uint256 Ledger::getNicknameIndex(const uint256& uNickname) { - Serializer s; + Serializer s(34); - s.add16(spaceNickname); - s.add256(uNickname); + s.add16(spaceNickname); // 2 + s.add256(uNickname); // 32 return s.getSHA512Half(); } -uint256 Ledger::getGeneratorIndex(const uint160& uGeneratorID) +uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence) { - Serializer s; + Serializer s(26); - s.add16(spaceGenerator); - s.add160(uGeneratorID); + s.add16(spaceOffer); // 2 + s.add160(uAccountID); // 20 + s.add32(uSequence); // 4 + + return s.getSHA512Half(); +} + +uint256 Ledger::getOwnerDirIndex(const uint160& uAccountID) +{ + Serializer s(22); + + s.add16(spaceOwnerDir); // 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(); } @@ -39,75 +135,14 @@ uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddr uint160 uAID = naA.getAccountID(); uint160 uBID = naB.getAccountID(); bool bAltB = uAID < uBID; - Serializer s; + Serializer s(62); - s.add16(spaceRipple); - s.add160(bAltB ? uAID : uBID); - s.add160(bAltB ? uBID : uAID); - s.add160(uCurrency); + s.add16(spaceRipple); // 2 + s.add160(bAltB ? uAID : uBID); // 20 + s.add160(bAltB ? uBID : uAID); // 20 + s.add160(uCurrency); // 20 return s.getSHA512Half(); } -uint256 Ledger::getRippleDirIndex(const uint160& uAccountID) -{ - Serializer s; - - s.add16(spaceRippleDir); - s.add160(uAccountID); - - return s.getSHA512Half(); -} - -uint160 Ledger::getOfferBase(const uint160& currencyIn, const uint160& accountIn, - const uint160& currencyOut, const uint160& accountOut) -{ - bool inNative = currencyIn.isZero(); - bool outNative = currencyOut.isZero(); - - if (inNative && outNative) - throw std::runtime_error("native to native offer"); - - Serializer s(80); - - 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); - } - - 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(); -} - -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); -} - -int Ledger::getOfferSkip(const uint256& offerId) -{ // how far ahead we skip if an index node is full - return *offerId.begin(); -} - // vim:ts=4 diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index 2013247ad..59e163da1 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()); @@ -98,7 +100,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(); @@ -122,6 +124,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 // @@ -144,6 +157,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 // @@ -155,36 +180,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 3b1abcf5b..228d9bfcf 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; @@ -472,7 +451,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) { @@ -498,7 +477,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 a4695fc99..74e8a2469 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -110,9 +110,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 @@ -124,8 +123,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 c99f734f7..68aab99bf 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"; @@ -525,95 +525,6 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) return ret; } -// account_lines || [] -Json::Value RPCServer::doAccountLines(const Json::Value ¶ms) -{ -// uint256 uClosed = 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 uDirLineNodeFirst; - uint256 uDirLineNodeLast; - - if (mNetOps->getDirLineInfo(uCurrent, naAccount, uDirLineNodeFirst, uDirLineNodeLast)) - { - for (; uDirLineNodeFirst <= uDirLineNodeLast; uDirLineNodeFirst++) - { - STVector256 svRippleNodes = mNetOps->getDirNode(uCurrent, uDirLineNodeFirst); - - 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; - } - } - } - } - ret["lines"] = jsonLines; - } - else - { - ret["status"] = "NotFound"; - } - - return ret; -} - // account_message_set Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; @@ -747,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) { @@ -1142,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) { @@ -1282,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 @@ -2029,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 }, @@ -2046,10 +1985,11 @@ 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 }, - { "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/RPCServer.h b/src/RPCServer.h index c57871d75..fa6be57e9 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/SerializedLedger.cpp b/src/SerializedLedger.cpp index 0dac98c62..372e9cd73 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; } diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 8f465936f..6fbd45e63 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/SerializedObject.h b/src/SerializedObject.h index 0918db000..5dfcc4694 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -34,6 +34,7 @@ enum SOE_Field sfAmountOut, sfAuthorizedKey, sfBalance, + sfBookNode, sfBorrowExpire, sfBorrowRate, sfBorrowStart, @@ -43,8 +44,9 @@ enum SOE_Field sfCurrencyIn, sfCurrencyOut, sfDestination, + sfDomain, sfEmailHash, - sfExpireLedger, + sfExpiration, sfExtensions, sfFirstNode, sfFlags, @@ -55,7 +57,11 @@ enum SOE_Field sfHighLimit, sfIdentifier, sfIndexes, + sfIndexNext, + sfIndexPrevious, sfInvoiceID, + sfIssuerIn, + sfIssuerOut, sfLastNode, sfLastReceive, sfLastTxn, @@ -72,9 +78,12 @@ enum SOE_Field sfNextTransitRate, sfNextTransitStart, sfNickname, - sfOfferCurrency, + sfOfferSequence, + sfOwnerNode, sfPaths, sfPubKey, + sfQualityIn, + sfQualityOut, sfSendMax, sfSequence, sfSignature, @@ -82,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 04462f245..9b9720285 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); @@ -640,6 +644,8 @@ public: void setValue(const STVector256& v) { mValue = v.mValue; } void setValue(const std::vector& v) { mValue = v; } + + Json::Value getJson(int) const; }; #endif diff --git a/src/Serializer.h b/src/Serializer.h index a0962c43a..ab39a1c30 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/Transaction.cpp b/src/Transaction.cpp index 95d4d2772..483cc6104 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 2f34f1b20..02f256281 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/TransactionEngine.cpp b/src/TransactionEngine.cpp index d21010c4c..448e0ecbf 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_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." }, @@ -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." }, @@ -47,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." }, @@ -54,13 +59,14 @@ 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." }, { 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" }, @@ -87,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); + svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. + sleNode->setIFieldV256(sfIndexes, svIndexes); // Save entry. - 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)); - } + Log(lsTRACE) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); + Log(lsTRACE) << "dirAdd: appending: Node: " << strHex(uNodeDir); + Log(lsTRACE) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); 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 { @@ -212,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)); + } + } } } @@ -385,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) @@ -469,9 +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; @@ -729,8 +797,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran result = doInvoice(txn, accounts); break; - case ttOFFER: - result = doOffer(txn, accounts); + case ttOFFER_CREATE: + result = doOfferCreate(txn, accounts, srcAccountID); + break; + + case ttOFFER_CANCEL: + result = doOfferCancel(txn, accounts, srcAccountID); break; case ttNICKNAME_SET: @@ -749,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; @@ -1117,6 +1185,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, @@ -1337,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) { @@ -1524,10 +1613,371 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction return tenUNKNOWN; } -TransactionEngineResult TransactionEngine::doOffer(const SerializedTransaction& txn, - std::vector& accounts) +#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) { - return tenUNKNOWN; + 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) +{ + uint32 txFlags = txn.getFlags(); + bool bPassive = !!(txFlags & tfPassive); + STAmount saAmountIn = txn.getITFieldAmount(sfAmountIn); + STAmount saAmountOut = txn.getITFieldAmount(sfAmountOut); + uint160 uIssuerInID = txn.getITFieldAccount(sfIssuerIn); + uint160 uIssuerOutID = txn.getITFieldAccount(sfIssuerOut); + 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) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString(); + + uint160 uCurrencyIn = saAmountIn.getCurrency(); + uint160 uCurrencyOut = saAmountOut.getCurrency(); + + TransactionEngineResult terResult = terSUCCESS; + uint64 uOwnerNode; // Delete hint. + uint64 uBookNode; // Delete hint. + + uint32 uPrevLedgerTime = 0; // XXX Need previous + + if (!bHaveExpiration || !uExpiration) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration"; + + terResult = tenBAD_EXPIRATION; + } + else if (!bHaveExpiration || uPrevLedgerTime >= uExpiration) + { + Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; + + terResult = tenEXPIRED; + } + else if (saAmountIn.isNative() && saAmountOut.isNative()) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: stamps for stamps"; + + terResult = tenBAD_OFFER; + } + else if (saAmountIn.isZero() || saAmountOut.isZero()) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; + + terResult = tenBAD_OFFER; + } + else if (uCurrencyIn == uCurrencyOut && uIssuerInID == uIssuerOutID) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: no conversion"; + + terResult = tenREDUNDANT; + } + else if (saAmountIn.isNative() != uIssuerInID.isZero() || saAmountOut.isNative() != uIssuerOutID.isZero()) + { + 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); + + 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; + + STAmount saSrcBalance = sleRippleOut->getIValueFieldAmount(sfBalance); + if (bSltD) + saSrcBalance.negate(); // Put balance in low terms. + + if (saSrcBalance.isPositive()) + { + // Funded. + nothing(); + } + else + { + Log(lsWARNING) << "doOfferCreate: delay: offers must be funded"; + + terResult = terUNFUNDED; + } + } + } + + if (terSUCCESS == terResult) + { + 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) + { + sleOffer->setIndex(uLedgerIndex); + + sleOffer->setIFieldAccount(sfAccount, uSrcAccountID); + sleOffer->setIFieldU32(sfSequence, uSequence); + sleOffer->setIFieldAmount(sfAmountIn, saAmountIn); + sleOffer->setIFieldAmount(sfAmountOut, saAmountOut); + sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); + sleOffer->setIFieldU64(sfBookNode, uBookNode); + sleOffer->setIFieldU32(sfExpiration, uExpiration); + + 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 f7f70b812..d8dec7e46 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, @@ -48,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, @@ -62,6 +67,7 @@ enum TransactionEngineResult terNO_DST, terNO_LINE_NO_ZERO, terNO_PATH, + terOFFER_NOT_FOUND, terOVER_LIMIT, terPAST_LEDGER, terPAST_SEQ, @@ -97,20 +103,44 @@ 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 + 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: 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); @@ -118,7 +148,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 doOfferCreate(const SerializedTransaction& txn, std::vector& accounts, + const uint160& uSrcAccountID); + TransactionEngineResult doOfferCancel(const SerializedTransaction& txn, std::vector& accounts, + const uint160& uSrcAccountID); TransactionEngineResult doNicknameSet(const SerializedTransaction& txn, std::vector& accounts, const uint160& uSrcAccountID); TransactionEngineResult doPasswordFund(const SerializedTransaction& txn, std::vector& accounts, @@ -128,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 cddcafcf6..0f23fb769 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,14 +54,20 @@ 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 }, { 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_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 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, @@ -92,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 1f5b63d20..7994fdee8 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -13,10 +13,10 @@ enum TransactionType ttPASSWORD_FUND = 4, ttPASSWORD_SET = 5, ttNICKNAME_SET = 6, + ttOFFER_CREATE = 7, + ttOFFER_CANCEL = 8, ttCREDIT_SET = 20, - ttTRANSIT_SET = 21, ttINVOICE = 10, - ttOFFER = 11, }; struct TransactionFormat @@ -39,6 +39,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; diff --git a/src/Version.h b/src/Version.h index 2762c5938..7b8a1c573 100644 --- a/src/Version.h +++ b/src/Version.h @@ -1,26 +1,30 @@ - +#ifndef __VERSIONS__ +#define __VERSIONS__ +// // Versions - -#ifndef SERVER_VERSION_MAJOR +// #define SERVER_VERSION_MAJOR 0 #define SERVER_VERSION_MINOR 2 #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 2 +// Version we prefer to speak: +#define PROTO_VERSION_MAJOR 0 +#define PROTO_VERSION_MINOR 2 -#define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 2 +// 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 diff --git a/src/main.cpp b/src/main.cpp index aa9e3d7b6..75832a912 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,9 +53,10 @@ 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 << " transit_set " << endl; cout << " tx " << endl; cout << " unl_add | []" << endl; cout << " unl_delete |" << endl; diff --git a/src/uint256.h b/src/uint256.h index a13c814dc..2529705f3 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)