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