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

This commit is contained in:
Arthur Britto
2012-11-29 15:46:56 -08:00
17 changed files with 203 additions and 49 deletions

View File

@@ -71,8 +71,24 @@ static void InitDB(DatabaseCon** dbCon, const char *fileName, const char *dbInit
*dbCon = new DatabaseCon(fileName, dbInit, dbCount);
}
volatile bool doShutdown = false;
#ifdef SIGINT
void sigIntHandler(int)
{
doShutdown = true;
}
#endif
void Application::run()
{
#ifdef SIGINT
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigIntHandler;
sigaction(SIGINT, &sa, NULL);
#endif
assert(mTxnDB == NULL);
if (!theConfig.DEBUG_LOGFILE.empty())
{ // Let DEBUG messages go to the file but only WARNING or higher to regular output (unless verbose)
@@ -118,13 +134,6 @@ void Application::run()
else
startNewLedger();
if (theConfig.FULL_HISTORY && (theConfig.START_UP != Config::LOAD))
{
Ledger::pointer ledger = Ledger::getLastFullLedger();
if (ledger)
mLedgerMaster.setLedgerRangePresent(0, ledger->getLedgerSeq());
}
//
// Begin validation and ip maintenance.
// - Wallet maintains local information: including identity and network connection persistence information.

View File

@@ -3,6 +3,7 @@
#include "utils.h"
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <fstream>
#include <iostream>
#include <algorithm>
@@ -14,7 +15,7 @@
#define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create"
#define SECTION_FEE_OFFER "fee_offer"
#define SECTION_FEE_OPERATION "fee_operation"
#define SECTION_FULL_HISTORY "full_history"
#define SECTION_LEDGER_HISTORY "ledger_history"
#define SECTION_IPS "ips"
#define SECTION_NETWORK_QUORUM "network_quorum"
#define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water"
@@ -157,7 +158,7 @@ void Config::setup(const std::string& strConf)
FEE_DEFAULT = DEFAULT_FEE_DEFAULT;
FEE_CONTRACT_OPERATION = DEFAULT_FEE_OPERATION;
FULL_HISTORY = false;
LEDGER_HISTORY = 256;
ACCOUNT_PROBE_MAX = 10;
@@ -292,8 +293,16 @@ void Config::load()
if (sectionSingleB(secConfig, SECTION_FEE_OPERATION, strTemp))
FEE_CONTRACT_OPERATION = boost::lexical_cast<int>(strTemp);
if (sectionSingleB(secConfig, SECTION_FULL_HISTORY, strTemp))
FULL_HISTORY = boost::lexical_cast<bool>(strTemp);
if (sectionSingleB(secConfig, SECTION_LEDGER_HISTORY, strTemp))
{
boost::to_lower(strTemp);
if ((strTemp == "no") || (strTemp == "none") || (strTemp == "off") || (strTemp == "false"))
LEDGER_HISTORY = 0;
else if ((strTemp == "yes") || (strTemp == "full") || (strTemp == "on") || (strTemp == "-1"))
LEDGER_HISTORY = 1000000000u;
else
LEDGER_HISTORY = boost::lexical_cast<uint32>(strTemp);
}
if (sectionSingleB(secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp))
ACCOUNT_PROBE_MAX = boost::lexical_cast<int>(strTemp);

View File

@@ -108,7 +108,7 @@ public:
int FEE_CONTRACT_OPERATION; // fee for each contract operation
// Node storage configuration
bool FULL_HISTORY;
uint32 LEDGER_HISTORY;
// Client behavior
int ACCOUNT_PROBE_MAX; // How far to scan for accounts.

View File

@@ -12,7 +12,7 @@ SETUP_LOG();
DECLARE_INSTANCE(HashedObject);
HashedObjectStore::HashedObjectStore(int cacheSize, int cacheAge) :
mCache("HashedObjectStore", cacheSize, cacheAge), mWritePending(false), mWriteGeneration(0)
mCache("HashedObjectStore", cacheSize, cacheAge), mWriteGeneration(0), mWritePending(false)
{
mWriteSet.reserve(128);
}

View File

@@ -299,6 +299,29 @@ SerializedTransaction::pointer Ledger::getSTransaction(SHAMapItem::ref item, SHA
return SerializedTransaction::pointer();
}
SerializedTransaction::pointer Ledger::getSMTransaction(SHAMapItem::ref item, SHAMapTreeNode::TNType type,
TransactionMetaSet::pointer& txMeta)
{
SerializerIterator sit(item->peekSerializer());
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
{
txMeta.reset();
return boost::make_shared<SerializedTransaction>(boost::ref(sit));
}
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
{
Serializer sTxn(sit.getVL());
SerializerIterator tSit(sTxn);
txMeta = boost::make_shared<TransactionMetaSet>(item->getTag(), mLedgerSeq, sit.getVL());
return boost::make_shared<SerializedTransaction>(boost::ref(tSit));
}
txMeta.reset();
return SerializedTransaction::pointer();
}
bool Ledger::getTransaction(const uint256& txID, Transaction::pointer& txn, TransactionMetaSet::pointer& meta)
{
SHAMapTreeNode::TNType type;
@@ -346,7 +369,8 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;");
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransId = '%s';");
static boost::format transExists("SELECT Status FROM Transactions WHERE TransID = '%s';");
static boost::format updateTx("UPDATE Transactions SET LedgerSeq = %d, Status = '%c' WHERE TransID = '%s';");
static boost::format
updateTx("UPDATE Transactions SET LedgerSeq = %d, Status = '%c', TxnMeta = %s WHERE TransID = '%s';");
static boost::format addLedger("INSERT INTO Ledgers "
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,"
"AccountSetHash,TransSetHash) VALUES ('%s','%u','%s','%s','%u','%u','%d','%u','%s','%s');");
@@ -374,14 +398,20 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
for (SHAMapItem::pointer item = txSet.peekFirstItem(type); !!item;
item = txSet.peekNextItem(item->getTag(), type))
{
SerializedTransaction::pointer txn = getSTransaction(item, type);
assert(txn);
assert(type == SHAMapTreeNode::tnTRANSACTION_MD);
SerializerIterator sit(item->peekSerializer());
Serializer rawTxn(sit.getVL());
std::string escMeta(sqlEscape(sit.getVL()));
SerializerIterator txnIt(rawTxn);
SerializedTransaction txn(txnIt);
assert(txn.getTransactionID() == item->getTag());
// Make sure transaction is in AccountTransactions.
if (!SQL_EXISTS(db, boost::str(AcctTransExists % item->getTag().GetHex())))
{
// Transaction not in AccountTransactions
std::vector<RippleAddress> accts = txn->getAffectedAccounts();
std::vector<RippleAddress> accts = txn.getAffectedAccounts();
std::string sql = "INSERT INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES ";
bool first = true;
@@ -394,7 +424,7 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
sql += "('";
first = false;
}
sql += txn->getTransactionID().GetHex();
sql += txn.getTransactionID().GetHex();
sql += "','";
sql += it->humanAccountID();
sql += "',";
@@ -406,19 +436,20 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
db->executeSQL(sql); // may already be in there
}
if (SQL_EXISTS(db, boost::str(transExists % txn->getTransactionID().GetHex())))
if (SQL_EXISTS(db, boost::str(transExists % txn.getTransactionID().GetHex())))
{
// In Transactions, update LedgerSeq and Status.
// In Transactions, update LedgerSeq, metadata and Status.
db->executeSQL(boost::str(updateTx
% getLedgerSeq()
% TXN_SQL_VALIDATED
% txn->getTransactionID().GetHex()));
% escMeta
% txn.getTransactionID().GetHex()));
}
else
{
// Not in Transactions, insert the whole thing..
db->executeSQL(
txn->getSQLInsertHeader() + txn->getSQL(getLedgerSeq(), TXN_SQL_VALIDATED) + ";");
txn.getMetaSQLInsertHeader() + txn.getMetaSQL(getLedgerSeq(), escMeta) + ";");
}
}
db->executeSQL("COMMIT TRANSACTION;");

View File

@@ -161,7 +161,10 @@ public:
bool hasTransaction(const uint256& TransID) const { return mTransactionMap->hasItem(TransID); }
Transaction::pointer getTransaction(const uint256& transID) const;
bool getTransaction(const uint256& transID, Transaction::pointer& txn, TransactionMetaSet::pointer& txMeta);
static SerializedTransaction::pointer getSTransaction(SHAMapItem::ref, SHAMapTreeNode::TNType);
SerializedTransaction::pointer getSMTransaction(SHAMapItem::ref, SHAMapTreeNode::TNType,
TransactionMetaSet::pointer& txMeta);
// high-level functions
AccountState::pointer getAccountState(const RippleAddress& acctID);

View File

@@ -644,8 +644,16 @@ void LedgerConsensus::stateAccepted()
endConsensus();
}
extern volatile bool doShutdown;
void LedgerConsensus::timerEntry()
{
if (doShutdown)
{
cLog(lsFATAL) << "Shutdown requested";
theApp->stop();
}
if ((mState != lcsFINISHED) && (mState != lcsACCEPTED))
checkLCL();

View File

@@ -117,6 +117,12 @@ TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEng
return result;
}
bool LedgerMaster::haveLedgerRange(uint32 from, uint32 to)
{
uint32 prevMissing = mCompleteLedgers.prevMissing(to + 1);
return (prevMissing == RangeSet::RangeSetAbsent) || (prevMissing < from);
}
void LedgerMaster::acquireMissingLedger(const uint256& ledgerHash, uint32 ledgerSeq)
{
mMissingLedger = theApp->getMasterLedgerAcquire().findCreate(ledgerHash);
@@ -152,8 +158,19 @@ void LedgerMaster::missingAcquireComplete(LedgerAcquire::pointer acq)
}
}
void LedgerMaster::setFullLedger(Ledger::ref ledger)
static bool shouldAcquire(uint32 currentLedger, uint32 ledgerHistory, uint32 candidateLedger)
{
bool ret;
if (candidateLedger >= currentLedger)
ret = true;
else ret = (currentLedger - candidateLedger) <= ledgerHistory;
cLog(lsDEBUG) << "Missing ledger " << candidateLedger << (ret ? "will" : "will NOT") << " be acquired";
return ret;
}
void LedgerMaster::setFullLedger(Ledger::ref ledger)
{ // A new ledger has been accepted as part of the trusted chain
boost::recursive_mutex::scoped_lock ml(mLock);
mCompleteLedgers.setValue(ledger->getLedgerSeq());
@@ -161,7 +178,12 @@ void LedgerMaster::setFullLedger(Ledger::ref ledger)
if ((ledger->getLedgerSeq() != 0) && mCompleteLedgers.hasValue(ledger->getLedgerSeq() - 1))
{ // we think we have the previous ledger, double check
Ledger::pointer prevLedger = getLedgerBySeq(ledger->getLedgerSeq() - 1);
if (prevLedger && (prevLedger->getHash() != ledger->getParentHash()))
if (!prevLedger)
{
cLog(lsWARNING) << "Ledger " << ledger->getLedgerSeq() - 1 << " missing";
mCompleteLedgers.clearValue(ledger->getLedgerSeq() - 1);
}
else if (prevLedger->getHash() != ledger->getParentHash())
{
cLog(lsWARNING) << "Ledger " << ledger->getLedgerSeq() << " invalidates prior ledger";
mCompleteLedgers.clearValue(prevLedger->getLedgerSeq());
@@ -171,7 +193,7 @@ void LedgerMaster::setFullLedger(Ledger::ref ledger)
if (mMissingLedger && mMissingLedger->isComplete())
mMissingLedger.reset();
if (mMissingLedger || !theConfig.FULL_HISTORY)
if (mMissingLedger || !theConfig.LEDGER_HISTORY)
return;
if (Ledger::getPendingSaves() > 3)
@@ -183,13 +205,17 @@ void LedgerMaster::setFullLedger(Ledger::ref ledger)
// see if there's a ledger gap we need to fill
if (!mCompleteLedgers.hasValue(ledger->getLedgerSeq() - 1))
{
if (!shouldAcquire(mCurrentLedger->getLedgerSeq(), theConfig.LEDGER_HISTORY, ledger->getLedgerSeq() - 1))
return;
cLog(lsINFO) << "We need the ledger before the ledger we just accepted";
acquireMissingLedger(ledger->getParentHash(), ledger->getLedgerSeq() - 1);
}
else
{
uint32 prevMissing = mCompleteLedgers.prevMissing(ledger->getLedgerSeq());
if (prevMissing != RangeSet::RangeSetAbsent)
if (prevMissing == RangeSet::RangeSetAbsent)
return;
if (shouldAcquire(mCurrentLedger->getLedgerSeq(), theConfig.LEDGER_HISTORY, prevMissing))
{
cLog(lsINFO) << "Ledger " << prevMissing << " is missing";
assert(!mCompleteLedgers.hasValue(prevMissing));

View File

@@ -93,6 +93,8 @@ public:
void addHeldTransaction(const Transaction::pointer& trans);
bool haveLedgerRange(uint32 from, uint32 to);
void sweep(void) { mLedgerHistory.sweep(); }
};

View File

@@ -81,6 +81,11 @@ uint32 NetworkOPs::getCurrentLedgerID()
return mLedgerMaster->getCurrentLedger()->getLedgerSeq();
}
bool NetworkOPs::haveLedgerRange(uint32 from, uint32 to)
{
return mLedgerMaster->haveLedgerRange(from, to);
}
void NetworkOPs::submitTransaction(Job&, SerializedTransaction::pointer iTrans, stCallback callback)
{ // this is an asynchronous interface
Serializer s;
@@ -876,14 +881,15 @@ void NetworkOPs::setMode(OperatingMode om)
mMode = om;
}
std::vector< std::pair<uint32, uint256> >
NetworkOPs::getAffectedAccounts(const RippleAddress& account, uint32 minLedger, uint32 maxLedger)
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
NetworkOPs::getAccountTxs(const RippleAddress& account, uint32 minLedger, uint32 maxLedger)
{
std::vector< std::pair<uint32, uint256> > affectedAccounts;
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > ret;
std::string sql =
str(boost::format("SELECT LedgerSeq,TransID FROM AccountTransactions INDEXED BY AcctTxIndex "
" WHERE Account = '%s' AND LedgerSeq <= '%d' AND LedgerSeq >= '%d' ORDER BY LedgerSeq LIMIT 1000;")
str(boost::format("SELECT LedgerSeq,Status,RawTxn,TxnMeta FROM Transactions where TransID in (SELECT TransID from AccountTransactions "
" WHERE Account = '%s' AND LedgerSeq <= '%d' AND LedgerSeq >= '%d' LIMIT 1000) ORDER BY LedgerSeq;")
% account.humanAccountID() % maxLedger % minLedger);
{
@@ -892,11 +898,24 @@ std::vector< std::pair<uint32, uint256> >
SQL_FOREACH(db, sql)
{
affectedAccounts.push_back(std::make_pair<uint32, uint256>(db->getInt("LedgerSeq"), uint256(db->getStrBinary("TransID"))));
Transaction::pointer txn=Transaction::transactionFromSQL(db,false);
Serializer rawMeta;
int metaSize = 2048;
rawMeta.resize(metaSize);
metaSize = db->getBinary("RawTxn", &*rawMeta.begin(), rawMeta.getLength());
if (metaSize > rawMeta.getLength())
{
rawMeta.resize(metaSize);
db->getBinary("RawTxn", &*rawMeta.begin(), rawMeta.getLength());
}else rawMeta.resize(metaSize);
TransactionMetaSet::pointer meta= boost::make_shared<TransactionMetaSet>(txn->getID(), txn->getLedger(), rawMeta.getData());
ret.push_back(std::make_pair<Transaction::pointer, TransactionMetaSet::pointer>(txn,meta));
}
}
return affectedAccounts;
return ret;
}
std::vector<RippleAddress>
@@ -1076,6 +1095,7 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terRes
void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta)
{
Json::Value jvObj = transJson(stTxn, terResult, true, lpCurrent, "transaction");
if(meta) jvObj["meta"]=meta->getJson(0);
{
boost::recursive_mutex::scoped_lock sl(mMonitorLock);

View File

@@ -134,6 +134,9 @@ public:
uint256 getClosedLedgerHash() { return mLedgerMaster->getClosedLedger()->getHash(); }
// Do we have this inclusive range of ledgers in our database
bool haveLedgerRange(uint32 from, uint32 to);
SerializedValidation::ref getLastValidation() { return mLastValidation; }
void setLastValidation(SerializedValidation::ref v) { mLastValidation = v; }
@@ -230,8 +233,8 @@ public:
uint256 getConsensusLCL();
// client information retrieval functions
std::vector< std::pair<uint32, uint256> >
getAffectedAccounts(const RippleAddress& account, uint32 minLedger, uint32 maxLedger);
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
getAccountTxs(const RippleAddress& account, uint32 minLedger, uint32 maxLedger);
std::vector<RippleAddress> getLedgerAffectedAccounts(uint32 ledgerSeq);
std::vector<SerializedTransaction> getLedgerTransactions(uint32 ledgerSeq);

View File

@@ -1303,25 +1303,18 @@ Json::Value RPCHandler::doAccountTransactions(const Json::Value& params)
try
{
#endif
std::vector< std::pair<uint32, uint256> > txns = mNetOps->getAffectedAccounts(account, minLedger, maxLedger);
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > txns = mNetOps->getAccountTxs(account, minLedger, maxLedger);
Json::Value ret(Json::objectValue);
ret["account"] = account.humanAccountID();
Json::Value ledgers(Json::arrayValue);
// uint32 currentLedger = 0;
for (std::vector< std::pair<uint32, uint256> >::iterator it = txns.begin(), end = txns.end(); it != end; ++it)
for (std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >::iterator it = txns.begin(), end = txns.end(); it != end; ++it)
{
Transaction::pointer txn = theApp->getMasterTransaction().fetch(it->second, true);
if (!txn)
{
ret["transactions"].append(it->second.GetHex());
}
else
{
txn->setLedger(it->first);
ret["transactions"].append(txn->getJson(1));
}
Json::Value obj(Json::objectValue);
if(it->first) obj["tx"]=it->first->getJson(1);
if(it->second) obj["meta"]=it->second->getJson(0);
ret["transactions"].append(obj);
}
return ret;
#ifndef DEBUG

View File

@@ -183,11 +183,21 @@ std::string SerializedTransaction::getSQLValueHeader()
return "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn)";
}
std::string SerializedTransaction::getMetaSQLValueHeader()
{
return "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn, TxnMeta)";
}
std::string SerializedTransaction::getSQLInsertHeader()
{
return "INSERT INTO Transactions " + getSQLValueHeader() + " VALUES ";
}
std::string SerializedTransaction::getMetaSQLInsertHeader()
{
return "INSERT INTO Transactions " + getMetaSQLValueHeader() + " VALUES ";
}
std::string SerializedTransaction::getSQL(uint32 inLedger, char status) const
{
Serializer s;
@@ -195,16 +205,36 @@ std::string SerializedTransaction::getSQL(uint32 inLedger, char status) const
return getSQL(s, inLedger, status);
}
std::string SerializedTransaction::getMetaSQL(uint32 inLedger, const std::string& escapedMetaData) const
{
Serializer s;
add(s);
return getMetaSQL(s, inLedger, TXN_SQL_VALIDATED, escapedMetaData);
}
std::string SerializedTransaction::getSQL(Serializer rawTxn, uint32 inLedger, char status) const
{
static boost::format bfTrans("('%s', '%s', '%s', '%d', '%d', '%c', %s)");
std::string rTxn;
theApp->getTxnDB()->getDB()->escape(
reinterpret_cast<const unsigned char *>(rawTxn.getDataPtr()), rawTxn.getLength(), rTxn);
return str(boost::format("('%s', '%s', '%s', '%d', '%d', '%c', %s)")
return str(bfTrans
% getTransactionID().GetHex() % getTransactionType() % getSourceAccount().humanAccountID()
% getSequence() % inLedger % status % rTxn);
}
std::string SerializedTransaction::getMetaSQL(Serializer rawTxn, uint32 inLedger, char status,
const std::string& escapedMetaData) const
{
static boost::format bfTrans("('%s', '%s', '%s', '%d', '%d', '%c', %s, %s)");
std::string rTxn;
theApp->getTxnDB()->getDB()->escape(
reinterpret_cast<const unsigned char *>(rawTxn.getDataPtr()), rawTxn.getLength(), rTxn);
return str(bfTrans
% getTransactionID().GetHex() % getTransactionType() % getSourceAccount().humanAccountID()
% getSequence() % inLedger % status % rTxn % escapedMetaData);
}
BOOST_AUTO_TEST_SUITE(SerializedTransactionTS)

View File

@@ -77,6 +77,12 @@ public:
std::string getSQL(uint32 inLedger, char status) const;
std::string getSQL(Serializer rawTxn, uint32 inLedger, char status) const;
// SQL Functions with metadata
static std::string getMetaSQLValueHeader();
static std::string getMetaSQLInsertHeader();
std::string getMetaSQL(uint32 inLedger, const std::string& escapedMetaData) const;
std::string getMetaSQL(Serializer rawTxn, uint32 inLedger, char status, const std::string& escapedMetaData) const;
};
#endif

View File

@@ -246,6 +246,7 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
return tr;
}
Transaction::pointer Transaction::load(const uint256& id)
{
std::string sql = "SELECT LedgerSeq,Status,RawTxn FROM Transactions WHERE TransID='";

View File

@@ -158,6 +158,12 @@ inline static std::string sqlEscape(const std::string& strSrc)
return str(f % strHex(strSrc));
}
inline static std::string sqlEscape(const std::vector<unsigned char>& vecSrc)
{
static boost::format f("X'%s'");
return str(f % strHex(vecSrc));
}
template<class Iterator>
bool isZero(Iterator first, int iSize)
{