Merge branch 'master' of github.com:jedmccaleb/NewCoin

This commit is contained in:
Arthur Britto
2013-03-12 11:41:14 -07:00
18 changed files with 570 additions and 187 deletions

View File

@@ -183,6 +183,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
#ifndef NO_SQLITE3_PREPARE
{
LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtDISK, "HOS::retrieve"));
ScopedLock sl(theApp->getHashNodeDB()->getDBLock());
static SqliteStatement pSt(theApp->getHashNodeDB()->getDB()->getSqliteDB(),
"SELECT ObjType,LedgerIndex,Object FROM CommittedObjects WHERE Hash = ?;");

View File

@@ -405,7 +405,9 @@ void Ledger::saveAcceptedLedger(Job&, bool fromConsensus)
cLog(lsTRACE) << "saveAcceptedLedger " << (fromConsensus ? "fromConsensus " : "fromAcquire ") << getLedgerSeq();
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers INDEXED BY SeqLedger where LedgerSeq = %u;");
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %u;");
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransID = '%s';");
static boost::format deleteTrans1("DELETE FROM Transactions WHERE LedgerSeq = %u;");
static boost::format deleteTrans2("DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
static boost::format deleteAcctTrans("DELETE FROM AccountTransactions WHERE TransID = '%s';");
static boost::format transExists("SELECT Status FROM Transactions WHERE TransID = '%s';");
static boost::format
updateTx("UPDATE Transactions SET LedgerSeq = %u, Status = '%c', TxnMeta = %s WHERE TransID = '%s';");
@@ -431,88 +433,80 @@ void Ledger::saveAcceptedLedger(Job&, bool fromConsensus)
AcceptedLedger::pointer aLedger = AcceptedLedger::makeAcceptedLedger(shared_from_this());
{
{
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
if (SQL_EXISTS(theApp->getLedgerDB()->getDB(), boost::str(ledgerExists % mLedgerSeq)))
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(deleteLedger % mLedgerSeq));
}
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(deleteLedger % mLedgerSeq));
}
{
Database *db = theApp->getTxnDB()->getDB();
{
ScopedLock dbLock(theApp->getTxnDB()->getDBLock());
db->executeSQL("BEGIN TRANSACTION;");
ScopedLock dbLock(theApp->getTxnDB()->getDBLock());
db->executeSQL("BEGIN TRANSACTION;");
BOOST_FOREACH(const AcceptedLedger::value_type& vt, aLedger->getMap())
db->executeSQL(boost::str(deleteTrans1 % mLedgerSeq));
db->executeSQL(boost::str(deleteTrans2 % mLedgerSeq));
BOOST_FOREACH(const AcceptedLedger::value_type& vt, aLedger->getMap())
{
uint256 txID = vt.second.getTransactionID();
theApp->getMasterTransaction().inLedger(txID, mLedgerSeq);
db->executeSQL(boost::str(deleteAcctTrans % txID.GetHex()));
const std::vector<RippleAddress>& accts = vt.second.getAffected();
if (!accts.empty())
{
cLog(lsTRACE) << "Saving: " << vt.second.getJson(0);
uint256 txID = vt.second.getTransactionID();
theApp->getMasterTransaction().inLedger(txID, mLedgerSeq);
// Make sure transaction is in AccountTransactions.
if (!SQL_EXISTS(db, boost::str(AcctTransExists % txID.GetHex())))
std::string sql = "INSERT OR REPLACE INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES ";
bool first = true;
for (std::vector<RippleAddress>::const_iterator it = accts.begin(), end = accts.end(); it != end; ++it)
{
// Transaction not in AccountTransactions
const std::vector<RippleAddress>& accts = vt.second.getAffected();
if (!accts.empty())
{
std::string sql = "INSERT OR REPLACE INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES ";
bool first = true;
for (std::vector<RippleAddress>::const_iterator it = accts.begin(), end = accts.end(); it != end; ++it)
{
if (!first)
sql += ", ('";
else
{
sql += "('";
first = false;
}
sql += txID.GetHex();
sql += "','";
sql += it->humanAccountID();
sql += "',";
sql += boost::lexical_cast<std::string>(getLedgerSeq());
sql += ")";
}
sql += ";";
Log(lsTRACE) << "ActTx: " << sql;
db->executeSQL(sql); // may already be in there
}
if (!first)
sql += ", ('";
else
cLog(lsWARNING) << "Transaction in ledger " << mLedgerSeq << " affects no accounts";
}
if (SQL_EXISTS(db, boost::str(transExists % txID.GetHex())))
{
// In Transactions, update LedgerSeq, metadata and Status.
db->executeSQL(boost::str(updateTx
% getLedgerSeq()
% TXN_SQL_VALIDATED
% vt.second.getEscMeta()
% txID.GetHex()));
}
else
{
// Not in Transactions, insert the whole thing..
db->executeSQL(
SerializedTransaction::getMetaSQLInsertHeader() +
vt.second.getTxn()->getMetaSQL(getLedgerSeq(), vt.second.getEscMeta()) + ";");
{
sql += "('";
first = false;
}
sql += txID.GetHex();
sql += "','";
sql += it->humanAccountID();
sql += "',";
sql += boost::lexical_cast<std::string>(getLedgerSeq());
sql += ")";
}
sql += ";";
Log(lsTRACE) << "ActTx: " << sql;
db->executeSQL(sql); // may already be in there
}
db->executeSQL("COMMIT TRANSACTION;");
}
else
cLog(lsWARNING) << "Transaction in ledger " << mLedgerSeq << " affects no accounts";
if (!theConfig.RUN_STANDALONE)
theApp->getHashedObjectStore().waitWrite(); // wait until all nodes are written
{
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(addLedger %
getHash().GetHex() % mLedgerSeq % mParentHash.GetHex() %
boost::lexical_cast<std::string>(mTotCoins) % mCloseTime % mParentCloseTime %
mCloseResolution % mCloseFlags %
mAccountHash.GetHex() % mTransHash.GetHex()));
if (SQL_EXISTS(db, boost::str(transExists % txID.GetHex())))
{
// In Transactions, update LedgerSeq, metadata and Status.
db->executeSQL(boost::str(updateTx
% getLedgerSeq()
% TXN_SQL_VALIDATED
% vt.second.getEscMeta()
% txID.GetHex()));
}
else
{
// Not in Transactions, insert the whole thing..
db->executeSQL(
SerializedTransaction::getMetaSQLInsertHeader() +
vt.second.getTxn()->getMetaSQL(getLedgerSeq(), vt.second.getEscMeta()) + ";");
}
}
db->executeSQL("COMMIT TRANSACTION;");
}
{
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(addLedger %
getHash().GetHex() % mLedgerSeq % mParentHash.GetHex() %
boost::lexical_cast<std::string>(mTotCoins) % mCloseTime % mParentCloseTime %
mCloseResolution % mCloseFlags %
mAccountHash.GetHex() % mTransHash.GetHex()));
}
if (!fromConsensus)
@@ -1313,6 +1307,42 @@ std::vector< std::pair<uint32, uint256> > Ledger::getLedgerHashes()
return ret;
}
bool Ledger::isValidBook(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID)
{
if (uTakerPaysCurrency.isZero())
{ // XRP in
if (uTakerPaysIssuerID.isNonZero()) // XRP cannot have an issuer
return false;
if (uTakerGetsCurrency.isZero()) // XRP to XRP not allowed
return false;
if (uTakerGetsIssuerID.isZero()) // non-XRP must have issuer
return false;
return true;
}
// non-XRP in
if (uTakerPaysIssuerID.isZero()) // non-XRP must have issuer
return false;
if (uTakerGetsCurrency.isZero()) // non-XRP to XRP
{
if (uTakerGetsIssuerID.isNonZero()) // XRP cannot have issuer
return false;
}
else // non-XRP to non-XRP
{
if ((uTakerPaysCurrency == uTakerGetsCurrency) && (uTakerGetsIssuerID == uTakerGetsIssuerID))
return false; // Input and output cannot be identical
}
return true;
}
uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID)
{

View File

@@ -257,6 +257,9 @@ public:
//
// Order book dirs have a base so we can use next to step through them in quality order.
static bool isValidBook(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID);
static uint256 getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID);

View File

@@ -1598,21 +1598,21 @@ void NetworkOPs::unsubAccount(uint64 uSeq, const boost::unordered_set<RippleAddr
}
}
bool NetworkOPs::subBook(InfoSub::ref isrListener, const uint160& currencyIn, const uint160& currencyOut,
const uint160& issuerIn, const uint160& issuerOut)
bool NetworkOPs::subBook(InfoSub::ref isrListener, const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets)
{
BookListeners::pointer listeners =
theApp->getOrderBookDB().makeBookListeners(currencyIn, currencyOut, issuerIn, issuerOut);
theApp->getOrderBookDB().makeBookListeners(currencyPays, currencyGets, issuerPays, issuerGets);
if (listeners)
listeners->addSubscriber(isrListener);
return true;
}
bool NetworkOPs::unsubBook(uint64 uSeq,
const uint160& currencyIn, const uint160& currencyOut, const uint160& issuerIn, const uint160& issuerOut)
const uint160& currencyPays, const uint160& currencyGets, const uint160& issuerPays, const uint160& issuerGets)
{
BookListeners::pointer listeners =
theApp->getOrderBookDB().getBookListeners(currencyIn, currencyOut, issuerIn, issuerOut);
theApp->getOrderBookDB().getBookListeners(currencyPays, currencyGets, issuerPays, issuerGets);
if (listeners)
listeners->removeSubscriber(uSeq);
return true;

View File

@@ -322,10 +322,10 @@ public:
bool subServer(InfoSub::ref ispListener, Json::Value& jvResult);
bool unsubServer(uint64 uListener);
bool subBook(InfoSub::ref ispListener, const uint160& currencyIn, const uint160& currencyOut,
const uint160& issuerIn, const uint160& issuerOut);
bool unsubBook(uint64 uListener, const uint160& currencyIn, const uint160& currencyOut,
const uint160& issuerIn, const uint160& issuerOut);
bool subBook(InfoSub::ref ispListener, const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets);
bool unsubBook(uint64 uListener, const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets);
bool subTransactions(InfoSub::ref ispListener);
bool unsubTransactions(uint64 uListener);

View File

@@ -93,40 +93,40 @@ void OrderBookDB::getBooks(const uint160& issuerID, const uint160& currencyID, s
}
}
BookListeners::pointer OrderBookDB::makeBookListeners(const uint160& currencyIn, const uint160& currencyOut,
const uint160& issuerIn, const uint160& issuerOut)
BookListeners::pointer OrderBookDB::makeBookListeners(const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets)
{
boost::recursive_mutex::scoped_lock sl(mLock);
BookListeners::pointer ret = getBookListeners(currencyIn, currencyOut, issuerIn, issuerOut);
BookListeners::pointer ret = getBookListeners(currencyPays, currencyGets, issuerPays, issuerGets);
if (!ret)
{
ret = boost::make_shared<BookListeners>();
mListeners[issuerIn][issuerOut][currencyIn][currencyOut] = ret;
mListeners[issuerPays][issuerGets][currencyPays][currencyGets] = ret;
}
return ret;
}
BookListeners::pointer OrderBookDB::getBookListeners(const uint160& currencyIn, const uint160& currencyOut,
const uint160& issuerIn, const uint160& issuerOut)
BookListeners::pointer OrderBookDB::getBookListeners(const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets)
{
BookListeners::pointer ret;
boost::recursive_mutex::scoped_lock sl(mLock);
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > >::iterator
it0 = mListeners.find(issuerIn);
it0 = mListeners.find(issuerPays);
if(it0 == mListeners.end())
return ret;
std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > >::iterator
it1 = (*it0).second.find(issuerOut);
it1 = (*it0).second.find(issuerGets);
if(it1 == (*it0).second.end())
return ret;
std::map<uint160, std::map<uint160, BookListeners::pointer> >::iterator it2 = (*it1).second.find(currencyIn);
std::map<uint160, std::map<uint160, BookListeners::pointer> >::iterator it2 = (*it1).second.find(currencyPays);
if(it2 == (*it1).second.end())
return ret;
std::map<uint160, BookListeners::pointer>::iterator it3 = (*it2).second.find(currencyOut);
std::map<uint160, BookListeners::pointer>::iterator it3 = (*it2).second.find(currencyGets);
if(it3 == (*it2).second.end())
return ret;
@@ -216,16 +216,16 @@ void OrderBookDB::processTxn(Ledger::ref ledger, const ALTransaction& alTx, Json
if (data)
{
STAmount takerGets = data->getFieldAmount(sfTakerGets);
uint160 currencyOut = takerGets.getCurrency();
uint160 issuerOut = takerGets.getIssuer();
uint160 currencyGets = takerGets.getCurrency();
uint160 issuerGets = takerGets.getIssuer();
STAmount takerPays = data->getFieldAmount(sfTakerPays);
uint160 currencyIn = takerPays.getCurrency();
uint160 issuerIn = takerPays.getIssuer();
uint160 currencyPays = takerPays.getCurrency();
uint160 issuerPays = takerPays.getIssuer();
// determine the OrderBook
BookListeners::pointer book =
getBookListeners(currencyIn, currencyOut, issuerIn, issuerOut);
getBookListeners(currencyPays, currencyGets, issuerPays, issuerGets);
if (book)
book->publish(jvObj);
}

View File

@@ -35,8 +35,8 @@ class OrderBookDB
boost::unordered_map<uint160, std::vector<OrderBook::pointer> > mIssuerMap;
//std::vector<OrderBook::pointer> mAllOrderBooks;
// issuerIn, issuerOut, currencyIn, currencyOut
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > > mListeners;
// issuerPays, issuerGets, currencyPays, currencyGets
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > > mListeners;
uint32 mSeq;
boost::recursive_mutex mLock;
@@ -56,13 +56,13 @@ public:
void getBooks(const uint160& issuerID, const uint160& currencyID, std::vector<OrderBook::pointer>& bookRet);
// returns the best rate we can find
float getPrice(uint160& currencyIn,uint160& currencyOut);
float getPrice(uint160& currencyPays,uint160& currencyGets);
BookListeners::pointer getBookListeners(const uint160& currencyIn, const uint160& currencyOut,
const uint160& issuerIn, const uint160& issuerOut);
BookListeners::pointer makeBookListeners(const uint160& currencyIn, const uint160& currencyOut,
const uint160& issuerIn, const uint160& issuerOut);
BookListeners::pointer getBookListeners(const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets);
BookListeners::pointer makeBookListeners(const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets);
// see if this txn effects any orderbook
void processTxn(Ledger::ref ledger, const ALTransaction& alTx, Json::Value& jvObj);

View File

@@ -168,9 +168,6 @@ void Peer::handleVerifyTimer(const boost::system::error_code& ecResult)
else if (ecResult)
{
cLog(lsINFO) << "Peer verify timer error";
// Can't do anything sound.
abort();
}
else
{
@@ -222,6 +219,7 @@ void Peer::connect(const std::string& strIp, int iPort)
{
cLog(lsINFO) << "Peer: Connect: Outbound: " << ADDRESS(this) << ": " << mIpPort.first << " " << mIpPort.second;
boost::recursive_mutex::scoped_lock sl(ioMutex);
boost::asio::async_connect(
getSocket(),
itrEndpoint,

View File

@@ -2753,37 +2753,101 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest, int& cost)
}
if (jvRequest.isMember("books"))
{
{ // FIXME: This can crash the server if the parameters to things like getBookPage are invalid
for (Json::Value::iterator it = jvRequest["books"].begin(); it != jvRequest["books"].end(); it++)
{
uint160 currencyOut;
STAmount::currencyFromString(currencyOut,(*it)["CurrencyOut"].asString());
uint160 issuerOut,issuerIn;
if(currencyOut.isNonZero())
STAmount::issuerFromString(issuerOut,(*it)["IssuerOut"].asString());
uint160 currencyIn;
STAmount::currencyFromString(currencyIn,(*it)["CurrencyIn"].asString());
if(currencyIn.isNonZero())
STAmount::issuerFromString(issuerIn,(*it)["IssuerIn"].asString());
uint160 uTakerPaysCurrencyID;
uint160 uTakerPaysIssuerID;
Json::Value jvTakerPays = (*it)["taker_pays"];
bool bothSides=false;
if((*it).isMember("BothSides") && (*it)["BothSides"].asBool()) bothSides=true;
// Parse mandatory currency.
if (!jvTakerPays.isMember("currency")
|| !STAmount::currencyFromString(uTakerPaysCurrencyID, jvTakerPays["currency"].asString()))
{
cLog(lsINFO) << "Bad taker_pays currency.";
mNetOps->subBook(ispSub, currencyIn, currencyOut, issuerIn, issuerOut);
if(bothSides) mNetOps->subBook(ispSub, currencyOut, currencyIn, issuerOut, issuerIn);
if((*it)["StateNow"].asBool())
return rpcError(rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerPays.isMember("issuer"))
&& (!jvTakerPays["issuer"].isString()
|| !STAmount::issuerFromString(uTakerPaysIssuerID, jvTakerPays["issuer"].asString())))
// Don't allow illegal issuers.
|| (!uTakerPaysCurrencyID != !uTakerPaysIssuerID)
|| ACCOUNT_ONE == uTakerPaysIssuerID)
{
cLog(lsINFO) << "Bad taker_pays issuer.";
return rpcError(rpcSRC_ISR_MALFORMED);
}
uint160 uTakerGetsCurrencyID;
uint160 uTakerGetsIssuerID;
Json::Value jvTakerGets = (*it)["taker_gets"];
// Parse mandatory currency.
if (!jvTakerGets.isMember("currency")
|| !STAmount::currencyFromString(uTakerGetsCurrencyID, jvTakerGets["currency"].asString()))
{
cLog(lsINFO) << "Bad taker_pays currency.";
return rpcError(rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerGets.isMember("issuer"))
&& (!jvTakerGets["issuer"].isString()
|| !STAmount::issuerFromString(uTakerGetsIssuerID, jvTakerGets["issuer"].asString())))
// Don't allow illegal issuers.
|| (!uTakerGetsCurrencyID != !uTakerGetsIssuerID)
|| ACCOUNT_ONE == uTakerGetsIssuerID)
{
cLog(lsINFO) << "Bad taker_gets issuer.";
return rpcError(rpcDST_ISR_MALFORMED);
}
if (uTakerPaysCurrencyID == uTakerGetsCurrencyID
&& uTakerPaysIssuerID == uTakerGetsIssuerID)
{
cLog(lsINFO) << "taker_gets same as taker_pays.";
return rpcError(rpcBAD_MARKET);
}
RippleAddress raTakerID;
if (!(*it).isMember("taker"))
{
raTakerID.setAccountID(ACCOUNT_ONE);
}
else if (!raTakerID.setAccountID((*it)["taker"].asString()))
{
return rpcError(rpcBAD_ISSUER);
}
bool bothSides = (*it)["both_sides"].asBool();
if (!Ledger::isValidBook(uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID))
{
cLog(lsWARNING) << "Bad market: " <<
uTakerPaysCurrencyID << ":" << uTakerPaysIssuerID << " -> " <<
uTakerGetsCurrencyID << ":" << uTakerGetsIssuerID;
return rpcError(rpcBAD_MARKET);
}
mNetOps->subBook(ispSub, uTakerPaysCurrencyID, uTakerGetsCurrencyID, uTakerPaysIssuerID, uTakerGetsIssuerID);
if (bothSides) mNetOps->subBook(ispSub, uTakerGetsCurrencyID, uTakerPaysCurrencyID, uTakerGetsIssuerID, uTakerPaysIssuerID);
if ((*it)["state_now"].asBool())
{
Ledger::pointer ledger= theApp->getLedgerMaster().getClosedLedger();
RippleAddress raTakerID;
raTakerID.setAccountID(ACCOUNT_ONE);
const Json::Value jvMarker = Json::Value(Json::nullValue);
mNetOps->getBookPage(ledger, currencyOut, issuerOut, currencyIn, issuerIn, raTakerID.getAccountID(), false, 0, jvMarker, jvResult);
if(bothSides)
mNetOps->getBookPage(ledger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID(), false, 0, jvMarker, jvResult);
if (bothSides)
{
Json::Value tempJson(Json::objectValue);
if(jvResult.isMember("offers")) jvResult["bids"]=jvResult["offers"];
mNetOps->getBookPage(ledger, currencyIn, issuerIn, currencyOut, issuerOut, raTakerID.getAccountID(), false, 0, jvMarker, tempJson);
if(tempJson.isMember("offers")) jvResult["asks"]=tempJson["offers"];
if (jvResult.isMember("offers")) jvResult["bids"]=jvResult["offers"];
mNetOps->getBookPage(ledger, uTakerGetsCurrencyID, uTakerGetsIssuerID, uTakerPaysCurrencyID, uTakerPaysIssuerID, raTakerID.getAccountID(), false, 0, jvMarker, tempJson);
if (tempJson.isMember("offers")) jvResult["asks"]=tempJson["offers"];
}
}
}
@@ -2888,14 +2952,68 @@ Json::Value RPCHandler::doUnsubscribe(Json::Value jvRequest, int& cost)
{
for (Json::Value::iterator it = jvRequest["books"].begin(); it != jvRequest["books"].end(); it++)
{
uint160 currencyOut;
STAmount::issuerFromString(currencyOut,(*it)["CurrencyOut"].asString());
uint160 issuerOut = RippleAddress::createNodePublic( (*it)["IssuerOut"].asString() ).getAccountID();
uint160 currencyIn;
STAmount::issuerFromString(currencyOut,(*it)["CurrencyIn"].asString());
uint160 issuerIn = RippleAddress::createNodePublic( (*it)["IssuerIn"].asString() ).getAccountID();
uint160 uTakerPaysCurrencyID;
uint160 uTakerPaysIssuerID;
Json::Value jvTakerPays = (*it)["taker_pays"];
mNetOps->unsubBook(ispSub->getSeq(), currencyIn, currencyOut, issuerIn, issuerOut);
// Parse mandatory currency.
if (!jvTakerPays.isMember("currency")
|| !STAmount::currencyFromString(uTakerPaysCurrencyID, jvTakerPays["currency"].asString()))
{
cLog(lsINFO) << "Bad taker_pays currency.";
return rpcError(rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerPays.isMember("issuer"))
&& (!jvTakerPays["issuer"].isString()
|| !STAmount::issuerFromString(uTakerPaysIssuerID, jvTakerPays["issuer"].asString())))
// Don't allow illegal issuers.
|| (!uTakerPaysCurrencyID != !uTakerPaysIssuerID)
|| ACCOUNT_ONE == uTakerPaysIssuerID)
{
cLog(lsINFO) << "Bad taker_pays issuer.";
return rpcError(rpcSRC_ISR_MALFORMED);
}
uint160 uTakerGetsCurrencyID;
uint160 uTakerGetsIssuerID;
Json::Value jvTakerGets = (*it)["taker_gets"];
// Parse mandatory currency.
if (!jvTakerGets.isMember("currency")
|| !STAmount::currencyFromString(uTakerGetsCurrencyID, jvTakerGets["currency"].asString()))
{
cLog(lsINFO) << "Bad taker_pays currency.";
return rpcError(rpcSRC_CUR_MALFORMED);
}
// Parse optional issuer.
else if (((jvTakerGets.isMember("issuer"))
&& (!jvTakerGets["issuer"].isString()
|| !STAmount::issuerFromString(uTakerGetsIssuerID, jvTakerGets["issuer"].asString())))
// Don't allow illegal issuers.
|| (!uTakerGetsCurrencyID != !uTakerGetsIssuerID)
|| ACCOUNT_ONE == uTakerGetsIssuerID)
{
cLog(lsINFO) << "Bad taker_gets issuer.";
return rpcError(rpcDST_ISR_MALFORMED);
}
if (uTakerPaysCurrencyID == uTakerGetsCurrencyID
&& uTakerPaysIssuerID == uTakerGetsIssuerID)
{
cLog(lsINFO) << "taker_gets same as taker_pays.";
return rpcError(rpcBAD_MARKET);
}
bool bothSides = (*it)["both_sides"].asBool();
mNetOps->unsubBook(ispSub->getSeq(), uTakerPaysCurrencyID, uTakerGetsCurrencyID, uTakerPaysIssuerID, uTakerGetsIssuerID);
if (bothSides) mNetOps->unsubBook(ispSub->getSeq(), uTakerGetsCurrencyID, uTakerPaysCurrencyID, uTakerGetsIssuerID, uTakerPaysIssuerID);
}
}

View File

@@ -233,7 +233,7 @@ std::string SerializedTransaction::getSQLInsertReplaceHeader()
std::string SerializedTransaction::getMetaSQLInsertHeader()
{
return "INSERT OR REPLACE INTO Transactions " + getMetaSQLValueHeader() + " VALUES ";
return "INSERT INTO Transactions " + getMetaSQLValueHeader() + " VALUES ";
}
std::string SerializedTransaction::getSQL(uint32 inLedger, char status) const