Reformatting using AStyle

This commit is contained in:
Vinnie Falco
2013-06-14 08:45:13 -07:00
parent 36bd8f7173
commit 521e812fc4
294 changed files with 54609 additions and 47598 deletions

View File

@@ -13,408 +13,432 @@ SETUP_LOG (SqliteDatabase)
using namespace std;
SqliteDatabase::SqliteDatabase(const char* host) : Database(host,"",""), mWalQ(NULL), walRunning(false)
SqliteDatabase::SqliteDatabase (const char* host) : Database (host, "", ""), mWalQ (NULL), walRunning (false)
{
mConnection = NULL;
mAuxConnection = NULL;
mCurrentStmt = NULL;
mConnection = NULL;
mAuxConnection = NULL;
mCurrentStmt = NULL;
}
void SqliteDatabase::connect()
void SqliteDatabase::connect ()
{
int rc = sqlite3_open(mHost.c_str(), &mConnection);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't open " << mHost << " " << rc;
sqlite3_close(mConnection);
assert((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
}
int rc = sqlite3_open (mHost.c_str (), &mConnection);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't open " << mHost << " " << rc;
sqlite3_close (mConnection);
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
}
}
sqlite3* SqliteDatabase::getAuxConnection()
sqlite3* SqliteDatabase::getAuxConnection ()
{
boost::mutex::scoped_lock sl(walMutex);
if (mAuxConnection == NULL)
{
int rc = sqlite3_open(mHost.c_str(), &mAuxConnection);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't aux open " << mHost << " " << rc;
assert((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
if (mAuxConnection != NULL)
{
sqlite3_close(mConnection);
mAuxConnection = NULL;
}
}
}
return mAuxConnection;
boost::mutex::scoped_lock sl (walMutex);
if (mAuxConnection == NULL)
{
int rc = sqlite3_open (mHost.c_str (), &mAuxConnection);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't aux open " << mHost << " " << rc;
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
if (mAuxConnection != NULL)
{
sqlite3_close (mConnection);
mAuxConnection = NULL;
}
}
}
return mAuxConnection;
}
void SqliteDatabase::disconnect()
void SqliteDatabase::disconnect ()
{
sqlite3_finalize(mCurrentStmt);
sqlite3_close(mConnection);
if (mAuxConnection != NULL)
sqlite3_close(mAuxConnection);
sqlite3_finalize (mCurrentStmt);
sqlite3_close (mConnection);
if (mAuxConnection != NULL)
sqlite3_close (mAuxConnection);
}
// returns true if the query went ok
bool SqliteDatabase::executeSQL(const char* sql, bool fail_ok)
bool SqliteDatabase::executeSQL (const char* sql, bool fail_ok)
{
#ifdef DEBUG_HANGING_LOCKS
assert(fail_ok || (mCurrentStmt == NULL));
assert (fail_ok || (mCurrentStmt == NULL));
#endif
sqlite3_finalize(mCurrentStmt);
sqlite3_finalize (mCurrentStmt);
int rc = sqlite3_prepare_v2(mConnection, sql, -1, &mCurrentStmt, NULL);
int rc = sqlite3_prepare_v2 (mConnection, sql, -1, &mCurrentStmt, NULL);
if (SQLITE_OK != rc)
{
if (!fail_ok)
{
if (SQLITE_OK != rc)
{
if (!fail_ok)
{
#ifdef DEBUG
WriteLog (lsWARNING, SqliteDatabase) << "Perror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg(mConnection);
WriteLog (lsWARNING, SqliteDatabase) << "Perror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg (mConnection);
#endif
}
endIterRows();
return false;
}
rc = sqlite3_step(mCurrentStmt);
if (rc == SQLITE_ROW)
{
mMoreRows = true;
}
else if (rc == SQLITE_DONE)
{
endIterRows();
mMoreRows = false;
}
else
{
if ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED))
{
WriteLog (lsFATAL, SqliteDatabase) << mHost << " returns error " << rc << ": " << sqlite3_errmsg(mConnection);
assert(false);
}
mMoreRows = false;
}
if (!fail_ok)
{
endIterRows ();
return false;
}
rc = sqlite3_step (mCurrentStmt);
if (rc == SQLITE_ROW)
{
mMoreRows = true;
}
else if (rc == SQLITE_DONE)
{
endIterRows ();
mMoreRows = false;
}
else
{
if ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED))
{
WriteLog (lsFATAL, SqliteDatabase) << mHost << " returns error " << rc << ": " << sqlite3_errmsg (mConnection);
assert (false);
}
mMoreRows = false;
if (!fail_ok)
{
#ifdef DEBUG
WriteLog (lsWARNING, SqliteDatabase) << "SQL Serror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg(mConnection);
WriteLog (lsWARNING, SqliteDatabase) << "SQL Serror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg (mConnection);
#endif
}
endIterRows();
return false;
}
}
return true;
endIterRows ();
return false;
}
return true;
}
// returns false if there are no results
bool SqliteDatabase::startIterRows(bool finalize)
bool SqliteDatabase::startIterRows (bool finalize)
{
mColNameTable.clear();
mColNameTable.resize(sqlite3_column_count(mCurrentStmt));
for(unsigned n=0; n<mColNameTable.size(); n++)
{
mColNameTable[n]=sqlite3_column_name(mCurrentStmt,n);
}
mColNameTable.clear ();
mColNameTable.resize (sqlite3_column_count (mCurrentStmt));
if (!mMoreRows && finalize)
endIterRows();
for (unsigned n = 0; n < mColNameTable.size (); n++)
{
mColNameTable[n] = sqlite3_column_name (mCurrentStmt, n);
}
return(mMoreRows);
if (!mMoreRows && finalize)
endIterRows ();
return (mMoreRows);
}
void SqliteDatabase::endIterRows()
void SqliteDatabase::endIterRows ()
{
sqlite3_finalize(mCurrentStmt);
mCurrentStmt=NULL;
sqlite3_finalize (mCurrentStmt);
mCurrentStmt = NULL;
}
// call this after you executeSQL
// will return false if there are no more rows
bool SqliteDatabase::getNextRow(bool finalize)
bool SqliteDatabase::getNextRow (bool finalize)
{
if (mMoreRows)
{
int rc=sqlite3_step(mCurrentStmt);
if (rc==SQLITE_ROW)
return(true);
assert((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
CondLog ((rc != SQLITE_DONE), lsWARNING, SqliteDatabase) << "Rerror: " << mHost << ": " << rc;
}
if (mMoreRows)
{
int rc = sqlite3_step (mCurrentStmt);
if (finalize)
endIterRows();
return false;
if (rc == SQLITE_ROW)
return (true);
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
CondLog ((rc != SQLITE_DONE), lsWARNING, SqliteDatabase) << "Rerror: " << mHost << ": " << rc;
}
if (finalize)
endIterRows ();
return false;
}
bool SqliteDatabase::getNull(int colIndex)
bool SqliteDatabase::getNull (int colIndex)
{
return(SQLITE_NULL == sqlite3_column_type(mCurrentStmt, colIndex));
return (SQLITE_NULL == sqlite3_column_type (mCurrentStmt, colIndex));
}
char* SqliteDatabase::getStr(int colIndex,std::string& retStr)
char* SqliteDatabase::getStr (int colIndex, std::string& retStr)
{
const char *text = reinterpret_cast<const char *>(sqlite3_column_text(mCurrentStmt, colIndex));
retStr = (text == NULL) ? "" : text;
return const_cast<char*>(retStr.c_str());
const char* text = reinterpret_cast<const char*> (sqlite3_column_text (mCurrentStmt, colIndex));
retStr = (text == NULL) ? "" : text;
return const_cast<char*> (retStr.c_str ());
}
int32 SqliteDatabase::getInt(int colIndex)
int32 SqliteDatabase::getInt (int colIndex)
{
return(sqlite3_column_int(mCurrentStmt, colIndex));
return (sqlite3_column_int (mCurrentStmt, colIndex));
}
float SqliteDatabase::getFloat(int colIndex)
float SqliteDatabase::getFloat (int colIndex)
{
return(static_cast <float> (sqlite3_column_double(mCurrentStmt, colIndex)));
return (static_cast <float> (sqlite3_column_double (mCurrentStmt, colIndex)));
}
bool SqliteDatabase::getBool(int colIndex)
bool SqliteDatabase::getBool (int colIndex)
{
return(sqlite3_column_int(mCurrentStmt, colIndex) ? true : false);
return (sqlite3_column_int (mCurrentStmt, colIndex) ? true : false);
}
int SqliteDatabase::getBinary(int colIndex,unsigned char* buf,int maxSize)
int SqliteDatabase::getBinary (int colIndex, unsigned char* buf, int maxSize)
{
const void* blob=sqlite3_column_blob(mCurrentStmt, colIndex);
int size=sqlite3_column_bytes(mCurrentStmt, colIndex);
if(size<maxSize) maxSize=size;
memcpy(buf,blob,maxSize);
return(size);
const void* blob = sqlite3_column_blob (mCurrentStmt, colIndex);
int size = sqlite3_column_bytes (mCurrentStmt, colIndex);
if (size < maxSize) maxSize = size;
memcpy (buf, blob, maxSize);
return (size);
}
Blob SqliteDatabase::getBinary(int colIndex)
Blob SqliteDatabase::getBinary (int colIndex)
{
const unsigned char* blob = reinterpret_cast<const unsigned char*>(sqlite3_column_blob(mCurrentStmt, colIndex));
size_t iSize = sqlite3_column_bytes(mCurrentStmt, colIndex);
Blob vucResult;
const unsigned char* blob = reinterpret_cast<const unsigned char*> (sqlite3_column_blob (mCurrentStmt, colIndex));
size_t iSize = sqlite3_column_bytes (mCurrentStmt, colIndex);
Blob vucResult;
vucResult.resize(iSize);
std::copy(blob, blob+iSize, vucResult.begin());
vucResult.resize (iSize);
std::copy (blob, blob + iSize, vucResult.begin ());
return vucResult;
return vucResult;
}
uint64 SqliteDatabase::getBigInt(int colIndex)
uint64 SqliteDatabase::getBigInt (int colIndex)
{
return(sqlite3_column_int64(mCurrentStmt, colIndex));
return (sqlite3_column_int64 (mCurrentStmt, colIndex));
}
int SqliteDatabase::getKBUsedAll()
int SqliteDatabase::getKBUsedAll ()
{
return static_cast<int>(sqlite3_memory_used() / 1024);
return static_cast<int> (sqlite3_memory_used () / 1024);
}
int SqliteDatabase::getKBUsedDB()
int SqliteDatabase::getKBUsedDB ()
{
int cur = 0, hiw = 0;
sqlite3_db_status(mConnection, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0);
return cur / 1024;
int cur = 0, hiw = 0;
sqlite3_db_status (mConnection, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0);
return cur / 1024;
}
static int SqliteWALHook(void *s, sqlite3* dbCon, const char *dbName, int walSize)
static int SqliteWALHook (void* s, sqlite3* dbCon, const char* dbName, int walSize)
{
(reinterpret_cast<SqliteDatabase*>(s))->doHook(dbName, walSize);
return SQLITE_OK;
(reinterpret_cast<SqliteDatabase*> (s))->doHook (dbName, walSize);
return SQLITE_OK;
}
bool SqliteDatabase::setupCheckpointing(JobQueue *q)
bool SqliteDatabase::setupCheckpointing (JobQueue* q)
{
mWalQ = q;
sqlite3_wal_hook(mConnection, SqliteWALHook, this);
return true;
mWalQ = q;
sqlite3_wal_hook (mConnection, SqliteWALHook, this);
return true;
}
void SqliteDatabase::doHook(const char *db, int pages)
void SqliteDatabase::doHook (const char* db, int pages)
{
if (pages < 1000)
return;
{
boost::mutex::scoped_lock sl(walMutex);
if (walRunning)
return;
walRunning = true;
}
if (mWalQ)
mWalQ->addJob(jtWAL, std::string("WAL:") + mHost, boost::bind(&SqliteDatabase::runWal, this));
else
boost::thread(boost::bind(&SqliteDatabase::runWal, this)).detach();
if (pages < 1000)
return;
{
boost::mutex::scoped_lock sl (walMutex);
if (walRunning)
return;
walRunning = true;
}
if (mWalQ)
mWalQ->addJob (jtWAL, std::string ("WAL:") + mHost, boost::bind (&SqliteDatabase::runWal, this));
else
boost::thread (boost::bind (&SqliteDatabase::runWal, this)).detach ();
}
void SqliteDatabase::runWal()
void SqliteDatabase::runWal ()
{
int log = 0, ckpt = 0;
int ret = sqlite3_wal_checkpoint_v2(mConnection, NULL, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt);
if (ret != SQLITE_OK)
{
WriteLog ((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING, SqliteDatabase) << "WAL("
<< sqlite3_db_filename(mConnection, "main") << "): error " << ret;
}
else
WriteLog (lsTRACE, SqliteDatabase) << "WAL(" << sqlite3_db_filename(mConnection, "main") <<
"): frames=" << log << ", written=" << ckpt;
int log = 0, ckpt = 0;
int ret = sqlite3_wal_checkpoint_v2 (mConnection, NULL, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt);
{
boost::mutex::scoped_lock sl(walMutex);
walRunning = false;
}
if (ret != SQLITE_OK)
{
WriteLog ((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING, SqliteDatabase) << "WAL("
<< sqlite3_db_filename (mConnection, "main") << "): error " << ret;
}
else
WriteLog (lsTRACE, SqliteDatabase) << "WAL(" << sqlite3_db_filename (mConnection, "main") <<
"): frames=" << log << ", written=" << ckpt;
{
boost::mutex::scoped_lock sl (walMutex);
walRunning = false;
}
}
SqliteStatement::SqliteStatement(SqliteDatabase* db, const char *sql, bool aux)
SqliteStatement::SqliteStatement (SqliteDatabase* db, const char* sql, bool aux)
{
assert(db);
assert (db);
sqlite3* conn = aux ? db->getAuxConnection() : db->peekConnection();
int j = sqlite3_prepare_v2(conn, sql, strlen(sql) + 1, &statement, NULL);
if (j != SQLITE_OK)
throw j;
sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection ();
int j = sqlite3_prepare_v2 (conn, sql, strlen (sql) + 1, &statement, NULL);
if (j != SQLITE_OK)
throw j;
}
SqliteStatement::SqliteStatement(SqliteDatabase* db, const std::string& sql, bool aux)
SqliteStatement::SqliteStatement (SqliteDatabase* db, const std::string& sql, bool aux)
{
assert(db);
assert (db);
sqlite3* conn = aux ? db->getAuxConnection() : db->peekConnection();
int j = sqlite3_prepare_v2(conn, sql.c_str(), sql.size() + 1, &statement, NULL);
if (j != SQLITE_OK)
throw j;
sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection ();
int j = sqlite3_prepare_v2 (conn, sql.c_str (), sql.size () + 1, &statement, NULL);
if (j != SQLITE_OK)
throw j;
}
SqliteStatement::~SqliteStatement()
SqliteStatement::~SqliteStatement ()
{
sqlite3_finalize(statement);
sqlite3_finalize (statement);
}
sqlite3_stmt* SqliteStatement::peekStatement()
sqlite3_stmt* SqliteStatement::peekStatement ()
{
return statement;
return statement;
}
int SqliteStatement::bind(int position, const void *data, int length)
int SqliteStatement::bind (int position, const void* data, int length)
{
return sqlite3_bind_blob(statement, position, data, length, SQLITE_TRANSIENT);
return sqlite3_bind_blob (statement, position, data, length, SQLITE_TRANSIENT);
}
int SqliteStatement::bindStatic(int position, const void *data, int length)
int SqliteStatement::bindStatic (int position, const void* data, int length)
{
return sqlite3_bind_blob(statement, position, data, length, SQLITE_STATIC);
return sqlite3_bind_blob (statement, position, data, length, SQLITE_STATIC);
}
int SqliteStatement::bindStatic(int position, Blob const& value)
int SqliteStatement::bindStatic (int position, Blob const& value)
{
return sqlite3_bind_blob(statement, position, &value.front(), value.size(), SQLITE_STATIC);
return sqlite3_bind_blob (statement, position, &value.front (), value.size (), SQLITE_STATIC);
}
int SqliteStatement::bind(int position, uint32 value)
int SqliteStatement::bind (int position, uint32 value)
{
return sqlite3_bind_int64(statement, position, static_cast<sqlite3_int64>(value));
return sqlite3_bind_int64 (statement, position, static_cast<sqlite3_int64> (value));
}
int SqliteStatement::bind(int position, const std::string& value)
int SqliteStatement::bind (int position, const std::string& value)
{
return sqlite3_bind_text(statement, position, value.data(), value.size(), SQLITE_TRANSIENT);
return sqlite3_bind_text (statement, position, value.data (), value.size (), SQLITE_TRANSIENT);
}
int SqliteStatement::bindStatic(int position, const std::string& value)
int SqliteStatement::bindStatic (int position, const std::string& value)
{
return sqlite3_bind_text(statement, position, value.data(), value.size(), SQLITE_STATIC);
return sqlite3_bind_text (statement, position, value.data (), value.size (), SQLITE_STATIC);
}
int SqliteStatement::bind(int position)
int SqliteStatement::bind (int position)
{
return sqlite3_bind_null(statement, position);
return sqlite3_bind_null (statement, position);
}
int SqliteStatement::size(int column)
int SqliteStatement::size (int column)
{
return sqlite3_column_bytes(statement, column);
return sqlite3_column_bytes (statement, column);
}
const void* SqliteStatement::peekBlob(int column)
const void* SqliteStatement::peekBlob (int column)
{
return sqlite3_column_blob(statement, column);
return sqlite3_column_blob (statement, column);
}
Blob SqliteStatement::getBlob(int column)
Blob SqliteStatement::getBlob (int column)
{
int size = sqlite3_column_bytes(statement, column);
Blob ret(size);
memcpy(&(ret.front()), sqlite3_column_blob(statement, column), size);
return ret;
int size = sqlite3_column_bytes (statement, column);
Blob ret (size);
memcpy (& (ret.front ()), sqlite3_column_blob (statement, column), size);
return ret;
}
std::string SqliteStatement::getString(int column)
std::string SqliteStatement::getString (int column)
{
return reinterpret_cast<const char *>(sqlite3_column_text(statement, column));
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
const char* SqliteStatement::peekString(int column)
const char* SqliteStatement::peekString (int column)
{
return reinterpret_cast<const char *>(sqlite3_column_text(statement, column));
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
uint32 SqliteStatement::getUInt32(int column)
uint32 SqliteStatement::getUInt32 (int column)
{
return static_cast<uint32>(sqlite3_column_int64(statement, column));
return static_cast<uint32> (sqlite3_column_int64 (statement, column));
}
int64 SqliteStatement::getInt64(int column)
int64 SqliteStatement::getInt64 (int column)
{
return sqlite3_column_int64(statement, column);
return sqlite3_column_int64 (statement, column);
}
int SqliteStatement::step()
int SqliteStatement::step ()
{
return sqlite3_step(statement);
return sqlite3_step (statement);
}
int SqliteStatement::reset()
int SqliteStatement::reset ()
{
return sqlite3_reset(statement);
return sqlite3_reset (statement);
}
bool SqliteStatement::isOk(int j)
bool SqliteStatement::isOk (int j)
{
return j == SQLITE_OK;
return j == SQLITE_OK;
}
bool SqliteStatement::isDone(int j)
bool SqliteStatement::isDone (int j)
{
return j == SQLITE_DONE;
return j == SQLITE_DONE;
}
bool SqliteStatement::isRow(int j)
bool SqliteStatement::isRow (int j)
{
return j == SQLITE_ROW;
return j == SQLITE_ROW;
}
bool SqliteStatement::isError(int j)
bool SqliteStatement::isError (int j)
{
switch (j)
{
case SQLITE_OK:
case SQLITE_ROW:
case SQLITE_DONE:
return true;
switch (j)
{
case SQLITE_OK:
case SQLITE_ROW:
case SQLITE_DONE:
return true;
default:
return false;
}
default:
return false;
}
}
std::string SqliteStatement::getError(int j)
std::string SqliteStatement::getError (int j)
{
return sqlite3_errstr(j);
return sqlite3_errstr (j);
}
// vim:ts=4

View File

@@ -7,104 +7,110 @@ struct sqlite3_stmt;
class SqliteDatabase : public Database
{
sqlite3* mConnection;
sqlite3* mAuxConnection;
sqlite3_stmt* mCurrentStmt;
bool mMoreRows;
sqlite3* mConnection;
sqlite3* mAuxConnection;
sqlite3_stmt* mCurrentStmt;
bool mMoreRows;
boost::mutex walMutex;
JobQueue* mWalQ;
bool walRunning;
boost::mutex walMutex;
JobQueue* mWalQ;
bool walRunning;
public:
SqliteDatabase(const char* host);
SqliteDatabase (const char* host);
void connect();
void disconnect();
void connect ();
void disconnect ();
// returns true if the query went ok
bool executeSQL(const char* sql, bool fail_okay);
// returns true if the query went ok
bool executeSQL (const char* sql, bool fail_okay);
// tells you how many rows were changed by an update or insert
int getNumRowsAffected();
// tells you how many rows were changed by an update or insert
int getNumRowsAffected ();
// returns false if there are no results
bool startIterRows(bool finalize);
void endIterRows();
// returns false if there are no results
bool startIterRows (bool finalize);
void endIterRows ();
// call this after you executeSQL
// will return false if there are no more rows
bool getNextRow(bool finalize);
// call this after you executeSQL
// will return false if there are no more rows
bool getNextRow (bool finalize);
bool getNull(int colIndex);
char* getStr(int colIndex,std::string& retStr);
int32 getInt(int colIndex);
float getFloat(int colIndex);
bool getBool(int colIndex);
// returns amount stored in buf
int getBinary(int colIndex,unsigned char* buf,int maxSize);
Blob getBinary(int colIndex);
uint64 getBigInt(int colIndex);
bool getNull (int colIndex);
char* getStr (int colIndex, std::string& retStr);
int32 getInt (int colIndex);
float getFloat (int colIndex);
bool getBool (int colIndex);
// returns amount stored in buf
int getBinary (int colIndex, unsigned char* buf, int maxSize);
Blob getBinary (int colIndex);
uint64 getBigInt (int colIndex);
sqlite3* peekConnection() { return mConnection; }
sqlite3* getAuxConnection();
virtual bool setupCheckpointing(JobQueue*);
virtual SqliteDatabase* getSqliteDB() { return this; }
sqlite3* peekConnection ()
{
return mConnection;
}
sqlite3* getAuxConnection ();
virtual bool setupCheckpointing (JobQueue*);
virtual SqliteDatabase* getSqliteDB ()
{
return this;
}
void runWal();
void doHook(const char *db, int walSize);
void runWal ();
void doHook (const char* db, int walSize);
int getKBUsedDB();
int getKBUsedAll();
int getKBUsedDB ();
int getKBUsedAll ();
};
class SqliteStatement
{
private:
SqliteStatement(const SqliteStatement&); // no implementation
SqliteStatement& operator=(const SqliteStatement&); // no implementation
SqliteStatement (const SqliteStatement&); // no implementation
SqliteStatement& operator= (const SqliteStatement&); // no implementation
protected:
sqlite3_stmt* statement;
sqlite3_stmt* statement;
public:
SqliteStatement(SqliteDatabase* db, const char *statement, bool aux = false);
SqliteStatement(SqliteDatabase* db, const std::string& statement, bool aux = false);
~SqliteStatement();
SqliteStatement (SqliteDatabase* db, const char* statement, bool aux = false);
SqliteStatement (SqliteDatabase* db, const std::string& statement, bool aux = false);
~SqliteStatement ();
sqlite3_stmt* peekStatement();
sqlite3_stmt* peekStatement ();
// positions start at 1
int bind(int position, const void *data, int length);
int bindStatic(int position, const void *data, int length);
int bindStatic(int position, Blob const& value);
// positions start at 1
int bind (int position, const void* data, int length);
int bindStatic (int position, const void* data, int length);
int bindStatic (int position, Blob const& value);
int bind(int position, const std::string& value);
int bindStatic(int position, const std::string& value);
int bind (int position, const std::string& value);
int bindStatic (int position, const std::string& value);
int bind(int position, uint32 value);
int bind(int position);
int bind (int position, uint32 value);
int bind (int position);
// columns start at 0
int size(int column);
// columns start at 0
int size (int column);
const void* peekBlob(int column);
Blob getBlob(int column);
const void* peekBlob (int column);
Blob getBlob (int column);
std::string getString(int column);
const char* peekString(int column);
uint32 getUInt32(int column);
int64 getInt64(int column);
std::string getString (int column);
const char* peekString (int column);
uint32 getUInt32 (int column);
int64 getInt64 (int column);
int step();
int reset();
int step ();
int reset ();
// translate return values of step and reset
bool isOk(int);
bool isDone(int);
bool isRow(int);
bool isError(int);
std::string getError(int);
// translate return values of step and reset
bool isOk (int);
bool isDone (int);
bool isRow (int);
bool isError (int);
std::string getError (int);
};
#endif

View File

@@ -3,185 +3,190 @@
#include <string.h>
Database::Database(const char* host,const char* user,const char* pass) : mNumCol(0)
Database::Database (const char* host, const char* user, const char* pass) : mNumCol (0)
{
mDBPass = pass;
mHost = host;
mUser = user;
mDBPass = pass;
mHost = host;
mUser = user;
}
Database::~Database()
Database::~Database ()
{
}
bool Database::getNull(const char* colName)
bool Database::getNull (const char* colName)
{
int index;
int index;
if (getColNumber(colName,&index))
{
return getNull(index);
}
if (getColNumber (colName, &index))
{
return getNull (index);
}
return true;
return true;
}
char* Database::getStr(const char* colName,std::string& retStr)
char* Database::getStr (const char* colName, std::string& retStr)
{
int index;
int index;
if (getColNumber(colName,&index))
{
return getStr(index,retStr);
}
if (getColNumber (colName, &index))
{
return getStr (index, retStr);
}
return NULL;
return NULL;
}
int32 Database::getInt(const char* colName)
int32 Database::getInt (const char* colName)
{
int index;
int index;
if (getColNumber(colName,&index))
{
return getInt(index);
}
if (getColNumber (colName, &index))
{
return getInt (index);
}
return 0;
return 0;
}
float Database::getFloat(const char* colName)
float Database::getFloat (const char* colName)
{
int index;
int index;
if (getColNumber(colName,&index))
{
return getFloat(index);
}
if (getColNumber (colName, &index))
{
return getFloat (index);
}
return 0;
return 0;
}
bool Database::getBool(const char* colName)
bool Database::getBool (const char* colName)
{
int index;
int index;
if (getColNumber(colName,&index))
{
return getBool(index);
}
if (getColNumber (colName, &index))
{
return getBool (index);
}
return 0;
return 0;
}
int Database::getBinary(const char* colName,unsigned char* buf,int maxSize)
int Database::getBinary (const char* colName, unsigned char* buf, int maxSize)
{
int index;
int index;
if (getColNumber(colName,&index))
{
return(getBinary(index,buf,maxSize));
}
if (getColNumber (colName, &index))
{
return (getBinary (index, buf, maxSize));
}
return(0);
return (0);
}
Blob Database::getBinary(const std::string& strColName)
Blob Database::getBinary (const std::string& strColName)
{
int index;
int index;
if (getColNumber(strColName.c_str(), &index))
{
return getBinary(index);
}
if (getColNumber (strColName.c_str (), &index))
{
return getBinary (index);
}
return Blob ();
return Blob ();
}
std::string Database::getStrBinary(const std::string& strColName)
std::string Database::getStrBinary (const std::string& strColName)
{
// YYY Could eliminate a copy if getStrBinary was a template.
return strCopy(getBinary(strColName.c_str()));
// YYY Could eliminate a copy if getStrBinary was a template.
return strCopy (getBinary (strColName.c_str ()));
}
uint64 Database::getBigInt(const char* colName)
uint64 Database::getBigInt (const char* colName)
{
int index;
int index;
if (getColNumber(colName,&index))
{
return getBigInt(index);
}
if (getColNumber (colName, &index))
{
return getBigInt (index);
}
return 0;
return 0;
}
// returns false if can't find col
bool Database::getColNumber(const char* colName,int* retIndex)
bool Database::getColNumber (const char* colName, int* retIndex)
{
for (unsigned int n=0; n<mColNameTable.size(); n++)
{
if (strcmp(colName,mColNameTable[n].c_str())==0)
{
*retIndex=n;
return(true);
}
}
for (unsigned int n = 0; n < mColNameTable.size (); n++)
{
if (strcmp (colName, mColNameTable[n].c_str ()) == 0)
{
*retIndex = n;
return (true);
}
}
return false;
return false;
}
#if 0
int Database::getSingleDBValueInt(const char* sql)
int Database::getSingleDBValueInt (const char* sql)
{
int ret;
if ( executeSQL(sql) && startIterRows()
{
ret=getInt(0);
endIterRows();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret=0;
}
return(ret);
int ret;
if ( executeSQL (sql) && startIterRows ()
{
ret = getInt (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
float Database::getSingleDBValueFloat(const char* sql)
float Database::getSingleDBValueFloat (const char* sql)
{
float ret;
if (executeSQL(sql) && startIterRows() && getNextRow())
{
ret=getFloat(0);
endIterRows();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret=0;
}
return(ret);
float ret;
if (executeSQL (sql) && startIterRows () && getNextRow ())
{
ret = getFloat (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
char* Database::getSingleDBValueStr(const char* sql,std::string& retStr)
char* Database::getSingleDBValueStr (const char* sql, std::string& retStr)
{
char* ret;
if (executeSQL(sql) && startIterRows())
{
ret=getStr(0,retStr);
endIterRows();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret=0;
}
return(ret);
char* ret;
if (executeSQL (sql) && startIterRows ())
{
ret = getStr (0, retStr);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif

View File

@@ -1,15 +1,15 @@
#ifndef __DATABASE__
#define __DATABASE__
#define SQL_FOREACH(_db, _strQuery) \
if ((_db)->executeSQL(_strQuery)) \
for (bool _bMore = (_db)->startIterRows(); _bMore; _bMore = (_db)->getNextRow())
#define SQL_FOREACH(_db, _strQuery) \
if ((_db)->executeSQL(_strQuery)) \
for (bool _bMore = (_db)->startIterRows(); _bMore; _bMore = (_db)->getNextRow())
#define SQL_EXISTS(_db, _strQuery) \
((_db)->executeSQL(_strQuery) && (_db)->startIterRows())
/*
this maintains the connection to the database
this maintains the connection to the database
*/
class SqliteDatabase;
@@ -18,70 +18,86 @@ class JobQueue;
class Database
{
protected:
int mNumCol;
std::string mUser;
std::string mHost;
std::string mDBPass;
std::vector<std::string> mColNameTable;
int mNumCol;
std::string mUser;
std::string mHost;
std::string mDBPass;
std::vector<std::string> mColNameTable;
bool getColNumber(const char* colName, int* retIndex);
bool getColNumber (const char* colName, int* retIndex);
public:
Database(const char* host,const char* user,const char* pass);
static Database* newMysqlDatabase(const char* host,const char* user,const char* pass);
virtual ~Database();
Database (const char* host, const char* user, const char* pass);
static Database* newMysqlDatabase (const char* host, const char* user, const char* pass);
virtual ~Database ();
virtual void connect()=0;
virtual void disconnect()=0;
virtual void connect () = 0;
virtual void disconnect () = 0;
std::string& getPass(){ return(mDBPass); }
std::string& getPass ()
{
return (mDBPass);
}
// returns true if the query went ok
virtual bool executeSQL(const char* sql, bool fail_okay=false)=0;
// returns true if the query went ok
virtual bool executeSQL (const char* sql, bool fail_okay = false) = 0;
bool executeSQL(std::string strSql, bool fail_okay=false) {
return executeSQL(strSql.c_str(), fail_okay);
}
bool executeSQL (std::string strSql, bool fail_okay = false)
{
return executeSQL (strSql.c_str (), fail_okay);
}
// returns false if there are no results
virtual bool startIterRows(bool finalize = true)=0;
virtual void endIterRows()=0;
// returns false if there are no results
virtual bool startIterRows (bool finalize = true) = 0;
virtual void endIterRows () = 0;
// call this after you executeSQL
// will return false if there are no more rows
virtual bool getNextRow(bool finalize = true)=0;
// call this after you executeSQL
// will return false if there are no more rows
virtual bool getNextRow (bool finalize = true) = 0;
// get Data from the current row
bool getNull(const char* colName);
char* getStr(const char* colName,std::string& retStr);
std::string getStrBinary(const std::string& strColName);
int32 getInt(const char* colName);
float getFloat(const char* colName);
bool getBool(const char* colName);
// get Data from the current row
bool getNull (const char* colName);
char* getStr (const char* colName, std::string& retStr);
std::string getStrBinary (const std::string& strColName);
int32 getInt (const char* colName);
float getFloat (const char* colName);
bool getBool (const char* colName);
// returns amount stored in buf
int getBinary(const char* colName, unsigned char* buf, int maxSize);
Blob getBinary(const std::string& strColName);
// returns amount stored in buf
int getBinary (const char* colName, unsigned char* buf, int maxSize);
Blob getBinary (const std::string& strColName);
uint64 getBigInt(const char* colName);
uint64 getBigInt (const char* colName);
virtual bool getNull(int colIndex)=0;
virtual char* getStr(int colIndex,std::string& retStr)=0;
virtual int32 getInt(int colIndex)=0;
virtual float getFloat(int colIndex)=0;
virtual bool getBool(int colIndex)=0;
virtual int getBinary(int colIndex,unsigned char* buf,int maxSize)=0;
virtual uint64 getBigInt(int colIndex)=0;
virtual Blob getBinary(int colIndex)=0;
virtual bool getNull (int colIndex) = 0;
virtual char* getStr (int colIndex, std::string& retStr) = 0;
virtual int32 getInt (int colIndex) = 0;
virtual float getFloat (int colIndex) = 0;
virtual bool getBool (int colIndex) = 0;
virtual int getBinary (int colIndex, unsigned char* buf, int maxSize) = 0;
virtual uint64 getBigInt (int colIndex) = 0;
virtual Blob getBinary (int colIndex) = 0;
// int getSingleDBValueInt(const char* sql);
// float getSingleDBValueFloat(const char* sql);
// char* getSingleDBValueStr(const char* sql, std::string& retStr);
// int getSingleDBValueInt(const char* sql);
// float getSingleDBValueFloat(const char* sql);
// char* getSingleDBValueStr(const char* sql, std::string& retStr);
virtual bool setupCheckpointing(JobQueue*) { return false; }
virtual SqliteDatabase* getSqliteDB() { return NULL; }
virtual int getKBUsedAll() { return -1; }
virtual int getKBUsedDB() { return -1; }
virtual bool setupCheckpointing (JobQueue*)
{
return false;
}
virtual SqliteDatabase* getSqliteDB ()
{
return NULL;
}
virtual int getKBUsedAll ()
{
return -1;
}
virtual int getKBUsedDB ()
{
return -1;
}
};
#endif

View File

@@ -1,231 +1,231 @@
SETUP_LOG (AccountSetTransactor)
TER AccountSetTransactor::doApply()
TER AccountSetTransactor::doApply ()
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet>";
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet>";
const uint32 uTxFlags = mTxn.getFlags();
const uint32 uTxFlags = mTxn.getFlags ();
const uint32 uFlagsIn = mTxnAccount->getFieldU32(sfFlags);
uint32 uFlagsOut = uFlagsIn;
const uint32 uFlagsIn = mTxnAccount->getFieldU32 (sfFlags);
uint32 uFlagsOut = uFlagsIn;
if (uTxFlags & tfAccountSetMask)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Invalid flags set.";
if (uTxFlags & tfAccountSetMask)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
return temINVALID_FLAG;
}
//
// RequireAuth
//
//
// RequireAuth
//
if ((tfRequireAuth|tfOptionalAuth) == (uTxFlags & (tfRequireAuth|tfOptionalAuth)))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Contradictory flags set.";
if ((tfRequireAuth | tfOptionalAuth) == (uTxFlags & (tfRequireAuth | tfOptionalAuth)))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Contradictory flags set.";
return temINVALID_FLAG;
}
return temINVALID_FLAG;
}
if ((uTxFlags & tfRequireAuth) && !isSetBit(uFlagsIn, lsfRequireAuth))
{
if (mTxnAccount->getFieldU32(sfOwnerCount))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Retry: OwnerCount not zero.";
if ((uTxFlags & tfRequireAuth) && !isSetBit (uFlagsIn, lsfRequireAuth))
{
if (mTxnAccount->getFieldU32 (sfOwnerCount))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Retry: OwnerCount not zero.";
return terOWNERS;
}
return terOWNERS;
}
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Set RequireAuth.";
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Set RequireAuth.";
uFlagsOut |= lsfRequireAuth;
}
uFlagsOut |= lsfRequireAuth;
}
if ((uTxFlags & tfOptionalAuth) && isSetBit(uFlagsIn, lsfRequireAuth))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Clear RequireAuth.";
if ((uTxFlags & tfOptionalAuth) && isSetBit (uFlagsIn, lsfRequireAuth))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Clear RequireAuth.";
uFlagsOut &= ~lsfRequireAuth;
}
uFlagsOut &= ~lsfRequireAuth;
}
//
// RequireDestTag
//
//
// RequireDestTag
//
if ((tfRequireDestTag|tfOptionalDestTag) == (uTxFlags & (tfRequireDestTag|tfOptionalDestTag)))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Contradictory flags set.";
if ((tfRequireDestTag | tfOptionalDestTag) == (uTxFlags & (tfRequireDestTag | tfOptionalDestTag)))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Contradictory flags set.";
return temINVALID_FLAG;
}
return temINVALID_FLAG;
}
if ((uTxFlags & tfRequireDestTag) && !isSetBit(uFlagsIn, lsfRequireDestTag))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Set lsfRequireDestTag.";
if ((uTxFlags & tfRequireDestTag) && !isSetBit (uFlagsIn, lsfRequireDestTag))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Set lsfRequireDestTag.";
uFlagsOut |= lsfRequireDestTag;
}
uFlagsOut |= lsfRequireDestTag;
}
if ((uTxFlags & tfOptionalDestTag) && isSetBit(uFlagsIn, lsfRequireDestTag))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Clear lsfRequireDestTag.";
if ((uTxFlags & tfOptionalDestTag) && isSetBit (uFlagsIn, lsfRequireDestTag))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Clear lsfRequireDestTag.";
uFlagsOut &= ~lsfRequireDestTag;
}
uFlagsOut &= ~lsfRequireDestTag;
}
//
// DisallowXRP
//
//
// DisallowXRP
//
if ((tfDisallowXRP|tfAllowXRP) == (uTxFlags & (tfDisallowXRP|tfAllowXRP)))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Contradictory flags set.";
if ((tfDisallowXRP | tfAllowXRP) == (uTxFlags & (tfDisallowXRP | tfAllowXRP)))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Contradictory flags set.";
return temINVALID_FLAG;
}
return temINVALID_FLAG;
}
if ((uTxFlags & tfDisallowXRP) && !isSetBit(uFlagsIn, lsfDisallowXRP))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Set lsfDisallowXRP.";
if ((uTxFlags & tfDisallowXRP) && !isSetBit (uFlagsIn, lsfDisallowXRP))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Set lsfDisallowXRP.";
uFlagsOut |= lsfDisallowXRP;
}
uFlagsOut |= lsfDisallowXRP;
}
if ((uTxFlags & tfAllowXRP) && isSetBit(uFlagsIn, lsfDisallowXRP))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Clear lsfDisallowXRP.";
if ((uTxFlags & tfAllowXRP) && isSetBit (uFlagsIn, lsfDisallowXRP))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Clear lsfDisallowXRP.";
uFlagsOut &= ~lsfDisallowXRP;
}
uFlagsOut &= ~lsfDisallowXRP;
}
//
// EmailHash
//
//
// EmailHash
//
if (mTxn.isFieldPresent(sfEmailHash))
{
uint128 uHash = mTxn.getFieldH128(sfEmailHash);
if (mTxn.isFieldPresent (sfEmailHash))
{
uint128 uHash = mTxn.getFieldH128 (sfEmailHash);
if (!uHash)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset email hash";
if (!uHash)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset email hash";
mTxnAccount->makeFieldAbsent(sfEmailHash);
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set email hash";
mTxnAccount->makeFieldAbsent (sfEmailHash);
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set email hash";
mTxnAccount->setFieldH128(sfEmailHash, uHash);
}
}
mTxnAccount->setFieldH128 (sfEmailHash, uHash);
}
}
//
// WalletLocator
//
//
// WalletLocator
//
if (mTxn.isFieldPresent(sfWalletLocator))
{
uint256 uHash = mTxn.getFieldH256(sfWalletLocator);
if (mTxn.isFieldPresent (sfWalletLocator))
{
uint256 uHash = mTxn.getFieldH256 (sfWalletLocator);
if (!uHash)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset wallet locator";
if (!uHash)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset wallet locator";
mTxnAccount->makeFieldAbsent(sfEmailHash);
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set wallet locator";
mTxnAccount->makeFieldAbsent (sfEmailHash);
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set wallet locator";
mTxnAccount->setFieldH256(sfWalletLocator, uHash);
}
}
mTxnAccount->setFieldH256 (sfWalletLocator, uHash);
}
}
//
// MessageKey
//
//
// MessageKey
//
if (mTxn.isFieldPresent(sfMessageKey))
{
Blob vucPublic = mTxn.getFieldVL(sfMessageKey);
if (mTxn.isFieldPresent (sfMessageKey))
{
Blob vucPublic = mTxn.getFieldVL (sfMessageKey);
if (vucPublic.size() > PUBLIC_BYTES_MAX)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: message key too long";
if (vucPublic.size () > PUBLIC_BYTES_MAX)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: message key too long";
return telBAD_PUBLIC_KEY;
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set message key";
return telBAD_PUBLIC_KEY;
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set message key";
mTxnAccount->setFieldVL(sfMessageKey, vucPublic);
}
}
mTxnAccount->setFieldVL (sfMessageKey, vucPublic);
}
}
//
// Domain
//
//
// Domain
//
if (mTxn.isFieldPresent(sfDomain))
{
Blob vucDomain = mTxn.getFieldVL(sfDomain);
if (mTxn.isFieldPresent (sfDomain))
{
Blob vucDomain = mTxn.getFieldVL (sfDomain);
if (vucDomain.empty())
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset domain";
if (vucDomain.empty ())
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset domain";
mTxnAccount->makeFieldAbsent(sfDomain);
}
else if (vucDomain.size() > DOMAIN_BYTES_MAX)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: domain too long";
mTxnAccount->makeFieldAbsent (sfDomain);
}
else if (vucDomain.size () > DOMAIN_BYTES_MAX)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: domain too long";
return telBAD_DOMAIN;
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set domain";
return telBAD_DOMAIN;
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set domain";
mTxnAccount->setFieldVL(sfDomain, vucDomain);
}
}
mTxnAccount->setFieldVL (sfDomain, vucDomain);
}
}
//
// TransferRate
//
//
// TransferRate
//
if (mTxn.isFieldPresent(sfTransferRate))
{
uint32 uRate = mTxn.getFieldU32(sfTransferRate);
if (mTxn.isFieldPresent (sfTransferRate))
{
uint32 uRate = mTxn.getFieldU32 (sfTransferRate);
if (!uRate || uRate == QUALITY_ONE)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset transfer rate";
if (!uRate || uRate == QUALITY_ONE)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: unset transfer rate";
mTxnAccount->makeFieldAbsent(sfTransferRate);
}
else if (uRate > QUALITY_ONE)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set transfer rate";
mTxnAccount->makeFieldAbsent (sfTransferRate);
}
else if (uRate > QUALITY_ONE)
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set transfer rate";
mTxnAccount->setFieldU32(sfTransferRate, uRate);
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: bad transfer rate";
mTxnAccount->setFieldU32 (sfTransferRate, uRate);
}
else
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: bad transfer rate";
return temBAD_TRANSFER_RATE;
}
}
return temBAD_TRANSFER_RATE;
}
}
if (uFlagsIn != uFlagsOut)
mTxnAccount->setFieldU32(sfFlags, uFlagsOut);
if (uFlagsIn != uFlagsOut)
mTxnAccount->setFieldU32 (sfFlags, uFlagsOut);
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet<";
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet<";
return tesSUCCESS;
return tesSUCCESS;
}
// vim:ts=4

View File

@@ -4,9 +4,9 @@
class AccountSetTransactor : public Transactor
{
public:
AccountSetTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {}
AccountSetTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : Transactor (txn, params, engine) {}
TER doApply();
TER doApply ();
};
#endif

View File

@@ -25,211 +25,237 @@ namespace bassl = basio::ssl;
class AutoSocket
{
public:
typedef bassl::stream<basio::ip::tcp::socket> ssl_socket;
typedef boost::shared_ptr<ssl_socket> socket_ptr;
typedef ssl_socket::next_layer_type plain_socket;
typedef ssl_socket::lowest_layer_type lowest_layer_type;
typedef ssl_socket::handshake_type handshake_type;
typedef boost::system::error_code error_code;
typedef boost::function<void(error_code)> callback;
typedef bassl::stream<basio::ip::tcp::socket> ssl_socket;
typedef boost::shared_ptr<ssl_socket> socket_ptr;
typedef ssl_socket::next_layer_type plain_socket;
typedef ssl_socket::lowest_layer_type lowest_layer_type;
typedef ssl_socket::handshake_type handshake_type;
typedef boost::system::error_code error_code;
typedef boost::function<void (error_code)> callback;
public:
AutoSocket(basio::io_service& s, bassl::context& c) : mSecure(false), mBuffer(4)
{
mSocket = boost::make_shared<ssl_socket>(boost::ref(s), boost::ref(c));
}
AutoSocket (basio::io_service& s, bassl::context& c) : mSecure (false), mBuffer (4)
{
mSocket = boost::make_shared<ssl_socket> (boost::ref (s), boost::ref (c));
}
AutoSocket(basio::io_service& s, bassl::context& c, bool secureOnly, bool plainOnly)
: mSecure(secureOnly), mBuffer((plainOnly || secureOnly) ? 0 : 4)
{
mSocket = boost::make_shared<ssl_socket>(boost::ref(s), boost::ref(c));
}
AutoSocket (basio::io_service& s, bassl::context& c, bool secureOnly, bool plainOnly)
: mSecure (secureOnly), mBuffer ((plainOnly || secureOnly) ? 0 : 4)
{
mSocket = boost::make_shared<ssl_socket> (boost::ref (s), boost::ref (c));
}
bool isSecure() { return mSecure; }
ssl_socket& SSLSocket() { return *mSocket; }
plain_socket& PlainSocket() { return mSocket->next_layer(); }
void setSSLOnly() { mSecure = true;}
void setPlainOnly() { mBuffer.clear(); }
bool isSecure ()
{
return mSecure;
}
ssl_socket& SSLSocket ()
{
return *mSocket;
}
plain_socket& PlainSocket ()
{
return mSocket->next_layer ();
}
void setSSLOnly ()
{
mSecure = true;
}
void setPlainOnly ()
{
mBuffer.clear ();
}
lowest_layer_type& lowest_layer() { return mSocket->lowest_layer(); }
lowest_layer_type& lowest_layer ()
{
return mSocket->lowest_layer ();
}
void swap(AutoSocket& s)
{
mBuffer.swap(s.mBuffer);
mSocket.swap(s.mSocket);
std::swap(mSecure, s.mSecure);
}
void swap (AutoSocket& s)
{
mBuffer.swap (s.mBuffer);
mSocket.swap (s.mSocket);
std::swap (mSecure, s.mSecure);
}
static bool rfc2818_verify(const std::string& domain, bool preverified, boost::asio::ssl::verify_context& ctx)
{
if (boost::asio::ssl::rfc2818_verification(domain)(preverified, ctx))
return true;
Log(lsWARNING, AutoSocketPartition) << "Outbound SSL connection to " <<
domain << " fails certificate verification";
return false;
}
static bool rfc2818_verify (const std::string& domain, bool preverified, boost::asio::ssl::verify_context& ctx)
{
if (boost::asio::ssl::rfc2818_verification (domain) (preverified, ctx))
return true;
boost::system::error_code verify(const std::string& strDomain)
{
boost::system::error_code ec;
Log (lsWARNING, AutoSocketPartition) << "Outbound SSL connection to " <<
domain << " fails certificate verification";
return false;
}
mSocket->set_verify_mode(boost::asio::ssl::verify_peer);
boost::system::error_code verify (const std::string& strDomain)
{
boost::system::error_code ec;
// XXX Verify semantics of RFC 2818 are what we want.
mSocket->set_verify_callback(boost::bind(&rfc2818_verify, strDomain, _1, _2), ec);
mSocket->set_verify_mode (boost::asio::ssl::verify_peer);
return ec;
}
// XXX Verify semantics of RFC 2818 are what we want.
mSocket->set_verify_callback (boost::bind (&rfc2818_verify, strDomain, _1, _2), ec);
void async_handshake(handshake_type type, callback cbFunc)
{
if ((type == ssl_socket::client) || (mSecure))
{ // must be ssl
mSecure = true;
mSocket->async_handshake(type, cbFunc);
}
else if (mBuffer.empty())
{ // must be plain
mSecure = false;
mSocket->get_io_service().post(boost::bind(cbFunc, error_code()));
}
else
{ // autodetect
mSocket->next_layer().async_receive(basio::buffer(mBuffer), basio::socket_base::message_peek,
boost::bind(&AutoSocket::handle_autodetect, this, cbFunc,
basio::placeholders::error, basio::placeholders::bytes_transferred));
}
}
return ec;
}
template <typename ShutdownHandler> void async_shutdown(ShutdownHandler handler)
{
if (isSecure())
mSocket->async_shutdown(handler);
else
{
lowest_layer().shutdown(plain_socket::shutdown_both);
mSocket->get_io_service().post(boost::bind(handler, error_code()));
}
}
void async_handshake (handshake_type type, callback cbFunc)
{
if ((type == ssl_socket::client) || (mSecure))
{
// must be ssl
mSecure = true;
mSocket->async_handshake (type, cbFunc);
}
else if (mBuffer.empty ())
{
// must be plain
mSecure = false;
mSocket->get_io_service ().post (boost::bind (cbFunc, error_code ()));
}
else
{
// autodetect
mSocket->next_layer ().async_receive (basio::buffer (mBuffer), basio::socket_base::message_peek,
boost::bind (&AutoSocket::handle_autodetect, this, cbFunc,
basio::placeholders::error, basio::placeholders::bytes_transferred));
}
}
template <typename Seq, typename Handler> void async_read_some(const Seq& buffers, Handler handler)
{
if (isSecure())
mSocket->async_read_some(buffers, handler);
else
PlainSocket().async_read_some(buffers, handler);
}
template <typename ShutdownHandler> void async_shutdown (ShutdownHandler handler)
{
if (isSecure ())
mSocket->async_shutdown (handler);
else
{
lowest_layer ().shutdown (plain_socket::shutdown_both);
mSocket->get_io_service ().post (boost::bind (handler, error_code ()));
}
}
template <typename Seq, typename Condition, typename Handler>
void async_read_until(const Seq& buffers, Condition condition, Handler handler)
{
if (isSecure())
basio::async_read_until(*mSocket, buffers, condition, handler);
else
basio::async_read_until(PlainSocket(), buffers, condition, handler);
}
template <typename Seq, typename Handler> void async_read_some (const Seq& buffers, Handler handler)
{
if (isSecure ())
mSocket->async_read_some (buffers, handler);
else
PlainSocket ().async_read_some (buffers, handler);
}
template <typename Allocator, typename Handler>
void async_read_until(basio::basic_streambuf<Allocator>& buffers, const std::string& delim, Handler handler)
{
if (isSecure())
basio::async_read_until(*mSocket, buffers, delim, handler);
else
basio::async_read_until(PlainSocket(), buffers, delim, handler);
}
template <typename Seq, typename Condition, typename Handler>
void async_read_until (const Seq& buffers, Condition condition, Handler handler)
{
if (isSecure ())
basio::async_read_until (*mSocket, buffers, condition, handler);
else
basio::async_read_until (PlainSocket (), buffers, condition, handler);
}
template <typename Allocator, typename MatchCondition, typename Handler>
void async_read_until(basio::basic_streambuf<Allocator>& buffers, MatchCondition cond, Handler handler)
{
if (isSecure())
basio::async_read_until(*mSocket, buffers, cond, handler);
else
basio::async_read_until(PlainSocket(), buffers, cond, handler);
}
template <typename Allocator, typename Handler>
void async_read_until (basio::basic_streambuf<Allocator>& buffers, const std::string& delim, Handler handler)
{
if (isSecure ())
basio::async_read_until (*mSocket, buffers, delim, handler);
else
basio::async_read_until (PlainSocket (), buffers, delim, handler);
}
template <typename Buf, typename Handler> void async_write(const Buf& buffers, Handler handler)
{
if (isSecure())
boost::asio::async_write(*mSocket, buffers, handler);
else
boost::asio::async_write(PlainSocket(), buffers, handler);
}
template <typename Allocator, typename MatchCondition, typename Handler>
void async_read_until (basio::basic_streambuf<Allocator>& buffers, MatchCondition cond, Handler handler)
{
if (isSecure ())
basio::async_read_until (*mSocket, buffers, cond, handler);
else
basio::async_read_until (PlainSocket (), buffers, cond, handler);
}
template <typename Allocator, typename Handler>
void async_write(boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
{
if (isSecure())
boost::asio::async_write(*mSocket, buffers, handler);
else
boost::asio::async_write(PlainSocket(), buffers, handler);
}
template <typename Buf, typename Handler> void async_write (const Buf& buffers, Handler handler)
{
if (isSecure ())
boost::asio::async_write (*mSocket, buffers, handler);
else
boost::asio::async_write (PlainSocket (), buffers, handler);
}
template <typename Buf, typename Condition, typename Handler>
void async_read(const Buf& buffers, Condition cond, Handler handler)
{
if (isSecure())
boost::asio::async_read(*mSocket, buffers, cond, handler);
else
boost::asio::async_read(PlainSocket(), buffers, cond, handler);
}
template <typename Allocator, typename Handler>
void async_write (boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
{
if (isSecure ())
boost::asio::async_write (*mSocket, buffers, handler);
else
boost::asio::async_write (PlainSocket (), buffers, handler);
}
template <typename Allocator, typename Condition, typename Handler>
void async_read(basio::basic_streambuf<Allocator>& buffers, Condition cond, Handler handler)
{
if (isSecure())
boost::asio::async_read(*mSocket, buffers, cond, handler);
else
boost::asio::async_read(PlainSocket(), buffers, cond, handler);
}
template <typename Buf, typename Condition, typename Handler>
void async_read (const Buf& buffers, Condition cond, Handler handler)
{
if (isSecure ())
boost::asio::async_read (*mSocket, buffers, cond, handler);
else
boost::asio::async_read (PlainSocket (), buffers, cond, handler);
}
template <typename Buf, typename Handler> void async_read(const Buf& buffers, Handler handler)
{
if (isSecure())
boost::asio::async_read(*mSocket, buffers, handler);
else
boost::asio::async_read(PlainSocket(), buffers, handler);
}
template <typename Allocator, typename Condition, typename Handler>
void async_read (basio::basic_streambuf<Allocator>& buffers, Condition cond, Handler handler)
{
if (isSecure ())
boost::asio::async_read (*mSocket, buffers, cond, handler);
else
boost::asio::async_read (PlainSocket (), buffers, cond, handler);
}
template <typename Seq, typename Handler> void async_write_some(const Seq& buffers, Handler handler)
{
if (isSecure())
mSocket->async_write_some(buffers, handler);
else
PlainSocket().async_write_some(buffers, handler);
}
template <typename Buf, typename Handler> void async_read (const Buf& buffers, Handler handler)
{
if (isSecure ())
boost::asio::async_read (*mSocket, buffers, handler);
else
boost::asio::async_read (PlainSocket (), buffers, handler);
}
template <typename Seq, typename Handler> void async_write_some (const Seq& buffers, Handler handler)
{
if (isSecure ())
mSocket->async_write_some (buffers, handler);
else
PlainSocket ().async_write_some (buffers, handler);
}
protected:
void handle_autodetect(callback cbFunc, const error_code& ec, size_t bytesTransferred)
{
if (ec)
{
Log(lsWARNING, AutoSocketPartition) << "Handle autodetect error: " << ec;
cbFunc(ec);
}
else if ((mBuffer[0] < 127) && (mBuffer[0] > 31) &&
((bytesTransferred < 2) || ((mBuffer[1] < 127) && (mBuffer[1] > 31))) &&
((bytesTransferred < 3) || ((mBuffer[2] < 127) && (mBuffer[2] > 31))) &&
((bytesTransferred < 4) || ((mBuffer[3] < 127) && (mBuffer[3] > 31))))
{ // not ssl
if (AutoSocketPartition.doLog(lsTRACE))
Log(lsTRACE, AutoSocketPartition) << "non-SSL";
mSecure = false;
cbFunc(ec);
}
else
{ // ssl
if (AutoSocketPartition.doLog(lsTRACE))
Log(lsTRACE, AutoSocketPartition) << "SSL";
mSecure = true;
mSocket->async_handshake(ssl_socket::server, cbFunc);
}
}
void handle_autodetect (callback cbFunc, const error_code& ec, size_t bytesTransferred)
{
if (ec)
{
Log (lsWARNING, AutoSocketPartition) << "Handle autodetect error: " << ec;
cbFunc (ec);
}
else if ((mBuffer[0] < 127) && (mBuffer[0] > 31) &&
((bytesTransferred < 2) || ((mBuffer[1] < 127) && (mBuffer[1] > 31))) &&
((bytesTransferred < 3) || ((mBuffer[2] < 127) && (mBuffer[2] > 31))) &&
((bytesTransferred < 4) || ((mBuffer[3] < 127) && (mBuffer[3] > 31))))
{
// not ssl
if (AutoSocketPartition.doLog (lsTRACE))
Log (lsTRACE, AutoSocketPartition) << "non-SSL";
mSecure = false;
cbFunc (ec);
}
else
{
// ssl
if (AutoSocketPartition.doLog (lsTRACE))
Log (lsTRACE, AutoSocketPartition) << "SSL";
mSecure = true;
mSocket->async_handshake (ssl_socket::server, cbFunc);
}
}
private:
socket_ptr mSocket;
bool mSecure;
socket_ptr mSocket;
bool mSecure;
std::vector<char> mBuffer;
std::vector<char> mBuffer;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -6,63 +6,63 @@
class RPCParser
{
public:
Json::Value parseCommand(std::string strMethod, Json::Value jvParams);
Json::Value parseCommand (std::string strMethod, Json::Value jvParams);
private:
typedef Json::Value (RPCParser::*parseFuncPtr)(const Json::Value &jvParams);
typedef Json::Value (RPCParser::*parseFuncPtr) (const Json::Value& jvParams);
Json::Value parseAccountRaw(const Json::Value& jvParams, bool bPeer);
Json::Value parseAccountRaw (const Json::Value& jvParams, bool bPeer);
Json::Value parseAccountItems(const Json::Value& jvParams);
Json::Value parseAccountLines(const Json::Value& jvParams);
Json::Value parseAccountTransactions(const Json::Value& jvParams);
Json::Value parseAsIs(const Json::Value& jvParams);
Json::Value parseBookOffers(const Json::Value& jvParams);
Json::Value parseConnect(const Json::Value& jvParams);
Json::Value parseAccountItems (const Json::Value& jvParams);
Json::Value parseAccountLines (const Json::Value& jvParams);
Json::Value parseAccountTransactions (const Json::Value& jvParams);
Json::Value parseAsIs (const Json::Value& jvParams);
Json::Value parseBookOffers (const Json::Value& jvParams);
Json::Value parseConnect (const Json::Value& jvParams);
#if ENABLE_INSECURE
Json::Value parseDataDelete(const Json::Value& jvParams);
Json::Value parseDataFetch(const Json::Value& jvParams);
Json::Value parseDataStore(const Json::Value& jvParams);
Json::Value parseDataDelete (const Json::Value& jvParams);
Json::Value parseDataFetch (const Json::Value& jvParams);
Json::Value parseDataStore (const Json::Value& jvParams);
#endif
Json::Value parseEvented(const Json::Value& jvParams);
Json::Value parseFeature(const Json::Value& jvParams);
Json::Value parseGetCounts(const Json::Value& jvParams);
Json::Value parseInternal(const Json::Value& jvParams);
Json::Value parseJson(const Json::Value& jvParams);
Json::Value parseLedger(const Json::Value& jvParams);
Json::Value parseLedgerId(const Json::Value& jvParams);
Json::Value parseEvented (const Json::Value& jvParams);
Json::Value parseFeature (const Json::Value& jvParams);
Json::Value parseGetCounts (const Json::Value& jvParams);
Json::Value parseInternal (const Json::Value& jvParams);
Json::Value parseJson (const Json::Value& jvParams);
Json::Value parseLedger (const Json::Value& jvParams);
Json::Value parseLedgerId (const Json::Value& jvParams);
#if ENABLE_INSECURE
Json::Value parseLogin(const Json::Value& jvParams);
Json::Value parseLogin (const Json::Value& jvParams);
#endif
Json::Value parseLogLevel(const Json::Value& jvParams);
Json::Value parseOwnerInfo(const Json::Value& jvParams);
Json::Value parseProofCreate(const Json::Value& jvParams);
Json::Value parseProofSolve(const Json::Value& jvParams);
Json::Value parseProofVerify(const Json::Value& jvParams);
Json::Value parseRandom(const Json::Value& jvParams);
Json::Value parseRipplePathFind(const Json::Value& jvParams);
Json::Value parseSMS(const Json::Value& jvParams);
Json::Value parseSignSubmit(const Json::Value& jvParams);
Json::Value parseTx(const Json::Value& jvParams);
Json::Value parseTxHistory(const Json::Value& jvParams);
Json::Value parseUnlAdd(const Json::Value& jvParams);
Json::Value parseUnlDelete(const Json::Value& jvParams);
Json::Value parseValidationCreate(const Json::Value& jvParams);
Json::Value parseValidationSeed(const Json::Value& jvParams);
Json::Value parseWalletAccounts(const Json::Value& jvParams);
Json::Value parseWalletPropose(const Json::Value& jvParams);
Json::Value parseWalletSeed(const Json::Value& jvParams);
Json::Value parseLogLevel (const Json::Value& jvParams);
Json::Value parseOwnerInfo (const Json::Value& jvParams);
Json::Value parseProofCreate (const Json::Value& jvParams);
Json::Value parseProofSolve (const Json::Value& jvParams);
Json::Value parseProofVerify (const Json::Value& jvParams);
Json::Value parseRandom (const Json::Value& jvParams);
Json::Value parseRipplePathFind (const Json::Value& jvParams);
Json::Value parseSMS (const Json::Value& jvParams);
Json::Value parseSignSubmit (const Json::Value& jvParams);
Json::Value parseTx (const Json::Value& jvParams);
Json::Value parseTxHistory (const Json::Value& jvParams);
Json::Value parseUnlAdd (const Json::Value& jvParams);
Json::Value parseUnlDelete (const Json::Value& jvParams);
Json::Value parseValidationCreate (const Json::Value& jvParams);
Json::Value parseValidationSeed (const Json::Value& jvParams);
Json::Value parseWalletAccounts (const Json::Value& jvParams);
Json::Value parseWalletPropose (const Json::Value& jvParams);
Json::Value parseWalletSeed (const Json::Value& jvParams);
};
extern int commandLineRPC(const std::vector<std::string>& vCmd);
extern int commandLineRPC (const std::vector<std::string>& vCmd);
extern void callRPC(
boost::asio::io_service& io_service,
const std::string& strIp, const int iPort,
const std::string& strUsername, const std::string& strPassword,
const std::string& strPath, const std::string& strMethod,
const Json::Value& jvParams, const bool bSSL,
FUNCTION_TYPE<void(const Json::Value& jvInput)> callbackFuncP = 0);
extern void callRPC (
boost::asio::io_service& io_service,
const std::string& strIp, const int iPort,
const std::string& strUsername, const std::string& strPassword,
const std::string& strPath, const std::string& strMethod,
const Json::Value& jvParams, const bool bSSL,
FUNCTION_TYPE<void (const Json::Value& jvInput)> callbackFuncP = 0);
#endif
// vim:ts=4

View File

@@ -1,114 +1,120 @@
SETUP_LOG (ChangeTransactor)
TER ChangeTransactor::doApply()
TER ChangeTransactor::doApply ()
{
if (mTxn.getTxnType() == ttFEATURE)
return applyFeature();
if (mTxn.getTxnType () == ttFEATURE)
return applyFeature ();
if (mTxn.getTxnType() == ttFEE)
return applyFee();
if (mTxn.getTxnType () == ttFEE)
return applyFee ();
return temUNKNOWN;
return temUNKNOWN;
}
TER ChangeTransactor::checkSig()
TER ChangeTransactor::checkSig ()
{
if (mTxn.getFieldAccount160(sfAccount).isNonZero())
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction had bad source account";
return temBAD_SRC_ACCOUNT;
}
if (mTxn.getFieldAccount160 (sfAccount).isNonZero ())
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction had bad source account";
return temBAD_SRC_ACCOUNT;
}
if (!mTxn.getSigningPubKey().empty() || !mTxn.getSignature().empty())
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction had bad signature";
return temBAD_SIGNATURE;
}
if (!mTxn.getSigningPubKey ().empty () || !mTxn.getSignature ().empty ())
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction had bad signature";
return temBAD_SIGNATURE;
}
return tesSUCCESS;
return tesSUCCESS;
}
TER ChangeTransactor::checkSeq()
TER ChangeTransactor::checkSeq ()
{
if ((mTxn.getSequence() != 0) || mTxn.isFieldPresent(sfPreviousTxnID))
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction had bad sequence";
return temBAD_SEQUENCE;
}
return tesSUCCESS;
if ((mTxn.getSequence () != 0) || mTxn.isFieldPresent (sfPreviousTxnID))
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction had bad sequence";
return temBAD_SEQUENCE;
}
return tesSUCCESS;
}
TER ChangeTransactor::payFee()
TER ChangeTransactor::payFee ()
{
if (mTxn.getTransactionFee() != STAmount())
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction with non-zero fee";
return temBAD_FEE;
}
if (mTxn.getTransactionFee () != STAmount ())
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction with non-zero fee";
return temBAD_FEE;
}
return tesSUCCESS;
return tesSUCCESS;
}
TER ChangeTransactor::preCheck()
TER ChangeTransactor::preCheck ()
{
mTxnAccountID = mTxn.getSourceAccount().getAccountID();
if (mTxnAccountID.isNonZero())
{
WriteLog (lsWARNING, ChangeTransactor) << "applyTransaction: bad source id";
mTxnAccountID = mTxn.getSourceAccount ().getAccountID ();
return temBAD_SRC_ACCOUNT;
}
if (mTxnAccountID.isNonZero ())
{
WriteLog (lsWARNING, ChangeTransactor) << "applyTransaction: bad source id";
if (isSetBit(mParams, tapOPEN_LEDGER))
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction against open ledger";
return temINVALID;
}
return temBAD_SRC_ACCOUNT;
}
return tesSUCCESS;
if (isSetBit (mParams, tapOPEN_LEDGER))
{
WriteLog (lsWARNING, ChangeTransactor) << "Change transaction against open ledger";
return temINVALID;
}
return tesSUCCESS;
}
TER ChangeTransactor::applyFeature()
TER ChangeTransactor::applyFeature ()
{
uint256 feature = mTxn.getFieldH256(sfFeature);
uint256 feature = mTxn.getFieldH256 (sfFeature);
SLE::pointer featureObject = mEngine->entryCache(ltFEATURES, Ledger::getLedgerFeatureIndex());
if (!featureObject)
featureObject = mEngine->entryCreate(ltFEATURES, Ledger::getLedgerFeatureIndex());
SLE::pointer featureObject = mEngine->entryCache (ltFEATURES, Ledger::getLedgerFeatureIndex ());
STVector256 features = featureObject->getFieldV256(sfFeatures);
if (features.hasValue(feature))
return tefALREADY;
features.addValue(feature);
featureObject->setFieldV256(sfFeatures, features);
mEngine->entryModify(featureObject);
if (!featureObject)
featureObject = mEngine->entryCreate (ltFEATURES, Ledger::getLedgerFeatureIndex ());
theApp->getFeatureTable().enableFeature(feature);
if (!theApp->getFeatureTable().isFeatureSupported(feature))
theApp->getOPs().setFeatureBlocked();
STVector256 features = featureObject->getFieldV256 (sfFeatures);
return tesSUCCESS;
if (features.hasValue (feature))
return tefALREADY;
features.addValue (feature);
featureObject->setFieldV256 (sfFeatures, features);
mEngine->entryModify (featureObject);
theApp->getFeatureTable ().enableFeature (feature);
if (!theApp->getFeatureTable ().isFeatureSupported (feature))
theApp->getOPs ().setFeatureBlocked ();
return tesSUCCESS;
}
TER ChangeTransactor::applyFee()
TER ChangeTransactor::applyFee ()
{
SLE::pointer feeObject = mEngine->entryCache(ltFEE_SETTINGS, Ledger::getLedgerFeeIndex());
if (!feeObject)
feeObject = mEngine->entryCreate(ltFEE_SETTINGS, Ledger::getLedgerFeeIndex());
SLE::pointer feeObject = mEngine->entryCache (ltFEE_SETTINGS, Ledger::getLedgerFeeIndex ());
WriteLog (lsINFO, ChangeTransactor) << "Previous fee object: " << feeObject->getJson(0);
if (!feeObject)
feeObject = mEngine->entryCreate (ltFEE_SETTINGS, Ledger::getLedgerFeeIndex ());
feeObject->setFieldU64(sfBaseFee, mTxn.getFieldU64(sfBaseFee));
feeObject->setFieldU32(sfReferenceFeeUnits, mTxn.getFieldU32(sfReferenceFeeUnits));
feeObject->setFieldU32(sfReserveBase, mTxn.getFieldU32(sfReserveBase));
feeObject->setFieldU32(sfReserveIncrement, mTxn.getFieldU32(sfReserveIncrement));
WriteLog (lsINFO, ChangeTransactor) << "Previous fee object: " << feeObject->getJson (0);
mEngine->entryModify(feeObject);
feeObject->setFieldU64 (sfBaseFee, mTxn.getFieldU64 (sfBaseFee));
feeObject->setFieldU32 (sfReferenceFeeUnits, mTxn.getFieldU32 (sfReferenceFeeUnits));
feeObject->setFieldU32 (sfReserveBase, mTxn.getFieldU32 (sfReserveBase));
feeObject->setFieldU32 (sfReserveIncrement, mTxn.getFieldU32 (sfReserveIncrement));
WriteLog (lsINFO, ChangeTransactor) << "New fee object: " << feeObject->getJson(0);
WriteLog (lsWARNING, ChangeTransactor) << "Fees have been changed";
return tesSUCCESS;
mEngine->entryModify (feeObject);
WriteLog (lsINFO, ChangeTransactor) << "New fee object: " << feeObject->getJson (0);
WriteLog (lsWARNING, ChangeTransactor) << "Fees have been changed";
return tesSUCCESS;
}

View File

@@ -3,22 +3,27 @@
class ChangeTransactor : public Transactor
{
public:
ChangeTransactor(const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine *engine)
: Transactor(txn, params, engine)
{ ; }
ChangeTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine)
: Transactor (txn, params, engine)
{
;
}
TER doApply();
TER checkSig();
TER checkSeq();
TER payFee();
TER preCheck();
TER doApply ();
TER checkSig ();
TER checkSeq ();
TER payFee ();
TER preCheck ();
private:
TER applyFeature();
TER applyFee();
TER applyFeature ();
TER applyFee ();
// VFALCO TODO Can this be removed?
bool mustHaveValidAccount() { return false; }
bool mustHaveValidAccount ()
{
return false;
}
};
// vim:ts=4

View File

@@ -4,30 +4,30 @@ using namespace Script;
JED: V III
*/
Contract::Contract()
Contract::Contract ()
{
}
void Contract::executeCreate()
void Contract::executeCreate ()
{
}
void Contract::executeRemove()
void Contract::executeRemove ()
{
}
void Contract::executeFund()
void Contract::executeFund ()
{
}
void Contract::executeAccept()
void Contract::executeAccept ()
{
//std::vector<char> code;
//std::vector<char> code;
//Interpreter interpreter;
//interpreter.interpret(this,code);
//Interpreter interpreter;
//interpreter.interpret(this,code);
}
// vim:ts=4

View File

@@ -2,26 +2,26 @@
#define CONTRACT_H
/*
Encapsulates the SLE for a Contract
Encapsulates the SLE for a Contract
*/
class Contract
{
public:
Contract();
Contract ();
uint160& getIssuer();
uint160& getOwner();
STAmount& getRippleEscrow();
uint32 getEscrow();
uint32 getBond();
uint160& getIssuer ();
uint160& getOwner ();
STAmount& getRippleEscrow ();
uint32 getEscrow ();
uint32 getBond ();
Script::Data getData(int index);
Script::Data getData (int index);
void executeCreate();
void executeRemove();
void executeFund();
void executeAccept();
void executeCreate ();
void executeRemove ();
void executeFund ();
void executeAccept ();
};
#endif

View File

@@ -2,18 +2,19 @@
#include <string>
// Transaction database holds transactions and public keys
const char *TxnDBInit[] = {
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
const char* TxnDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
"PRAGMA mmap_size=4294967296;",
"PRAGMA mmap_size=4294967296;",
#endif
"BEGIN TRANSACTION;",
"BEGIN TRANSACTION;",
"CREATE TABLE Transactions ( \
"CREATE TABLE Transactions ( \
TransID CHARACTER(64) PRIMARY KEY, \
TransType CHARACTER(24), \
FromAcct CHARACTER(35), \
@@ -23,36 +24,37 @@ const char *TxnDBInit[] = {
RawTxn BLOB, \
TxnMeta BLOB \
);",
"CREATE INDEX TxLgrIndex ON \
"CREATE INDEX TxLgrIndex ON \
Transactions(LedgerSeq);",
"CREATE TABLE AccountTransactions ( \
"CREATE TABLE AccountTransactions ( \
TransID CHARACTER(64), \
Account CHARACTER(64), \
LedgerSeq BIGINT UNSIGNED, \
TxnSeq INTEGER \
);",
"CREATE INDEX AcctTxIDIndex ON \
"CREATE INDEX AcctTxIDIndex ON \
AccountTransactions(TransID);",
"CREATE INDEX AcctTxIndex ON \
"CREATE INDEX AcctTxIndex ON \
AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);",
"CREATE INDEX AcctLgrIndex ON \
"CREATE INDEX AcctLgrIndex ON \
AccountTransactions(LedgerSeq, Account, TransID);",
"END TRANSACTION;"
"END TRANSACTION;"
};
int TxnDBCount = NUMBER(TxnDBInit);
int TxnDBCount = NUMBER (TxnDBInit);
// Ledger database holds ledgers and ledger confirmations
const char *LedgerDBInit[] = {
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
const char* LedgerDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
"BEGIN TRANSACTION;",
"BEGIN TRANSACTION;",
"CREATE TABLE Ledgers ( \
"CREATE TABLE Ledgers ( \
LedgerHash CHARACTER(64) PRIMARY KEY, \
LedgerSeq BIGINT UNSIGNED, \
PrevHash CHARACTER(64), \
@@ -64,82 +66,84 @@ const char *LedgerDBInit[] = {
AccountSetHash CHARACTER(64), \
TransSetHash CHARACTER(64) \
);",
"CREATE INDEX SeqLedger ON Ledgers(LedgerSeq);",
"CREATE INDEX SeqLedger ON Ledgers(LedgerSeq);",
"CREATE TABLE Validations ( \
"CREATE TABLE Validations ( \
LedgerHash CHARACTER(64), \
NodePubKey CHARACTER(56), \
SignTime BIGINT UNSIGNED, \
RawData BLOB \
);",
"CREATE INDEX ValidationsByHash ON \
"CREATE INDEX ValidationsByHash ON \
Validations(LedgerHash);",
"CREATE INDEX ValidationsByTime ON \
"CREATE INDEX ValidationsByTime ON \
Validations(SignTime);",
"END TRANSACTION;"
"END TRANSACTION;"
};
int LedgerDBCount = NUMBER(LedgerDBInit);
int LedgerDBCount = NUMBER (LedgerDBInit);
// RPC database holds persistent data for RPC clients.
const char *RpcDBInit[] = {
const char* RpcDBInit[] =
{
// Local persistence of the RPC client
"CREATE TABLE RPCData ( \
// Local persistence of the RPC client
"CREATE TABLE RPCData ( \
Key TEXT PRIMARY Key, \
Value TEXT \
);",
};
int RpcDBCount = NUMBER(RpcDBInit);
int RpcDBCount = NUMBER (RpcDBInit);
// Wallet database holds local accounts and trusted nodes
const char *WalletDBInit[] = {
// Node identity must be persisted for CAS routing and responsibilities.
"BEGIN TRANSACTION;",
const char* WalletDBInit[] =
{
// Node identity must be persisted for CAS routing and responsibilities.
"BEGIN TRANSACTION;",
"CREATE TABLE NodeIdentity ( \
"CREATE TABLE NodeIdentity ( \
PublicKey CHARACTER(53), \
PrivateKey CHARACTER(52), \
Dh512 TEXT, \
Dh1024 TEXT \
);",
// Miscellaneous persistent information
// Integer: 1 : Used to simplify SQL.
// ScoreUpdated: when scores was last updated.
// FetchUpdated: when last fetch succeeded.
"CREATE TABLE Misc ( \
// Miscellaneous persistent information
// Integer: 1 : Used to simplify SQL.
// ScoreUpdated: when scores was last updated.
// FetchUpdated: when last fetch succeeded.
"CREATE TABLE Misc ( \
Magic INTEGER UNIQUE NOT NULL, \
ScoreUpdated DATETIME, \
FetchUpdated DATETIME \
);",
// Scoring and other information for domains.
//
// Domain:
// Domain source for https.
// PublicKey:
// Set if ever succeeded.
// XXX Use NULL in place of ""
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
// Table of Domains user has asked to trust.
"CREATE TABLE SeedDomains ( \
// Scoring and other information for domains.
//
// Domain:
// Domain source for https.
// PublicKey:
// Set if ever succeeded.
// XXX Use NULL in place of ""
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
// Table of Domains user has asked to trust.
"CREATE TABLE SeedDomains ( \
Domain TEXT PRIMARY KEY NOT NULL, \
PublicKey CHARACTER(53), \
Source CHARACTER(1) NOT NULL, \
@@ -150,27 +154,27 @@ const char *WalletDBInit[] = {
Comment TEXT \
);",
// Allow us to easily find the next SeedDomain to fetch.
"CREATE INDEX SeedDomainNext ON SeedDomains (Next);",
// Allow us to easily find the next SeedDomain to fetch.
"CREATE INDEX SeedDomainNext ON SeedDomains (Next);",
// Table of PublicKeys user has asked to trust.
// Fetches are made to the CAS. This gets the ripple.txt so even validators without a web server can publish a ripple.txt.
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
"CREATE TABLE SeedNodes ( \
// Table of PublicKeys user has asked to trust.
// Fetches are made to the CAS. This gets the ripple.txt so even validators without a web server can publish a ripple.txt.
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
"CREATE TABLE SeedNodes ( \
PublicKey CHARACTER(53) PRIMARY KEY NOT NULL, \
Source CHARACTER(1) NOT NULL, \
Next DATETIME, \
@@ -180,51 +184,51 @@ const char *WalletDBInit[] = {
Comment TEXT \
);",
// Allow us to easily find the next SeedNode to fetch.
"CREATE INDEX SeedNodeNext ON SeedNodes (Next);",
// Allow us to easily find the next SeedNode to fetch.
"CREATE INDEX SeedNodeNext ON SeedNodes (Next);",
// Nodes we trust to not grossly collude against us. Derived from SeedDomains, SeedNodes, and ValidatorReferrals.
//
// Score:
// Computed trust score. Higher is better.
// Seen:
// Last validation received.
"CREATE TABLE TrustedNodes ( \
// Nodes we trust to not grossly collude against us. Derived from SeedDomains, SeedNodes, and ValidatorReferrals.
//
// Score:
// Computed trust score. Higher is better.
// Seen:
// Last validation received.
"CREATE TABLE TrustedNodes ( \
PublicKey CHARACTER(53) PRIMARY KEY NOT NULL, \
Score INTEGER DEFAULT 0 NOT NULL, \
Seen DATETIME, \
Comment TEXT \
);",
// List of referrals.
// - There may be multiple sources for a Validator. The last source is used.
// Validator:
// Public key of referrer.
// Entry:
// Entry index in [validators] table.
// Referral:
// This is the form provided by the ripple.txt:
// - Public key for CAS based referral.
// - Domain for domain based referral.
// XXX Do garbage collection when validators have no references.
"CREATE TABLE ValidatorReferrals ( \
// List of referrals.
// - There may be multiple sources for a Validator. The last source is used.
// Validator:
// Public key of referrer.
// Entry:
// Entry index in [validators] table.
// Referral:
// This is the form provided by the ripple.txt:
// - Public key for CAS based referral.
// - Domain for domain based referral.
// XXX Do garbage collection when validators have no references.
"CREATE TABLE ValidatorReferrals ( \
Validator CHARACTER(53) NOT NULL, \
Entry INTEGER NOT NULL, \
Referral TEXT NOT NULL, \
PRIMARY KEY (Validator,Entry) \
);",
// List of referrals from ripple.txt files.
// Validator:
// Public key of referree.
// Entry:
// Entry index in [validators] table.
// IP:
// IP of referred.
// Port:
// -1 = Default
// XXX Do garbage collection when ips have no references.
"CREATE TABLE IpReferrals ( \
// List of referrals from ripple.txt files.
// Validator:
// Public key of referree.
// Entry:
// Entry index in [validators] table.
// IP:
// IP of referred.
// Port:
// -1 = Default
// XXX Do garbage collection when ips have no references.
"CREATE TABLE IpReferrals ( \
Validator CHARACTER(53) NOT NULL, \
Entry INTEGER NOT NULL, \
IP TEXT NOT NULL, \
@@ -232,25 +236,25 @@ const char *WalletDBInit[] = {
PRIMARY KEY (Validator,Entry) \
);",
// Table of IPs to contact the network.
// IP:
// IP address to contact.
// Port:
// Port to contact.
// -1 = Default
// Score:
// Computed trust score. Higher is better.
// Source:
// 'V' = Validation file
// 'M' = Manually added.
// 'I' = Inbound connection.
// 'T' = Told by other peer
// 'O' = Other.
// ScanNext:
// When to next scan. Null=not scanning.
// ScanInterval:
// Delay between scans.
"CREATE TABLE PeerIps ( \
// Table of IPs to contact the network.
// IP:
// IP address to contact.
// Port:
// Port to contact.
// -1 = Default
// Score:
// Computed trust score. Higher is better.
// Source:
// 'V' = Validation file
// 'M' = Manually added.
// 'I' = Inbound connection.
// 'T' = Told by other peer
// 'O' = Other.
// ScanNext:
// When to next scan. Null=not scanning.
// ScanInterval:
// Delay between scans.
"CREATE TABLE PeerIps ( \
IpPort TEXT NOT NULL PRIMARY KEY, \
Score INTEGER NOT NULL DEFAULT 0, \
Source CHARACTER(1) NOT NULL, \
@@ -258,48 +262,50 @@ const char *WalletDBInit[] = {
ScanInterval INTEGER NOT NULL DEFAULT 0 \
);",
"CREATE INDEX PeerScanIndex ON \
"CREATE INDEX PeerScanIndex ON \
PeerIps(ScanNext);",
"CREATE TABLE Features ( \
"CREATE TABLE Features ( \
Hash CHARACTER(64) PRIMARY KEY, \
FirstMajority BIGINT UNSIGNED, \
LastMajority BIGINT UNSIGNED \
);",
"END TRANSACTION;"
"END TRANSACTION;"
};
int WalletDBCount = NUMBER(WalletDBInit);
int WalletDBCount = NUMBER (WalletDBInit);
// Hash node database holds nodes indexed by hash
const char *HashNodeDBInit[] = {
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
const char* HashNodeDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
"PRAGMA mmap_size=4294967296;",
"PRAGMA mmap_size=4294967296;",
#endif
"BEGIN TRANSACTION;",
"BEGIN TRANSACTION;",
"CREATE TABLE CommittedObjects ( \
"CREATE TABLE CommittedObjects ( \
Hash CHARACTER(64) PRIMARY KEY, \
ObjType CHAR(1) NOT NULL, \
LedgerIndex BIGINT UNSIGNED, \
Object BLOB \
);",
"END TRANSACTION;"
"END TRANSACTION;"
};
int HashNodeDBCount = NUMBER(HashNodeDBInit);
int HashNodeDBCount = NUMBER (HashNodeDBInit);
// Net node database holds nodes seen on the network
// XXX Not really used needs replacement.
const char *NetNodeDBInit[] = {
"CREATE TABLE KnownNodes ( \
const char* NetNodeDBInit[] =
{
"CREATE TABLE KnownNodes ( \
Hanko CHARACTER(35) PRIMARY KEY, \
LastSeen TEXT, \
HaveContactInfo CHARACTER(1), \
@@ -307,38 +313,39 @@ const char *NetNodeDBInit[] = {
);"
};
int NetNodeDBCount = NUMBER(NetNodeDBInit);
int NetNodeDBCount = NUMBER (NetNodeDBInit);
const char *PathFindDBInit[] = {
"PRAGMA synchronous = OFF; ",
const char* PathFindDBInit[] =
{
"PRAGMA synchronous = OFF; ",
"DROP TABLE TrustLines; ",
"DROP TABLE TrustLines; ",
"CREATE TABLE TrustLines { "
"To CHARACTER(40), " // Hex of account trusted
"By CHARACTER(40), " // Hex of account trusting
"Currency CHARACTER(80), " // Hex currency, hex issuer
"Use INTEGER, " // Use count
"Seq BIGINT UNSIGNED " // Sequence when use count was updated
"}; ",
"CREATE TABLE TrustLines { "
"To CHARACTER(40), " // Hex of account trusted
"By CHARACTER(40), " // Hex of account trusting
"Currency CHARACTER(80), " // Hex currency, hex issuer
"Use INTEGER, " // Use count
"Seq BIGINT UNSIGNED " // Sequence when use count was updated
"}; ",
"CREATE INDEX TLBy ON TrustLines(By, Currency, Use);",
"CREATE INDEX TLTo ON TrustLines(To, Currency, Use);",
"CREATE INDEX TLBy ON TrustLines(By, Currency, Use);",
"CREATE INDEX TLTo ON TrustLines(To, Currency, Use);",
"DROP TABLE Exchanges;",
"DROP TABLE Exchanges;",
"CREATE TABLE Exchanges { "
"From CHARACTER(80), "
"To CHARACTER(80), "
"Currency CHARACTER(80), "
"Use INTEGER, "
"Seq BIGINT UNSIGNED "
"}; ",
"CREATE TABLE Exchanges { "
"From CHARACTER(80), "
"To CHARACTER(80), "
"Currency CHARACTER(80), "
"Use INTEGER, "
"Seq BIGINT UNSIGNED "
"}; ",
"CREATE INDEX ExBy ON Exchanges(By, Currency, Use);",
"CREATE INDEX ExTo ON Exchanges(To, Currency, Use);",
"CREATE INDEX ExBy ON Exchanges(By, Currency, Use);",
"CREATE INDEX ExTo ON Exchanges(To, Currency, Use);",
};
int PathFindDBCount = NUMBER(PathFindDBInit);
int PathFindDBCount = NUMBER (PathFindDBInit);
// vim:ts=4

View File

@@ -8,97 +8,107 @@ SETUP_LOG (HTTPRequest)
// Logic to handle incoming HTTP reqests
void HTTPRequest::reset()
void HTTPRequest::reset ()
{
mHeaders.clear();
sRequestBody.clear();
sAuthorization.clear();
iDataSize = 0;
bShouldClose = true;
eState = await_request;
mHeaders.clear ();
sRequestBody.clear ();
sAuthorization.clear ();
iDataSize = 0;
bShouldClose = true;
eState = await_request;
}
HTTPRequestAction HTTPRequest::requestDone(bool forceClose)
HTTPRequestAction HTTPRequest::requestDone (bool forceClose)
{
if (forceClose || bShouldClose)
return haCLOSE_CONN;
reset();
return haREAD_LINE;
if (forceClose || bShouldClose)
return haCLOSE_CONN;
reset ();
return haREAD_LINE;
}
std::string HTTPRequest::getReplyHeaders(bool forceClose)
std::string HTTPRequest::getReplyHeaders (bool forceClose)
{
if (forceClose || bShouldClose)
return "Connection: close\r\n";
else
return "Connection: Keep-Alive\r\n";
if (forceClose || bShouldClose)
return "Connection: close\r\n";
else
return "Connection: Keep-Alive\r\n";
}
HTTPRequestAction HTTPRequest::consume(boost::asio::streambuf& buf)
HTTPRequestAction HTTPRequest::consume (boost::asio::streambuf& buf)
{
std::string line;
std::istream is(&buf);
std::getline(is, line);
boost::trim(line);
std::string line;
std::istream is (&buf);
std::getline (is, line);
boost::trim (line);
// WriteLog (lsTRACE, HTTPRequest) << "HTTPRequest line: " << line;
// WriteLog (lsTRACE, HTTPRequest) << "HTTPRequest line: " << line;
if (eState == await_request)
{ // VERB URL PROTO
if (line.empty())
return haREAD_LINE;
sRequest = line;
bShouldClose = sRequest.find("HTTP/1.1") == std::string::npos;
if (eState == await_request)
{
// VERB URL PROTO
if (line.empty ())
return haREAD_LINE;
eState = await_header;
return haREAD_LINE;
}
sRequest = line;
bShouldClose = sRequest.find ("HTTP/1.1") == std::string::npos;
if (eState == await_header)
{ // HEADER_NAME: HEADER_BODY
if (line.empty()) // empty line or bare \r
{
if (iDataSize == 0)
{ // no body
eState = do_request;
return haDO_REQUEST;
}
eState = getting_body;
return haREAD_RAW;
}
size_t colon = line.find(':');
if (colon != std::string::npos)
{
std::string headerName = line.substr(0, colon);
boost::trim(headerName);
boost::to_lower(headerName);
eState = await_header;
return haREAD_LINE;
}
std::string headerValue = line.substr(colon+1);
boost::trim(headerValue);
if (eState == await_header)
{
// HEADER_NAME: HEADER_BODY
if (line.empty ()) // empty line or bare \r
{
if (iDataSize == 0)
{
// no body
eState = do_request;
return haDO_REQUEST;
}
mHeaders[headerName] += headerValue;
eState = getting_body;
return haREAD_RAW;
}
if (headerName == "connection")
{
boost::to_lower(headerValue);
if ((headerValue == "keep-alive") || (headerValue == "keepalive"))
bShouldClose = false;
if (headerValue == "close")
bShouldClose = true;
}
size_t colon = line.find (':');
if (headerName == "content-length")
iDataSize = boost::lexical_cast<int>(headerValue);
if (colon != std::string::npos)
{
std::string headerName = line.substr (0, colon);
boost::trim (headerName);
boost::to_lower (headerName);
if (headerName == "authorization")
sAuthorization = headerValue;
}
std::string headerValue = line.substr (colon + 1);
boost::trim (headerValue);
return haREAD_LINE;
}
mHeaders[headerName] += headerValue;
assert(false);
return haERROR;
if (headerName == "connection")
{
boost::to_lower (headerValue);
if ((headerValue == "keep-alive") || (headerValue == "keepalive"))
bShouldClose = false;
if (headerValue == "close")
bShouldClose = true;
}
if (headerName == "content-length")
iDataSize = boost::lexical_cast<int> (headerValue);
if (headerName == "authorization")
sAuthorization = headerValue;
}
return haREAD_LINE;
}
assert (false);
return haERROR;
}
// vim:ts=4

View File

@@ -7,54 +7,83 @@
#include <boost/asio/streambuf.hpp>
enum HTTPRequestAction
{ // What the application code needs to do
haERROR = 0,
haREAD_LINE = 1,
haREAD_RAW = 2,
haDO_REQUEST = 3,
haCLOSE_CONN = 4
{
// What the application code needs to do
haERROR = 0,
haREAD_LINE = 1,
haREAD_RAW = 2,
haDO_REQUEST = 3,
haCLOSE_CONN = 4
};
class HTTPRequest
{ // an HTTP request we are handling from a client
{
// an HTTP request we are handling from a client
public:
HTTPRequest() : eState(await_request), iDataSize(0), bShouldClose(true) { ; }
void reset();
HTTPRequest () : eState (await_request), iDataSize (0), bShouldClose (true)
{
;
}
void reset ();
std::string& peekBody() { return sRequestBody; }
std::string getBody() { return sRequestBody; }
std::string& peekRequest() { return sRequest; }
std::string getRequest() { return sRequest; }
std::string& peekAuth() { return sAuthorization; }
std::string getAuth() { return sAuthorization; }
std::string& peekBody ()
{
return sRequestBody;
}
std::string getBody ()
{
return sRequestBody;
}
std::string& peekRequest ()
{
return sRequest;
}
std::string getRequest ()
{
return sRequest;
}
std::string& peekAuth ()
{
return sAuthorization;
}
std::string getAuth ()
{
return sAuthorization;
}
std::map<std::string, std::string>& peekHeaders() { return mHeaders; }
std::string getReplyHeaders(bool forceClose);
std::map<std::string, std::string>& peekHeaders ()
{
return mHeaders;
}
std::string getReplyHeaders (bool forceClose);
HTTPRequestAction consume(boost::asio::streambuf&);
HTTPRequestAction requestDone(bool forceClose); // call after reply is sent
HTTPRequestAction consume (boost::asio::streambuf&);
HTTPRequestAction requestDone (bool forceClose); // call after reply is sent
int getDataSize() { return iDataSize; }
int getDataSize ()
{
return iDataSize;
}
private:
enum state
{
await_request, // We are waiting for the request line
await_header, // We are waiting for request headers
getting_body, // We are waiting for the body
do_request, // We are waiting for the request to complete
};
enum state
{
await_request, // We are waiting for the request line
await_header, // We are waiting for request headers
getting_body, // We are waiting for the body
do_request, // We are waiting for the request to complete
};
state eState;
std::string sRequest; // VERB URL PROTO
std::string sRequestBody;
std::string sAuthorization;
state eState;
std::string sRequest; // VERB URL PROTO
std::string sRequestBody;
std::string sAuthorization;
std::map<std::string, std::string> mHeaders;
std::map<std::string, std::string> mHeaders;
int iDataSize;
bool bShouldClose;
int iDataSize;
bool bShouldClose;
};
#endif

View File

@@ -3,37 +3,37 @@
// TXN - Hash of transaction plus signature to give transaction ID
const uint32 sHP_TransactionID = 0x54584E00;
const uint32 sHP_TransactionID = 0x54584E00;
// TND - Hash of transaction plus metadata
const uint32 sHP_TransactionNode = 0x534E4400;
const uint32 sHP_TransactionNode = 0x534E4400;
// MLN - Hash of account state
const uint32 sHP_LeafNode = 0x4D4C4E00;
const uint32 sHP_LeafNode = 0x4D4C4E00;
// MIN - Hash of inner node in tree
const uint32 sHP_InnerNode = 0x4D494E00;
const uint32 sHP_InnerNode = 0x4D494E00;
// LGR - Hash of ledger master data for signing
const uint32 sHP_Ledger = 0x4C575200;
const uint32 sHP_Ledger = 0x4C575200;
// STX - Hash of inner transaction to sign
const uint32 sHP_TransactionSign = 0x53545800;
const uint32 sHP_TransactionSign = 0x53545800;
// VAL - Hash of validation for signing
const uint32 sHP_Validation = 0x56414C00;
const uint32 sHP_Validation = 0x56414C00;
// PRP - Hash of proposal for signing
const uint32 sHP_Proposal = 0x50525000;
const uint32 sHP_Proposal = 0x50525000;
// stx - TESTNET Hash of inner transaction to sign
const uint32 sHP_TestNetTransactionSign = 0x73747800;
const uint32 sHP_TestNetTransactionSign = 0x73747800;
// val - TESTNET Hash of validation for signing
const uint32 sHP_TestNetValidation = 0x76616C00;
const uint32 sHP_TestNetValidation = 0x76616C00;
// prp - TESTNET Hash of proposal for signing
const uint32 sHP_TestNetProposal = 0x70727000;
const uint32 sHP_TestNetProposal = 0x70727000;
#endif

View File

@@ -14,461 +14,472 @@ HttpsClient::HttpsClient (boost::asio::io_service& io_service,
, mResponseMax (responseMax)
, mDeadline (io_service)
{
if (!theConfig.SSL_VERIFY)
mSocket.SSLSocket().set_verify_mode (boost::asio::ssl::verify_none);
if (!theConfig.SSL_VERIFY)
mSocket.SSLSocket ().set_verify_mode (boost::asio::ssl::verify_none);
}
void HttpsClient::makeGet(const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost)
void HttpsClient::makeGet (const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost)
{
std::ostream osRequest(&sb);
std::ostream osRequest (&sb);
osRequest <<
"GET " << strPath << " HTTP/1.0\r\n"
"Host: " << strHost << "\r\n"
"Accept: */*\r\n" // YYY Do we need this line?
"Connection: close\r\n\r\n";
osRequest <<
"GET " << strPath << " HTTP/1.0\r\n"
"Host: " << strHost << "\r\n"
"Accept: */*\r\n" // YYY Do we need this line?
"Connection: close\r\n\r\n";
}
void HttpsClient::httpsRequest(
bool bSSL,
std::deque<std::string> deqSites,
FUNCTION_TYPE<void(boost::asio::streambuf& sb, const std::string& strHost)> build,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
void HttpsClient::httpsRequest (
bool bSSL,
std::deque<std::string> deqSites,
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> build,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
{
mSSL = bSSL;
mDeqSites = deqSites;
mBuild = build;
mComplete = complete;
mTimeout = timeout;
mSSL = bSSL;
mDeqSites = deqSites;
mBuild = build;
mComplete = complete;
mTimeout = timeout;
httpsNext();
httpsNext ();
}
void HttpsClient::httpsGet(
bool bSSL,
std::deque<std::string> deqSites,
const std::string& strPath,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete) {
mComplete = complete;
mTimeout = timeout;
httpsRequest(
bSSL,
deqSites,
BIND_TYPE(&HttpsClient::makeGet, shared_from_this(), strPath, P_1, P_2),
timeout,
complete);
}
void HttpsClient::httpsNext()
void HttpsClient::httpsGet (
bool bSSL,
std::deque<std::string> deqSites,
const std::string& strPath,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
{
WriteLog (lsTRACE, HttpsClient) << "Fetch: " << mDeqSites[0];
mComplete = complete;
mTimeout = timeout;
httpsRequest (
bSSL,
deqSites,
BIND_TYPE (&HttpsClient::makeGet, shared_from_this (), strPath, P_1, P_2),
timeout,
complete);
}
void HttpsClient::httpsNext ()
{
WriteLog (lsTRACE, HttpsClient) << "Fetch: " << mDeqSites[0];
boost::shared_ptr <boost::asio::ip::tcp::resolver::query> query (
new boost::asio::ip::tcp::resolver::query (
mDeqSites[0],
boost::lexical_cast <std::string>(mPort),
boost::asio::ip::resolver_query_base::numeric_service));
mQuery = query;
boost::lexical_cast <std::string> (mPort),
boost::asio::ip::resolver_query_base::numeric_service));
mQuery = query;
mDeadline.expires_from_now(mTimeout, mShutdown);
mDeadline.expires_from_now (mTimeout, mShutdown);
WriteLog (lsTRACE, HttpsClient) << "expires_from_now: " << mShutdown.message();
if (!mShutdown)
{
mDeadline.async_wait(
boost::bind(
&HttpsClient::handleDeadline,
shared_from_this(),
boost::asio::placeholders::error));
}
WriteLog (lsTRACE, HttpsClient) << "expires_from_now: " << mShutdown.message ();
if (!mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Resolving: " << mDeqSites[0];
mResolver.async_resolve(*mQuery,
boost::bind(
&HttpsClient::handleResolve,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
mDeadline.async_wait (
boost::bind (
&HttpsClient::handleDeadline,
shared_from_this (),
boost::asio::placeholders::error));
}
if (mShutdown)
invokeComplete(mShutdown);
if (!mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Resolving: " << mDeqSites[0];
mResolver.async_resolve (*mQuery,
boost::bind (
&HttpsClient::handleResolve,
shared_from_this (),
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
if (mShutdown)
invokeComplete (mShutdown);
}
void HttpsClient::handleDeadline(const boost::system::error_code& ecResult)
void HttpsClient::handleDeadline (const boost::system::error_code& ecResult)
{
if (ecResult == boost::asio::error::operation_aborted)
{
// Timer canceled because deadline no longer needed.
WriteLog (lsTRACE, HttpsClient) << "Deadline cancelled.";
nothing(); // Aborter is done.
}
else if (ecResult)
if (ecResult == boost::asio::error::operation_aborted)
{
WriteLog (lsTRACE, HttpsClient) << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message();
// Timer canceled because deadline no longer needed.
WriteLog (lsTRACE, HttpsClient) << "Deadline cancelled.";
// Can't do anything sound.
abort();
nothing (); // Aborter is done.
}
else if (ecResult)
{
WriteLog (lsTRACE, HttpsClient) << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message ();
// Can't do anything sound.
abort ();
}
else
{
WriteLog (lsTRACE, HttpsClient) << "Deadline arrived.";
WriteLog (lsTRACE, HttpsClient) << "Deadline arrived.";
// Mark us as shutting down.
// XXX Use our own error code.
mShutdown = boost::system::error_code(boost::system::errc::bad_address, boost::system::system_category());
// Mark us as shutting down.
// XXX Use our own error code.
mShutdown = boost::system::error_code (boost::system::errc::bad_address, boost::system::system_category ());
// Cancel any resolving.
mResolver.cancel();
// Cancel any resolving.
mResolver.cancel ();
// Stop the transaction.
mSocket.async_shutdown(boost::bind(
&HttpsClient::handleShutdown,
shared_from_this(),
boost::asio::placeholders::error));
// Stop the transaction.
mSocket.async_shutdown (boost::bind (
&HttpsClient::handleShutdown,
shared_from_this (),
boost::asio::placeholders::error));
}
}
void HttpsClient::handleShutdown(
const boost::system::error_code& ecResult
)
void HttpsClient::handleShutdown (
const boost::system::error_code& ecResult
)
{
if (ecResult)
{
WriteLog (lsTRACE, HttpsClient) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message();
}
if (ecResult)
{
WriteLog (lsTRACE, HttpsClient) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message ();
}
}
void HttpsClient::handleResolve(
const boost::system::error_code& ecResult,
boost::asio::ip::tcp::resolver::iterator itrEndpoint
)
void HttpsClient::handleResolve (
const boost::system::error_code& ecResult,
boost::asio::ip::tcp::resolver::iterator itrEndpoint
)
{
if (!mShutdown)
mShutdown = ecResult;
if (!mShutdown)
mShutdown = ecResult;
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message();
WriteLog (lsTRACE, HttpsClient) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message ();
invokeComplete(mShutdown);
invokeComplete (mShutdown);
}
else
{
WriteLog (lsTRACE, HttpsClient) << "Resolve complete.";
else
{
WriteLog (lsTRACE, HttpsClient) << "Resolve complete.";
boost::asio::async_connect(
mSocket.lowest_layer(),
itrEndpoint,
boost::bind(
&HttpsClient::handleConnect,
shared_from_this(),
boost::asio::placeholders::error));
boost::asio::async_connect (
mSocket.lowest_layer (),
itrEndpoint,
boost::bind (
&HttpsClient::handleConnect,
shared_from_this (),
boost::asio::placeholders::error));
}
}
void HttpsClient::handleConnect(const boost::system::error_code& ecResult)
void HttpsClient::handleConnect (const boost::system::error_code& ecResult)
{
if (!mShutdown)
mShutdown = ecResult;
if (!mShutdown)
mShutdown = ecResult;
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Connect error: " << mShutdown.message();
WriteLog (lsTRACE, HttpsClient) << "Connect error: " << mShutdown.message ();
}
if (!mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Connected.";
if (theConfig.SSL_VERIFY)
{
mShutdown = mSocket.verify(mDeqSites[0]);
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message();
}
}
}
if (mShutdown)
{
invokeComplete(mShutdown);
WriteLog (lsTRACE, HttpsClient) << "Connected.";
if (theConfig.SSL_VERIFY)
{
mShutdown = mSocket.verify (mDeqSites[0]);
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message ();
}
}
}
if (mShutdown)
{
invokeComplete (mShutdown);
}
else if (mSSL)
{
mSocket.async_handshake(
AutoSocket::ssl_socket::client,
boost::bind(
&HttpsClient::handleRequest,
shared_from_this(),
boost::asio::placeholders::error));
}
else
{
handleRequest(ecResult);
}
}
void HttpsClient::handleRequest(const boost::system::error_code& ecResult)
{
if (!mShutdown)
mShutdown = ecResult;
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Handshake error:" << mShutdown.message();
invokeComplete(mShutdown);
}
else
{
WriteLog (lsTRACE, HttpsClient) << "Session started.";
mBuild(mRequest, mDeqSites[0]);
mSocket.async_write(
mRequest,
boost::bind(&HttpsClient::handleWrite,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
void HttpsClient::handleWrite(const boost::system::error_code& ecResult, std::size_t bytes_transferred)
{
if (!mShutdown)
mShutdown = ecResult;
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Write error: " << mShutdown.message();
invokeComplete(mShutdown);
mSocket.async_handshake (
AutoSocket::ssl_socket::client,
boost::bind (
&HttpsClient::handleRequest,
shared_from_this (),
boost::asio::placeholders::error));
}
else
{
WriteLog (lsTRACE, HttpsClient) << "Wrote.";
mSocket.async_read_until(
mHeader,
"\r\n\r\n",
boost::bind(&HttpsClient::handleHeader,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
handleRequest (ecResult);
}
}
void HttpsClient::handleHeader(const boost::system::error_code& ecResult, std::size_t bytes_transferred)
void HttpsClient::handleRequest (const boost::system::error_code& ecResult)
{
std::string strHeader((std::istreambuf_iterator<char>(&mHeader)), std::istreambuf_iterator<char>());
WriteLog (lsTRACE, HttpsClient) << "Header: \"" << strHeader << "\"";
if (!mShutdown)
mShutdown = ecResult;
static boost::regex reStatus("\\`HTTP/1\\S+ (\\d{3}) .*\\'"); // HTTP/1.1 200 OK
static boost::regex reSize("\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'");
static boost::regex reBody("\\`.*\\r\\n\\r\\n(.*)\\'");
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Handshake error:" << mShutdown.message ();
boost::smatch smMatch;
invokeComplete (mShutdown);
}
else
{
WriteLog (lsTRACE, HttpsClient) << "Session started.";
bool bMatch = boost::regex_match(strHeader, smMatch, reStatus); // Match status code.
if (!bMatch)
{
// XXX Use our own error code.
WriteLog (lsTRACE, HttpsClient) << "No status code";
invokeComplete(boost::system::error_code(boost::system::errc::bad_address, boost::system::system_category()));
return;
}
mStatus = lexical_cast_st<int>(smMatch[1]);
mBuild (mRequest, mDeqSites[0]);
if (boost::regex_match(strHeader, smMatch, reBody)) // we got some body
mBody = smMatch[1];
if (boost::regex_match(strHeader, smMatch, reSize))
{
int size = lexical_cast_st<int>(smMatch[1]);
if (size < mResponseMax)
mResponseMax = size;
}
if (mResponseMax == 0) // no body wanted or available
invokeComplete(ecResult, mStatus);
else if (mBody.size() >= mResponseMax) // we got the whole thing
invokeComplete(ecResult, mStatus, mBody);
else
mSocket.async_read(
mResponse.prepare(mResponseMax - mBody.size()),
boost::asio::transfer_all(),
boost::bind(&HttpsClient::handleData,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
mSocket.async_write (
mRequest,
boost::bind (&HttpsClient::handleWrite,
shared_from_this (),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
void HttpsClient::handleData(const boost::system::error_code& ecResult, std::size_t bytes_transferred)
void HttpsClient::handleWrite (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
{
if (!mShutdown)
mShutdown = ecResult;
if (!mShutdown)
mShutdown = ecResult;
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Write error: " << mShutdown.message ();
invokeComplete (mShutdown);
}
else
{
WriteLog (lsTRACE, HttpsClient) << "Wrote.";
mSocket.async_read_until (
mHeader,
"\r\n\r\n",
boost::bind (&HttpsClient::handleHeader,
shared_from_this (),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
void HttpsClient::handleHeader (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
{
std::string strHeader ((std::istreambuf_iterator<char> (&mHeader)), std::istreambuf_iterator<char> ());
WriteLog (lsTRACE, HttpsClient) << "Header: \"" << strHeader << "\"";
static boost::regex reStatus ("\\`HTTP/1\\S+ (\\d{3}) .*\\'"); // HTTP/1.1 200 OK
static boost::regex reSize ("\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'");
static boost::regex reBody ("\\`.*\\r\\n\\r\\n(.*)\\'");
boost::smatch smMatch;
bool bMatch = boost::regex_match (strHeader, smMatch, reStatus); // Match status code.
if (!bMatch)
{
// XXX Use our own error code.
WriteLog (lsTRACE, HttpsClient) << "No status code";
invokeComplete (boost::system::error_code (boost::system::errc::bad_address, boost::system::system_category ()));
return;
}
mStatus = lexical_cast_st<int> (smMatch[1]);
if (boost::regex_match (strHeader, smMatch, reBody)) // we got some body
mBody = smMatch[1];
if (boost::regex_match (strHeader, smMatch, reSize))
{
int size = lexical_cast_st<int> (smMatch[1]);
if (size < mResponseMax)
mResponseMax = size;
}
if (mResponseMax == 0) // no body wanted or available
invokeComplete (ecResult, mStatus);
else if (mBody.size () >= mResponseMax) // we got the whole thing
invokeComplete (ecResult, mStatus, mBody);
else
mSocket.async_read (
mResponse.prepare (mResponseMax - mBody.size ()),
boost::asio::transfer_all (),
boost::bind (&HttpsClient::handleData,
shared_from_this (),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void HttpsClient::handleData (const boost::system::error_code& ecResult, std::size_t bytes_transferred)
{
if (!mShutdown)
mShutdown = ecResult;
if (mShutdown && mShutdown != boost::asio::error::eof)
{
WriteLog (lsTRACE, HttpsClient) << "Read error: " << mShutdown.message();
WriteLog (lsTRACE, HttpsClient) << "Read error: " << mShutdown.message ();
invokeComplete(mShutdown);
invokeComplete (mShutdown);
}
else
{
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Complete.";
if (mShutdown)
{
WriteLog (lsTRACE, HttpsClient) << "Complete.";
nothing();
}
else
{
mResponse.commit(bytes_transferred);
std::string strBody((std::istreambuf_iterator<char>(&mResponse)), std::istreambuf_iterator<char>());
invokeComplete(ecResult, mStatus, mBody + strBody);
}
nothing ();
}
else
{
mResponse.commit (bytes_transferred);
std::string strBody ((std::istreambuf_iterator<char> (&mResponse)), std::istreambuf_iterator<char> ());
invokeComplete (ecResult, mStatus, mBody + strBody);
}
}
}
// Call cancel the deadline timer and invoke the completion routine.
void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)
void HttpsClient::invokeComplete (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)
{
boost::system::error_code ecCancel;
boost::system::error_code ecCancel;
(void) mDeadline.cancel(ecCancel);
(void) mDeadline.cancel (ecCancel);
if (ecCancel)
{
WriteLog (lsTRACE, HttpsClient) << "HttpsClient::invokeComplete: Deadline cancel error: " << ecCancel.message();
}
if (ecCancel)
{
WriteLog (lsTRACE, HttpsClient) << "HttpsClient::invokeComplete: Deadline cancel error: " << ecCancel.message ();
}
WriteLog (lsDEBUG, HttpsClient) << "HttpsClient::invokeComplete: Deadline popping: " << mDeqSites.size();
if (!mDeqSites.empty())
{
mDeqSites.pop_front();
}
WriteLog (lsDEBUG, HttpsClient) << "HttpsClient::invokeComplete: Deadline popping: " << mDeqSites.size ();
bool bAgain = true;
if (!mDeqSites.empty ())
{
mDeqSites.pop_front ();
}
if (mDeqSites.empty() || !ecResult)
{
// ecResult: !0 = had an error, last entry
// iStatus: result, if no error
// strData: data, if no error
bAgain = mComplete && mComplete(ecResult ? ecResult : ecCancel, iStatus, strData);
}
bool bAgain = true;
if (!mDeqSites.empty() && bAgain)
{
httpsNext();
}
if (mDeqSites.empty () || !ecResult)
{
// ecResult: !0 = had an error, last entry
// iStatus: result, if no error
// strData: data, if no error
bAgain = mComplete && mComplete (ecResult ? ecResult : ecCancel, iStatus, strData);
}
if (!mDeqSites.empty () && bAgain)
{
httpsNext ();
}
}
void HttpsClient::httpsGet(
bool bSSL,
boost::asio::io_service& io_service,
std::deque<std::string> deqSites,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete) {
void HttpsClient::httpsGet (
bool bSSL,
boost::asio::io_service& io_service,
std::deque<std::string> deqSites,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
{
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, responseMax));
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, port, responseMax));
client->httpsGet(bSSL, deqSites, strPath, timeout, complete);
client->httpsGet (bSSL, deqSites, strPath, timeout, complete);
}
void HttpsClient::httpsGet(
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete) {
void HttpsClient::httpsGet (
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
{
std::deque<std::string> deqSites(1, strSite);
std::deque<std::string> deqSites (1, strSite);
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, responseMax));
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, port, responseMax));
client->httpsGet(bSSL, deqSites, strPath, timeout, complete);
client->httpsGet (bSSL, deqSites, strPath, timeout, complete);
}
void HttpsClient::httpsRequest(
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
FUNCTION_TYPE<void(boost::asio::streambuf& sb, const std::string& strHost)> setRequest,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete) {
void HttpsClient::httpsRequest (
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> setRequest,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
{
std::deque<std::string> deqSites(1, strSite);
std::deque<std::string> deqSites (1, strSite);
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, responseMax));
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, port, responseMax));
client->httpsRequest(bSSL, deqSites, setRequest, timeout, complete);
client->httpsRequest (bSSL, deqSites, setRequest, timeout, complete);
}
#define SMS_TIMEOUT 30
#define SMS_TIMEOUT 30
bool responseSMS(const boost::system::error_code& ecResult, int iStatus, const std::string& strData) {
WriteLog (lsINFO, HttpsClient) << "SMS: Response:" << iStatus << " :" << strData;
bool responseSMS (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)
{
WriteLog (lsINFO, HttpsClient) << "SMS: Response:" << iStatus << " :" << strData;
return true;
return true;
}
void HttpsClient::sendSMS(boost::asio::io_service& io_service, const std::string& strText) {
std::string strScheme;
std::string strDomain;
int iPort;
std::string strPath;
void HttpsClient::sendSMS (boost::asio::io_service& io_service, const std::string& strText)
{
std::string strScheme;
std::string strDomain;
int iPort;
std::string strPath;
if (theConfig.SMS_URL == "" || !parseUrl(theConfig.SMS_URL, strScheme, strDomain, iPort, strPath))
{
WriteLog (lsWARNING, HttpsClient) << "SMSRequest: Bad URL:" << theConfig.SMS_URL;
}
else
{
bool bSSL = strScheme == "https";
if (theConfig.SMS_URL == "" || !parseUrl (theConfig.SMS_URL, strScheme, strDomain, iPort, strPath))
{
WriteLog (lsWARNING, HttpsClient) << "SMSRequest: Bad URL:" << theConfig.SMS_URL;
}
else
{
bool bSSL = strScheme == "https";
std::deque<std::string> deqSites(1, strDomain);
std::string strURI =
boost::str(boost::format("%s?from=%s&to=%s&api_key=%s&api_secret=%s&text=%s")
% (strPath.empty() ? "/" : strPath)
% theConfig.SMS_FROM
% theConfig.SMS_TO
% theConfig.SMS_KEY
% theConfig.SMS_SECRET
% urlEncode(strText));
std::deque<std::string> deqSites (1, strDomain);
std::string strURI =
boost::str (boost::format ("%s?from=%s&to=%s&api_key=%s&api_secret=%s&text=%s")
% (strPath.empty () ? "/" : strPath)
% theConfig.SMS_FROM
% theConfig.SMS_TO
% theConfig.SMS_KEY
% theConfig.SMS_SECRET
% urlEncode (strText));
// WriteLog (lsINFO) << "SMS: Request:" << strURI;
WriteLog (lsINFO, HttpsClient) << "SMS: Request: '" << strText << "'";
// WriteLog (lsINFO) << "SMS: Request:" << strURI;
WriteLog (lsINFO, HttpsClient) << "SMS: Request: '" << strText << "'";
if (iPort < 0)
iPort = bSSL ? 443 : 80;
if (iPort < 0)
iPort = bSSL ? 443 : 80;
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, iPort, maxClientHeaderBytes));
boost::shared_ptr<HttpsClient> client (new HttpsClient (io_service, iPort, maxClientHeaderBytes));
client->httpsGet(bSSL, deqSites, strURI, boost::posix_time::seconds(SMS_TIMEOUT),
BIND_TYPE(&responseSMS, P_1, P_2, P_3));
}
client->httpsGet (bSSL, deqSites, strURI, boost::posix_time::seconds (SMS_TIMEOUT),
BIND_TYPE (&responseSMS, P_1, P_2, P_3));
}
}
// vim:ts=4

View File

@@ -19,106 +19,106 @@
class HttpsClient : public boost::enable_shared_from_this<HttpsClient>
{
public:
HttpsClient(
boost::asio::io_service& io_service,
const unsigned short port,
std::size_t responseMax
);
HttpsClient (
boost::asio::io_service& io_service,
const unsigned short port,
std::size_t responseMax
);
void httpsRequest(
bool bSSL,
std::deque<std::string> deqSites,
FUNCTION_TYPE<void(boost::asio::streambuf& sb, const std::string& strHost)> build,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
void httpsRequest (
bool bSSL,
std::deque<std::string> deqSites,
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> build,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
void httpsGet(
bool bSSL,
std::deque<std::string> deqSites,
const std::string& strPath,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
void httpsGet (
bool bSSL,
std::deque<std::string> deqSites,
const std::string& strPath,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
static void httpsGet(
bool bSSL,
boost::asio::io_service& io_service,
std::deque<std::string> deqSites,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
static void httpsGet (
bool bSSL,
boost::asio::io_service& io_service,
std::deque<std::string> deqSites,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
static void httpsGet(
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
static void httpsGet (
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
const std::string& strPath,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
static void httpsRequest(
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
FUNCTION_TYPE<void(boost::asio::streambuf& sb, const std::string& strHost)> build,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
static void httpsRequest (
bool bSSL,
boost::asio::io_service& io_service,
std::string strSite,
const unsigned short port,
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> build,
std::size_t responseMax,
boost::posix_time::time_duration timeout,
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
static void sendSMS(boost::asio::io_service& io_service, const std::string& strText);
static void sendSMS (boost::asio::io_service& io_service, const std::string& strText);
private:
static const int maxClientHeaderBytes = 32 * 1024;
typedef boost::shared_ptr<HttpsClient> pointer;
bool mSSL;
AutoSocket mSocket;
boost::asio::ip::tcp::resolver mResolver;
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> mQuery;
boost::asio::streambuf mRequest;
boost::asio::streambuf mHeader;
boost::asio::streambuf mResponse;
std::string mBody;
const unsigned short mPort;
int mResponseMax;
int mStatus;
FUNCTION_TYPE<void(boost::asio::streambuf& sb, const std::string& strHost)> mBuild;
FUNCTION_TYPE<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> mComplete;
bool mSSL;
AutoSocket mSocket;
boost::asio::ip::tcp::resolver mResolver;
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> mQuery;
boost::asio::streambuf mRequest;
boost::asio::streambuf mHeader;
boost::asio::streambuf mResponse;
std::string mBody;
const unsigned short mPort;
int mResponseMax;
int mStatus;
FUNCTION_TYPE<void (boost::asio::streambuf& sb, const std::string& strHost)> mBuild;
FUNCTION_TYPE<bool (const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> mComplete;
boost::asio::deadline_timer mDeadline;
boost::asio::deadline_timer mDeadline;
// If not success, we are shutting down.
boost::system::error_code mShutdown;
// If not success, we are shutting down.
boost::system::error_code mShutdown;
std::deque<std::string> mDeqSites;
boost::posix_time::time_duration mTimeout;
std::deque<std::string> mDeqSites;
boost::posix_time::time_duration mTimeout;
void handleDeadline(const boost::system::error_code& ecResult);
void handleDeadline (const boost::system::error_code& ecResult);
void handleResolve(const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
void handleResolve (const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
void handleConnect(const boost::system::error_code& ecResult);
void handleConnect (const boost::system::error_code& ecResult);
void handleRequest(const boost::system::error_code& ecResult);
void handleRequest (const boost::system::error_code& ecResult);
void handleWrite(const boost::system::error_code& ecResult, std::size_t bytes_transferred);
void handleWrite (const boost::system::error_code& ecResult, std::size_t bytes_transferred);
void handleHeader(const boost::system::error_code& ecResult, std::size_t bytes_transferred);
void handleHeader (const boost::system::error_code& ecResult, std::size_t bytes_transferred);
void handleData(const boost::system::error_code& ecResult, std::size_t bytes_transferred);
void handleData (const boost::system::error_code& ecResult, std::size_t bytes_transferred);
void handleShutdown(const boost::system::error_code& ecResult);
void handleShutdown (const boost::system::error_code& ecResult);
void httpsNext();
void httpsNext ();
void invokeComplete(const boost::system::error_code& ecResult, int iStatus = 0, const std::string& strData = "");
void invokeComplete (const boost::system::error_code& ecResult, int iStatus = 0, const std::string& strData = "");
void makeGet(const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost);
void makeGet (const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost);
};
#endif

View File

@@ -6,193 +6,203 @@ We also need to charge for each op
*/
namespace Script {
Interpreter::Interpreter()
namespace Script
{
mContract=NULL;
mCode=NULL;
mInstructionPointer=0;
mTotalFee=0;
mInBlock=false;
mBlockSuccess=true;
mBlockJump=0;
Interpreter::Interpreter ()
{
mContract = NULL;
mCode = NULL;
mInstructionPointer = 0;
mTotalFee = 0;
mFunctionTable.resize(NUM_OF_OPS);
mFunctionTable[INT_OP]=new IntOp();
mFunctionTable[FLOAT_OP]=new FloatOp();
mFunctionTable[UINT160_OP]=new Uint160Op();
mFunctionTable[BOOL_OP]=new Uint160Op();
mFunctionTable[PATH_OP]=new Uint160Op();
mInBlock = false;
mBlockSuccess = true;
mBlockJump = 0;
mFunctionTable.resize (NUM_OF_OPS);
mFunctionTable[INT_OP] = new IntOp ();
mFunctionTable[FLOAT_OP] = new FloatOp ();
mFunctionTable[UINT160_OP] = new Uint160Op ();
mFunctionTable[BOOL_OP] = new Uint160Op ();
mFunctionTable[PATH_OP] = new Uint160Op ();
mFunctionTable[ADD_OP] = new AddOp ();
mFunctionTable[SUB_OP] = new SubOp ();
mFunctionTable[MUL_OP] = new MulOp ();
mFunctionTable[DIV_OP] = new DivOp ();
mFunctionTable[MOD_OP] = new ModOp ();
mFunctionTable[GTR_OP] = new GtrOp ();
mFunctionTable[LESS_OP] = new LessOp ();
mFunctionTable[EQUAL_OP] = new SubOp ();
mFunctionTable[NOT_EQUAL_OP] = new SubOp ();
mFunctionTable[AND_OP] = new SubOp ();
mFunctionTable[OR_OP] = new SubOp ();
mFunctionTable[NOT_OP] = new SubOp ();
mFunctionTable[JUMP_OP] = new SubOp ();
mFunctionTable[JUMPIF_OP] = new SubOp ();
mFunctionTable[STOP_OP] = new SubOp ();
mFunctionTable[CANCEL_OP] = new SubOp ();
mFunctionTable[BLOCK_OP] = new SubOp ();
mFunctionTable[BLOCK_END_OP] = new SubOp ();
mFunctionTable[SEND_XRP_OP] = new SendXRPOp ();
/*
mFunctionTable[SEND_OP]=new SendOp();
mFunctionTable[REMOVE_CONTRACT_OP]=new SubOp();
mFunctionTable[FEE_OP]=new SubOp();
mFunctionTable[CHANGE_CONTRACT_OWNER_OP]=new SubOp();
mFunctionTable[STOP_REMOVE_OP]=new SubOp();
mFunctionTable[SET_DATA_OP]=new SubOp();
mFunctionTable[GET_DATA_OP]=new SubOp();
mFunctionTable[GET_NUM_DATA_OP]=new SubOp();
mFunctionTable[SET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_ISSUER_ID_OP]=new SubOp();
mFunctionTable[GET_OWNER_ID_OP]=new SubOp();
mFunctionTable[GET_LEDGER_TIME_OP]=new SubOp();
mFunctionTable[GET_LEDGER_NUM_OP]=new SubOp();
mFunctionTable[GET_RAND_FLOAT_OP]=new SubOp();
mFunctionTable[GET_XRP_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_CURRENCY_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_ISSUER]=new GetRippleEscrowedIssuerOp();
mFunctionTable[GET_ACCEPT_DATA_OP]=new AcceptDataOp();
mFunctionTable[GET_ACCEPTOR_ID_OP]=new GetAcceptorIDOp();
mFunctionTable[GET_CONTRACT_ID_OP]=new GetContractIDOp();
*/
mFunctionTable[ADD_OP]=new AddOp();
mFunctionTable[SUB_OP]=new SubOp();
mFunctionTable[MUL_OP]=new MulOp();
mFunctionTable[DIV_OP]=new DivOp();
mFunctionTable[MOD_OP]=new ModOp();
mFunctionTable[GTR_OP]=new GtrOp();
mFunctionTable[LESS_OP]=new LessOp();
mFunctionTable[EQUAL_OP]=new SubOp();
mFunctionTable[NOT_EQUAL_OP]=new SubOp();
mFunctionTable[AND_OP]=new SubOp();
mFunctionTable[OR_OP]=new SubOp();
mFunctionTable[NOT_OP]=new SubOp();
mFunctionTable[JUMP_OP]=new SubOp();
mFunctionTable[JUMPIF_OP]=new SubOp();
mFunctionTable[STOP_OP]=new SubOp();
mFunctionTable[CANCEL_OP]=new SubOp();
mFunctionTable[BLOCK_OP]=new SubOp();
mFunctionTable[BLOCK_END_OP]=new SubOp();
mFunctionTable[SEND_XRP_OP]=new SendXRPOp();
/*
mFunctionTable[SEND_OP]=new SendOp();
mFunctionTable[REMOVE_CONTRACT_OP]=new SubOp();
mFunctionTable[FEE_OP]=new SubOp();
mFunctionTable[CHANGE_CONTRACT_OWNER_OP]=new SubOp();
mFunctionTable[STOP_REMOVE_OP]=new SubOp();
mFunctionTable[SET_DATA_OP]=new SubOp();
mFunctionTable[GET_DATA_OP]=new SubOp();
mFunctionTable[GET_NUM_DATA_OP]=new SubOp();
mFunctionTable[SET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_ISSUER_ID_OP]=new SubOp();
mFunctionTable[GET_OWNER_ID_OP]=new SubOp();
mFunctionTable[GET_LEDGER_TIME_OP]=new SubOp();
mFunctionTable[GET_LEDGER_NUM_OP]=new SubOp();
mFunctionTable[GET_RAND_FLOAT_OP]=new SubOp();
mFunctionTable[GET_XRP_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_CURRENCY_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_ISSUER]=new GetRippleEscrowedIssuerOp();
mFunctionTable[GET_ACCEPT_DATA_OP]=new AcceptDataOp();
mFunctionTable[GET_ACCEPTOR_ID_OP]=new GetAcceptorIDOp();
mFunctionTable[GET_CONTRACT_ID_OP]=new GetContractIDOp();
*/
}
Data::pointer Interpreter::popStack()
Data::pointer Interpreter::popStack ()
{
if(mStack.size())
{
Data::pointer item=mStack[mStack.size()-1];
mStack.pop_back();
return(item);
}else
{
return(Data::pointer(new ErrorData()));
}
if (mStack.size ())
{
Data::pointer item = mStack[mStack.size () - 1];
mStack.pop_back ();
return (item);
}
else
{
return (Data::pointer (new ErrorData ()));
}
}
void Interpreter::pushStack(Data::pointer data)
void Interpreter::pushStack (Data::pointer data)
{
mStack.push_back(data);
mStack.push_back (data);
}
// offset is where to jump to if the block fails
bool Interpreter::startBlock(int offset)
bool Interpreter::startBlock (int offset)
{
if(mInBlock) return(false); // can't nest blocks
mBlockSuccess=true;
mInBlock=true;
mBlockJump=offset+mInstructionPointer;
return(true);
if (mInBlock) return (false); // can't nest blocks
mBlockSuccess = true;
mInBlock = true;
mBlockJump = offset + mInstructionPointer;
return (true);
}
bool Interpreter::endBlock()
bool Interpreter::endBlock ()
{
if(!mInBlock) return(false);
mInBlock=false;
mBlockJump=0;
pushStack(Data::pointer(new BoolData(mBlockSuccess)));
return(true);
if (!mInBlock) return (false);
mInBlock = false;
mBlockJump = 0;
pushStack (Data::pointer (new BoolData (mBlockSuccess)));
return (true);
}
TER Interpreter::interpret(Contract* contract,const SerializedTransaction& txn,Blob& code)
TER Interpreter::interpret (Contract* contract, const SerializedTransaction& txn, Blob& code)
{
mContract=contract;
mCode=&code;
mTotalFee=0;
mInstructionPointer=0;
while(mInstructionPointer<code.size())
{
unsigned int fun=(*mCode)[mInstructionPointer];
mInstructionPointer++;
mContract = contract;
mCode = &code;
mTotalFee = 0;
mInstructionPointer = 0;
if(fun>=mFunctionTable.size())
{
// TODO: log
return(temMALFORMED); // TODO: is this actually what we want to do?
}
while (mInstructionPointer < code.size ())
{
unsigned int fun = (*mCode)[mInstructionPointer];
mInstructionPointer++;
mTotalFee += mFunctionTable[ fun ]->getFee(); // FIXME: You can't use fees this way, there's no consensus
if(mTotalFee>txn.getTransactionFee().getNValue())
{
// TODO: log
return(telINSUF_FEE_P);
}else
{
if(!mFunctionTable[ fun ]->work(this))
{
// TODO: log
return(temMALFORMED); // TODO: is this actually what we want to do?
}
}
}
return(tesSUCCESS);
if (fun >= mFunctionTable.size ())
{
// TODO: log
return (temMALFORMED); // TODO: is this actually what we want to do?
}
mTotalFee += mFunctionTable[ fun ]->getFee (); // FIXME: You can't use fees this way, there's no consensus
if (mTotalFee > txn.getTransactionFee ().getNValue ())
{
// TODO: log
return (telINSUF_FEE_P);
}
else
{
if (!mFunctionTable[ fun ]->work (this))
{
// TODO: log
return (temMALFORMED); // TODO: is this actually what we want to do?
}
}
}
return (tesSUCCESS);
}
Data::pointer Interpreter::getIntData()
Data::pointer Interpreter::getIntData ()
{
int value=0; // TODO
mInstructionPointer += 4;
return(Data::pointer(new IntData(value)));
int value = 0; // TODO
mInstructionPointer += 4;
return (Data::pointer (new IntData (value)));
}
Data::pointer Interpreter::getFloatData()
Data::pointer Interpreter::getFloatData ()
{
float value=0; // TODO
mInstructionPointer += 4;
return(Data::pointer(new FloatData(value)));
float value = 0; // TODO
mInstructionPointer += 4;
return (Data::pointer (new FloatData (value)));
}
Data::pointer Interpreter::getUint160Data()
Data::pointer Interpreter::getUint160Data ()
{
uint160 value; // TODO
mInstructionPointer += 20;
return(Data::pointer(new Uint160Data(value)));
uint160 value; // TODO
mInstructionPointer += 20;
return (Data::pointer (new Uint160Data (value)));
}
bool Interpreter::jumpTo(int offset)
bool Interpreter::jumpTo (int offset)
{
mInstructionPointer += offset;
if( (mInstructionPointer<0) || (mInstructionPointer>mCode->size()) )
{
mInstructionPointer -= offset;
return(false);
}
return(true);
mInstructionPointer += offset;
if ( (mInstructionPointer < 0) || (mInstructionPointer > mCode->size ()) )
{
mInstructionPointer -= offset;
return (false);
}
return (true);
}
void Interpreter::stop()
void Interpreter::stop ()
{
mInstructionPointer=mCode->size();
mInstructionPointer = mCode->size ();
}
Data::pointer Interpreter::getContractData(int index)
Data::pointer Interpreter::getContractData (int index)
{
return(Data::pointer(new ErrorData()));
return (Data::pointer (new ErrorData ()));
}
bool Interpreter::canSign(const uint160& signer)
bool Interpreter::canSign (const uint160& signer)
{
return(true);
return (true);
}

View File

@@ -1,70 +1,78 @@
#ifndef INTERPRETER_H
#define INTERPRETER_H
namespace Script {
namespace Script
{
class Operation;
// Contracts are non typed have variable data types
class Interpreter
{
std::vector<Operation*> mFunctionTable;
std::vector<Operation*> mFunctionTable;
std::vector<Data::pointer> mStack;
std::vector<Data::pointer> mStack;
Contract* mContract;
Blob * mCode;
unsigned int mInstructionPointer;
int mTotalFee;
Contract* mContract;
Blob* mCode;
unsigned int mInstructionPointer;
int mTotalFee;
bool mInBlock;
int mBlockJump;
bool mBlockSuccess;
bool mInBlock;
int mBlockJump;
bool mBlockSuccess;
public:
enum { INT_OP=1,FLOAT_OP,UINT160_OP,BOOL_OP,PATH_OP,
ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP,
GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP,
AND_OP,OR_OP,NOT_OP,
JUMP_OP, JUMPIF_OP,
STOP_OP, CANCEL_OP,
enum { INT_OP = 1, FLOAT_OP, UINT160_OP, BOOL_OP, PATH_OP,
ADD_OP, SUB_OP, MUL_OP, DIV_OP, MOD_OP,
GTR_OP, LESS_OP, EQUAL_OP, NOT_EQUAL_OP,
AND_OP, OR_OP, NOT_OP,
JUMP_OP, JUMPIF_OP,
STOP_OP, CANCEL_OP,
BLOCK_OP, BLOCK_END_OP,
SEND_XRP_OP,SEND_OP,REMOVE_CONTRACT_OP,FEE_OP,CHANGE_CONTRACT_OWNER_OP,
STOP_REMOVE_OP,
SET_DATA_OP,GET_DATA_OP, GET_NUM_DATA_OP,
SET_REGISTER_OP,GET_REGISTER_OP,
GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP,
GET_XRP_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER,
GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP,
NUM_OF_OPS };
BLOCK_OP, BLOCK_END_OP,
SEND_XRP_OP, SEND_OP, REMOVE_CONTRACT_OP, FEE_OP, CHANGE_CONTRACT_OWNER_OP,
STOP_REMOVE_OP,
SET_DATA_OP, GET_DATA_OP, GET_NUM_DATA_OP,
SET_REGISTER_OP, GET_REGISTER_OP,
GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP,
GET_XRP_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER,
GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP,
NUM_OF_OPS
};
Interpreter();
Interpreter ();
// returns a TransactionEngineResult
TER interpret(Contract* contract,const SerializedTransaction& txn,Blob& code);
// returns a TransactionEngineResult
TER interpret (Contract* contract, const SerializedTransaction& txn, Blob& code);
void stop();
void stop ();
bool canSign(const uint160& signer);
bool canSign (const uint160& signer);
int getInstructionPointer(){ return(mInstructionPointer); }
void setInstructionPointer(int n){ mInstructionPointer=n;}
int getInstructionPointer ()
{
return (mInstructionPointer);
}
void setInstructionPointer (int n)
{
mInstructionPointer = n;
}
Data::pointer popStack();
void pushStack(Data::pointer data);
bool jumpTo(int offset);
Data::pointer popStack ();
void pushStack (Data::pointer data);
bool jumpTo (int offset);
bool startBlock(int offset);
bool endBlock();
bool startBlock (int offset);
bool endBlock ();
Data::pointer getIntData();
Data::pointer getFloatData();
Data::pointer getUint160Data();
Data::pointer getAcceptData(int index);
Data::pointer getContractData(int index);
Data::pointer getIntData ();
Data::pointer getFloatData ();
Data::pointer getUint160Data ();
Data::pointer getAcceptData (int index);
Data::pointer getContractData (int index);
};
} // end namespace

File diff suppressed because it is too large Load Diff

View File

@@ -5,25 +5,25 @@ class Job;
enum LedgerStateParms
{
lepNONE = 0, // no special flags
lepNONE = 0, // no special flags
// input flags
lepCREATE = 1, // Create if not present
// input flags
lepCREATE = 1, // Create if not present
// output flags
lepOKAY = 2, // success
lepMISSING = 4, // No node in that slot
lepWRONGTYPE = 8, // Node of different type there
lepCREATED = 16, // Node was created
lepERROR = 32, // error
// output flags
lepOKAY = 2, // success
lepMISSING = 4, // No node in that slot
lepWRONGTYPE = 8, // Node of different type there
lepCREATED = 16, // Node was created
lepERROR = 32, // error
};
#define LEDGER_JSON_DUMP_TXRP 0x10000000
#define LEDGER_JSON_DUMP_STATE 0x20000000
#define LEDGER_JSON_EXPAND 0x40000000
#define LEDGER_JSON_FULL 0x80000000
#define LEDGER_JSON_DUMP_TXRP 0x10000000
#define LEDGER_JSON_DUMP_STATE 0x20000000
#define LEDGER_JSON_EXPAND 0x40000000
#define LEDGER_JSON_FULL 0x80000000
DEFINE_INSTANCE(Ledger);
DEFINE_INSTANCE (Ledger);
class SqliteStatement;
@@ -32,343 +32,430 @@ class SqliteStatement;
// class. But then what is the meaning of a Ledger object? Is this
// really two classes in one? StoreOfAllLedgers + SingleLedgerObject?
//
class Ledger : public boost::enable_shared_from_this<Ledger>, public IS_INSTANCE(Ledger)
{ // The basic Ledger structure, can be opened, closed, or synching
class Ledger : public boost::enable_shared_from_this<Ledger>, public IS_INSTANCE (Ledger)
{
// The basic Ledger structure, can be opened, closed, or synching
// VFALCO TODO eliminate the need for friends
friend class TransactionEngine;
friend class Transactor;
friend class TransactionEngine;
friend class Transactor;
public:
typedef boost::shared_ptr<Ledger> pointer;
typedef const boost::shared_ptr<Ledger>& ref;
typedef boost::shared_ptr<Ledger> pointer;
typedef const boost::shared_ptr<Ledger>& ref;
enum TransResult
{
TR_ERROR = -1,
TR_SUCCESS = 0,
TR_NOTFOUND = 1,
TR_ALREADY = 2,
TR_BADTRANS = 3, // the transaction itself is corrupt
TR_BADACCT = 4, // one of the accounts is invalid
TR_INSUFF = 5, // the sending(apply)/receiving(remove) account is broke
TR_PASTASEQ = 6, // account is past this transaction
TR_PREASEQ = 7, // account is missing transactions before this
TR_BADLSEQ = 8, // ledger too early
TR_TOOSMALL = 9, // amount is less than Tx fee
};
enum TransResult
{
TR_ERROR = -1,
TR_SUCCESS = 0,
TR_NOTFOUND = 1,
TR_ALREADY = 2,
TR_BADTRANS = 3, // the transaction itself is corrupt
TR_BADACCT = 4, // one of the accounts is invalid
TR_INSUFF = 5, // the sending(apply)/receiving(remove) account is broke
TR_PASTASEQ = 6, // account is past this transaction
TR_PREASEQ = 7, // account is missing transactions before this
TR_BADLSEQ = 8, // ledger too early
TR_TOOSMALL = 9, // amount is less than Tx fee
};
// ledger close flags
static const uint32 sLCF_NoConsensusTime = 1;
// ledger close flags
static const uint32 sLCF_NoConsensusTime = 1;
public:
Ledger(const RippleAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger
Ledger (const RippleAddress & masterID, uint64 startAmount); // used for the starting bootstrap ledger
Ledger(uint256 const& parentHash, uint256 const& transHash, uint256 const& accountHash,
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution,
uint32 ledgerSeq, bool& loaded); // used for database ledgers
Ledger (uint256 const & parentHash, uint256 const & transHash, uint256 const & accountHash,
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution,
uint32 ledgerSeq, bool & loaded); // used for database ledgers
Ledger(Blob const& rawLedger, bool hasPrefix);
Ledger(const std::string& rawLedger, bool hasPrefix);
Ledger (Blob const & rawLedger, bool hasPrefix);
Ledger (const std::string & rawLedger, bool hasPrefix);
Ledger(bool dummy, Ledger& previous); // ledger after this one
Ledger (bool dummy, Ledger & previous); // ledger after this one
Ledger(Ledger& target, bool isMutable); // snapshot
Ledger (Ledger & target, bool isMutable); // snapshot
static Ledger::pointer getSQL(const std::string& sqlStatement);
static Ledger::pointer getSQL1(SqliteStatement*);
static void getSQL2(Ledger::ref);
static Ledger::pointer getLastFullLedger();
static uint32 roundCloseTime(uint32 closeTime, uint32 closeResolution);
static Ledger::pointer getSQL (const std::string & sqlStatement);
static Ledger::pointer getSQL1 (SqliteStatement*);
static void getSQL2 (Ledger::ref);
static Ledger::pointer getLastFullLedger ();
static uint32 roundCloseTime (uint32 closeTime, uint32 closeResolution);
void updateHash();
void setClosed() { mClosed = true; }
void setAccepted(uint32 closeTime, int closeResolution, bool correctCloseTime);
void setAccepted();
void setImmutable();
bool isClosed() { return mClosed; }
bool isAccepted() { return mAccepted; }
bool isImmutable() { return mImmutable; }
bool isFixed() { return mClosed || mImmutable; }
void setFull() { mTransactionMap->setLedgerSeq(mLedgerSeq); mAccountStateMap->setLedgerSeq(mLedgerSeq); }
void updateHash ();
void setClosed ()
{
mClosed = true;
}
void setAccepted (uint32 closeTime, int closeResolution, bool correctCloseTime);
void setAccepted ();
void setImmutable ();
bool isClosed ()
{
return mClosed;
}
bool isAccepted ()
{
return mAccepted;
}
bool isImmutable ()
{
return mImmutable;
}
bool isFixed ()
{
return mClosed || mImmutable;
}
void setFull ()
{
mTransactionMap->setLedgerSeq (mLedgerSeq);
mAccountStateMap->setLedgerSeq (mLedgerSeq);
}
// ledger signature operations
void addRaw(Serializer &s) const;
void setRaw(Serializer& s, bool hasPrefix);
// ledger signature operations
void addRaw (Serializer & s) const;
void setRaw (Serializer & s, bool hasPrefix);
uint256 getHash();
uint256 const& getParentHash() const { return mParentHash; }
uint256 const& getTransHash() const { return mTransHash; }
uint256 const& getAccountHash() const { return mAccountHash; }
uint64 getTotalCoins() const { return mTotCoins; }
void destroyCoins(uint64 fee) { mTotCoins -= fee; }
uint32 getCloseTimeNC() const { return mCloseTime; }
uint32 getParentCloseTimeNC() const { return mParentCloseTime; }
uint32 getLedgerSeq() const { return mLedgerSeq; }
int getCloseResolution() const { return mCloseResolution; }
bool getCloseAgree() const { return (mCloseFlags & sLCF_NoConsensusTime) == 0; }
uint256 getHash ();
uint256 const& getParentHash () const
{
return mParentHash;
}
uint256 const& getTransHash () const
{
return mTransHash;
}
uint256 const& getAccountHash () const
{
return mAccountHash;
}
uint64 getTotalCoins () const
{
return mTotCoins;
}
void destroyCoins (uint64 fee)
{
mTotCoins -= fee;
}
uint32 getCloseTimeNC () const
{
return mCloseTime;
}
uint32 getParentCloseTimeNC () const
{
return mParentCloseTime;
}
uint32 getLedgerSeq () const
{
return mLedgerSeq;
}
int getCloseResolution () const
{
return mCloseResolution;
}
bool getCloseAgree () const
{
return (mCloseFlags & sLCF_NoConsensusTime) == 0;
}
// close time functions
void setCloseTime(uint32 ct) { assert(!mImmutable); mCloseTime = ct; }
void setCloseTime(boost::posix_time::ptime);
boost::posix_time::ptime getCloseTime() const;
// close time functions
void setCloseTime (uint32 ct)
{
assert (!mImmutable);
mCloseTime = ct;
}
void setCloseTime (boost::posix_time::ptime);
boost::posix_time::ptime getCloseTime () const;
// low level functions
SHAMap::ref peekTransactionMap() { return mTransactionMap; }
SHAMap::ref peekAccountStateMap() { return mAccountStateMap; }
void dropCache()
{
assert(isImmutable());
if (mTransactionMap)
mTransactionMap->dropCache();
if (mAccountStateMap)
mAccountStateMap->dropCache();
}
// low level functions
SHAMap::ref peekTransactionMap ()
{
return mTransactionMap;
}
SHAMap::ref peekAccountStateMap ()
{
return mAccountStateMap;
}
void dropCache ()
{
assert (isImmutable ());
// ledger sync functions
void setAcquiring(void);
bool isAcquiring(void);
bool isAcquiringTx(void);
bool isAcquiringAS(void);
if (mTransactionMap)
mTransactionMap->dropCache ();
// Transaction Functions
bool addTransaction(uint256 const& id, const Serializer& txn);
bool addTransaction(uint256 const& id, const Serializer& txn, const Serializer& metaData);
bool hasTransaction(uint256 const& TransID) const { return mTransactionMap->hasItem(TransID); }
Transaction::pointer getTransaction(uint256 const& transID) const;
bool getTransaction(uint256 const& transID, Transaction::pointer& txn, TransactionMetaSet::pointer& txMeta);
bool getTransactionMeta(uint256 const& transID, TransactionMetaSet::pointer& txMeta);
bool getMetaHex(uint256 const& transID, std::string& hex);
if (mAccountStateMap)
mAccountStateMap->dropCache ();
}
static SerializedTransaction::pointer getSTransaction(SHAMapItem::ref, SHAMapTreeNode::TNType);
SerializedTransaction::pointer getSMTransaction(SHAMapItem::ref, SHAMapTreeNode::TNType,
TransactionMetaSet::pointer& txMeta);
// ledger sync functions
void setAcquiring (void);
bool isAcquiring (void);
bool isAcquiringTx (void);
bool isAcquiringAS (void);
// high-level functions
bool hasAccount(const RippleAddress& acctID);
AccountState::pointer getAccountState(const RippleAddress& acctID);
LedgerStateParms writeBack(LedgerStateParms parms, SLE::ref);
SLE::pointer getAccountRoot(const uint160& accountID);
SLE::pointer getAccountRoot(const RippleAddress& naAccountID);
void updateSkipList();
void visitAccountItems(const uint160& acctID, FUNCTION_TYPE<void(SLE::ref)>);
// Transaction Functions
bool addTransaction (uint256 const & id, const Serializer & txn);
bool addTransaction (uint256 const & id, const Serializer & txn, const Serializer & metaData);
bool hasTransaction (uint256 const & TransID) const
{
return mTransactionMap->hasItem (TransID);
}
Transaction::pointer getTransaction (uint256 const & transID) const;
bool getTransaction (uint256 const & transID, Transaction::pointer & txn, TransactionMetaSet::pointer & txMeta);
bool getTransactionMeta (uint256 const & transID, TransactionMetaSet::pointer & txMeta);
bool getMetaHex (uint256 const & transID, std::string & hex);
// database functions (low-level)
static Ledger::pointer loadByIndex(uint32 ledgerIndex);
static Ledger::pointer loadByHash(uint256 const& ledgerHash);
static uint256 getHashByIndex(uint32 index);
static bool getHashesByIndex(uint32 index, uint256& ledgerHash, uint256& parentHash);
static std::map< uint32, std::pair<uint256, uint256> > getHashesByIndex(uint32 minSeq, uint32 maxSeq);
void pendSave(bool fromConsensus);
static SerializedTransaction::pointer getSTransaction (SHAMapItem::ref, SHAMapTreeNode::TNType);
SerializedTransaction::pointer getSMTransaction (SHAMapItem::ref, SHAMapTreeNode::TNType,
TransactionMetaSet::pointer & txMeta);
// next/prev function
SLE::pointer getSLE(uint256 const& uHash); // SLE is mutable
SLE::pointer getSLEi(uint256 const& uHash); // SLE is immutable
uint256 getFirstLedgerIndex();
uint256 getLastLedgerIndex();
uint256 getNextLedgerIndex(uint256 const& uHash); // first node >hash
uint256 getNextLedgerIndex(uint256 const& uHash, uint256 const& uEnd); // first node >hash, <end
uint256 getPrevLedgerIndex(uint256 const& uHash); // last node <hash
uint256 getPrevLedgerIndex(uint256 const& uHash, uint256 const& uBegin); // last node <hash, >begin
// high-level functions
bool hasAccount (const RippleAddress & acctID);
AccountState::pointer getAccountState (const RippleAddress & acctID);
LedgerStateParms writeBack (LedgerStateParms parms, SLE::ref);
SLE::pointer getAccountRoot (const uint160 & accountID);
SLE::pointer getAccountRoot (const RippleAddress & naAccountID);
void updateSkipList ();
void visitAccountItems (const uint160 & acctID, FUNCTION_TYPE<void (SLE::ref)>);
// Ledger hash table function
static uint256 getLedgerHashIndex();
static uint256 getLedgerHashIndex(uint32 desiredLedgerIndex);
static int getLedgerHashOffset(uint32 desiredLedgerIndex);
static int getLedgerHashOffset(uint32 desiredLedgerIndex, uint32 currentLedgerIndex);
uint256 getLedgerHash(uint32 ledgerIndex);
std::vector< std::pair<uint32, uint256> > getLedgerHashes();
// database functions (low-level)
static Ledger::pointer loadByIndex (uint32 ledgerIndex);
static Ledger::pointer loadByHash (uint256 const & ledgerHash);
static uint256 getHashByIndex (uint32 index);
static bool getHashesByIndex (uint32 index, uint256 & ledgerHash, uint256 & parentHash);
static std::map< uint32, std::pair<uint256, uint256> > getHashesByIndex (uint32 minSeq, uint32 maxSeq);
void pendSave (bool fromConsensus);
static uint256 getLedgerFeatureIndex();
static uint256 getLedgerFeeIndex();
std::vector<uint256> getLedgerFeatures();
// next/prev function
SLE::pointer getSLE (uint256 const & uHash); // SLE is mutable
SLE::pointer getSLEi (uint256 const & uHash); // SLE is immutable
uint256 getFirstLedgerIndex ();
uint256 getLastLedgerIndex ();
uint256 getNextLedgerIndex (uint256 const & uHash); // first node >hash
uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd); // first node >hash, <end
uint256 getPrevLedgerIndex (uint256 const & uHash); // last node <hash
uint256 getPrevLedgerIndex (uint256 const & uHash, uint256 const & uBegin); // last node <hash, >begin
std::vector<uint256> getNeededTransactionHashes(int max, SHAMapSyncFilter* filter);
std::vector<uint256> getNeededAccountStateHashes(int max, SHAMapSyncFilter* filter);
// Ledger hash table function
static uint256 getLedgerHashIndex ();
static uint256 getLedgerHashIndex (uint32 desiredLedgerIndex);
static int getLedgerHashOffset (uint32 desiredLedgerIndex);
static int getLedgerHashOffset (uint32 desiredLedgerIndex, uint32 currentLedgerIndex);
uint256 getLedgerHash (uint32 ledgerIndex);
std::vector< std::pair<uint32, uint256> > getLedgerHashes ();
// index calculation functions
static uint256 getAccountRootIndex(const uint160& uAccountID);
static uint256 getLedgerFeatureIndex ();
static uint256 getLedgerFeeIndex ();
std::vector<uint256> getLedgerFeatures ();
static uint256 getAccountRootIndex(const RippleAddress& account)
{ return getAccountRootIndex(account.getAccountID()); }
std::vector<uint256> getNeededTransactionHashes (int max, SHAMapSyncFilter * filter);
std::vector<uint256> getNeededAccountStateHashes (int max, SHAMapSyncFilter * filter);
//
// Generator Map functions
//
// index calculation functions
static uint256 getAccountRootIndex (const uint160 & uAccountID);
SLE::pointer getGenerator(const uint160& uGeneratorID);
static uint256 getAccountRootIndex (const RippleAddress & account)
{
return getAccountRootIndex (account.getAccountID ());
}
static uint256 getGeneratorIndex(const uint160& uGeneratorID);
//
// Generator Map functions
//
//
// Nickname functions
//
SLE::pointer getGenerator (const uint160 & uGeneratorID);
static uint256 getNicknameHash(const std::string& strNickname)
{ Serializer s(strNickname); return s.getSHA256(); }
static uint256 getGeneratorIndex (const uint160 & uGeneratorID);
NicknameState::pointer getNicknameState(uint256 const& uNickname);
NicknameState::pointer getNicknameState(const std::string& strNickname)
{ return getNicknameState(getNicknameHash(strNickname)); }
//
// Nickname functions
//
SLE::pointer getNickname(uint256 const& uNickname);
SLE::pointer getNickname(const std::string& strNickname) { return getNickname(getNicknameHash(strNickname)); }
static uint256 getNicknameHash (const std::string & strNickname)
{
Serializer s (strNickname);
return s.getSHA256 ();
}
static uint256 getNicknameIndex(uint256 const& uNickname);
NicknameState::pointer getNicknameState (uint256 const & uNickname);
NicknameState::pointer getNicknameState (const std::string & strNickname)
{
return getNicknameState (getNicknameHash (strNickname));
}
//
// Order book functions
//
SLE::pointer getNickname (uint256 const & uNickname);
SLE::pointer getNickname (const std::string & strNickname)
{
return getNickname (getNicknameHash (strNickname));
}
// 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 getNicknameIndex (uint256 const & uNickname);
static uint256 getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID);
//
// Order book functions
//
//
// Offer functions
//
// 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);
SLE::pointer getOffer(uint256 const& uIndex);
static uint256 getBookBase (const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuerID,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuerID);
SLE::pointer getOffer(const uint160& uAccountID, uint32 uSequence)
{ return getOffer(getOfferIndex(uAccountID, uSequence)); }
//
// Offer functions
//
// The index of an offer.
static uint256 getOfferIndex(const uint160& uAccountID, uint32 uSequence);
SLE::pointer getOffer (uint256 const & uIndex);
//
// Owner functions
//
SLE::pointer getOffer (const uint160 & uAccountID, uint32 uSequence)
{
return getOffer (getOfferIndex (uAccountID, uSequence));
}
// The index of an offer.
static uint256 getOfferIndex (const uint160 & uAccountID, uint32 uSequence);
//
// Owner functions
//
// VFALCO NOTE This is a simple math operation that converts the account ID
// into a 256 bit object (I think....need to research this)
//
// All items controlled by an account are here: offers
static uint256 getOwnerDirIndex(const uint160& uAccountID);
// All items controlled by an account are here: offers
static uint256 getOwnerDirIndex (const uint160 & uAccountID);
//
// Directory functions
// Directories are doubly linked lists of nodes.
//
// Directory functions
// Directories are doubly linked lists of nodes.
// Given a directory root and and index compute the index of a node.
static uint256 getDirNodeIndex(uint256 const& uDirRoot, const uint64 uNodeIndex = 0);
static void ownerDirDescriber(SLE::ref, const uint160& owner);
// Given a directory root and and index compute the index of a node.
static uint256 getDirNodeIndex (uint256 const & uDirRoot, const uint64 uNodeIndex = 0);
static void ownerDirDescriber (SLE::ref, const uint160 & owner);
// Return a node: root or normal
SLE::pointer getDirNode(uint256 const& uNodeIndex);
// Return a node: root or normal
SLE::pointer getDirNode (uint256 const & uNodeIndex);
//
// Quality
//
//
// Quality
//
static uint256 getQualityIndex(uint256 const& uBase, const uint64 uNodeDir = 0);
static uint256 getQualityNext(uint256 const& uBase);
static uint64 getQuality(uint256 const& uBase);
static void qualityDirDescriber(SLE::ref,
const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuer,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuer,
const uint64& uRate);
static uint256 getQualityIndex (uint256 const & uBase, const uint64 uNodeDir = 0);
static uint256 getQualityNext (uint256 const & uBase);
static uint64 getQuality (uint256 const & uBase);
static void qualityDirDescriber (SLE::ref,
const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuer,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuer,
const uint64 & uRate);
//
// Ripple functions : credit lines
//
//
// Ripple functions : credit lines
//
// Index of node which is the ripple state between two accounts for a currency.
static uint256 getRippleStateIndex(const RippleAddress& naA, const RippleAddress& naB, const uint160& uCurrency);
static uint256 getRippleStateIndex(const uint160& uiA, const uint160& uiB, const uint160& uCurrency)
{ return getRippleStateIndex(RippleAddress::createAccountID(uiA), RippleAddress::createAccountID(uiB), uCurrency); }
// Index of node which is the ripple state between two accounts for a currency.
static uint256 getRippleStateIndex (const RippleAddress & naA, const RippleAddress & naB, const uint160 & uCurrency);
static uint256 getRippleStateIndex (const uint160 & uiA, const uint160 & uiB, const uint160 & uCurrency)
{
return getRippleStateIndex (RippleAddress::createAccountID (uiA), RippleAddress::createAccountID (uiB), uCurrency);
}
SLE::pointer getRippleState(uint256 const& uNode);
SLE::pointer getRippleState (uint256 const & uNode);
SLE::pointer getRippleState(const RippleAddress& naA, const RippleAddress& naB, const uint160& uCurrency)
{ return getRippleState(getRippleStateIndex(naA, naB, uCurrency)); }
SLE::pointer getRippleState (const RippleAddress & naA, const RippleAddress & naB, const uint160 & uCurrency)
{
return getRippleState (getRippleStateIndex (naA, naB, uCurrency));
}
SLE::pointer getRippleState(const uint160& uiA, const uint160& uiB, const uint160& uCurrency)
{ return getRippleState(getRippleStateIndex(RippleAddress::createAccountID(uiA), RippleAddress::createAccountID(uiB), uCurrency)); }
SLE::pointer getRippleState (const uint160 & uiA, const uint160 & uiB, const uint160 & uCurrency)
{
return getRippleState (getRippleStateIndex (RippleAddress::createAccountID (uiA), RippleAddress::createAccountID (uiB), uCurrency));
}
uint32 getReferenceFeeUnits()
{
if (!mBaseFee) updateFees();
return mReferenceFeeUnits;
}
uint32 getReferenceFeeUnits ()
{
if (!mBaseFee) updateFees ();
uint64 getBaseFee()
{
if (!mBaseFee) updateFees();
return mBaseFee;
}
return mReferenceFeeUnits;
}
uint64 getReserve(int increments)
{
if (!mBaseFee) updateFees();
return scaleFeeBase(static_cast<uint64>(increments) * mReserveIncrement + mReserveBase);
}
uint64 getBaseFee ()
{
if (!mBaseFee) updateFees ();
uint64 getReserveInc()
{
if (!mBaseFee) updateFees();
return mReserveIncrement;
}
return mBaseFee;
}
uint64 scaleFeeBase(uint64 fee);
uint64 scaleFeeLoad(uint64 fee, bool bAdmin);
uint64 getReserve (int increments)
{
if (!mBaseFee) updateFees ();
return scaleFeeBase (static_cast<uint64> (increments) * mReserveIncrement + mReserveBase);
}
uint64 getReserveInc ()
{
if (!mBaseFee) updateFees ();
return mReserveIncrement;
}
uint64 scaleFeeBase (uint64 fee);
uint64 scaleFeeLoad (uint64 fee, bool bAdmin);
Json::Value getJson(int options);
void addJson(Json::Value&, int options);
Json::Value getJson (int options);
void addJson (Json::Value&, int options);
bool walkLedger();
bool assertSane();
bool walkLedger ();
bool assertSane ();
protected:
SLE::pointer getASNode(LedgerStateParms& parms, uint256 const& nodeID, LedgerEntryType let);
SLE::pointer getASNode (LedgerStateParms & parms, uint256 const & nodeID, LedgerEntryType let);
// returned SLE is immutable
SLE::pointer getASNodeI(uint256 const& nodeID, LedgerEntryType let);
// returned SLE is immutable
SLE::pointer getASNodeI (uint256 const & nodeID, LedgerEntryType let);
void saveAcceptedLedger(Job&, bool fromConsensus);
void saveAcceptedLedger (Job&, bool fromConsensus);
void updateFees();
void updateFees ();
private:
void initializeFees ();
void initializeFees ();
private:
uint256 mHash;
uint256 mParentHash;
uint256 mTransHash;
uint256 mAccountHash;
uint64 mTotCoins;
uint32 mLedgerSeq;
uint32 mCloseTime; // when this ledger closed
uint32 mParentCloseTime; // when the previous ledger closed
int mCloseResolution; // the resolution for this ledger close time (2-120 seconds)
uint32 mCloseFlags; // flags indicating how this ledger close took place
bool mClosed, mValidHash, mAccepted, mImmutable;
uint256 mHash;
uint256 mParentHash;
uint256 mTransHash;
uint256 mAccountHash;
uint64 mTotCoins;
uint32 mLedgerSeq;
uint32 mCloseTime; // when this ledger closed
uint32 mParentCloseTime; // when the previous ledger closed
int mCloseResolution; // the resolution for this ledger close time (2-120 seconds)
uint32 mCloseFlags; // flags indicating how this ledger close took place
bool mClosed, mValidHash, mAccepted, mImmutable;
uint32 mReferenceFeeUnits; // Fee units for the reference transaction
uint32 mReserveBase, mReserveIncrement; // Reserve basse and increment in fee units
uint64 mBaseFee; // Ripple cost of the reference transaction
uint32 mReferenceFeeUnits; // Fee units for the reference transaction
uint32 mReserveBase, mReserveIncrement; // Reserve basse and increment in fee units
uint64 mBaseFee; // Ripple cost of the reference transaction
SHAMap::pointer mTransactionMap;
SHAMap::pointer mTransactionMap;
SHAMap::pointer mAccountStateMap;
mutable boost::recursive_mutex mLock;
mutable boost::recursive_mutex mLock;
// VFALCO TODO derive this from beast::Uncopyable
Ledger(const Ledger&); // no implementation
Ledger& operator=(const Ledger&); // no implementation
Ledger (const Ledger&); // no implementation
Ledger& operator= (const Ledger&); // no implementation
};
inline LedgerStateParms operator|(const LedgerStateParms& l1, const LedgerStateParms& l2)
inline LedgerStateParms operator| (const LedgerStateParms& l1, const LedgerStateParms& l2)
{
return static_cast<LedgerStateParms>(static_cast<int>(l1) | static_cast<int>(l2));
return static_cast<LedgerStateParms> (static_cast<int> (l1) | static_cast<int> (l2));
}
inline LedgerStateParms operator&(const LedgerStateParms& l1, const LedgerStateParms& l2)
inline LedgerStateParms operator& (const LedgerStateParms& l1, const LedgerStateParms& l2)
{
return static_cast<LedgerStateParms>(static_cast<int>(l1) & static_cast<int>(l2));
return static_cast<LedgerStateParms> (static_cast<int> (l1) & static_cast<int> (l2));
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,45 @@
#ifndef __LEDGERENTRYSET__
#define __LEDGERENTRYSET__
DEFINE_INSTANCE(LedgerEntrySetEntry);
DEFINE_INSTANCE(LedgerEntrySet);
DEFINE_INSTANCE (LedgerEntrySetEntry);
DEFINE_INSTANCE (LedgerEntrySet);
enum TransactionEngineParams
{
tapNONE = 0x00,
tapNONE = 0x00,
tapNO_CHECK_SIGN = 0x01, // Signature already checked
tapNO_CHECK_SIGN = 0x01, // Signature already checked
tapOPEN_LEDGER = 0x10, // Transaction is running against an open ledger
// true = failures are not forwarded, check transaction fee
// false = debit ledger for consumed funds
tapOPEN_LEDGER = 0x10, // Transaction is running against an open ledger
// true = failures are not forwarded, check transaction fee
// false = debit ledger for consumed funds
tapRETRY = 0x20, // This is not the transaction's last pass
// Transaction can be retried, soft failures allowed
tapRETRY = 0x20, // This is not the transaction's last pass
// Transaction can be retried, soft failures allowed
tapADMIN = 0x400, // Transaction came from a privileged source
tapADMIN = 0x400, // Transaction came from a privileged source
};
enum LedgerEntryAction
{
taaNONE,
taaCACHED, // Unmodified.
taaMODIFY, // Modifed, must have previously been taaCACHED.
taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY.
taaCREATE, // Newly created.
taaNONE,
taaCACHED, // Unmodified.
taaMODIFY, // Modifed, must have previously been taaCACHED.
taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY.
taaCREATE, // Newly created.
};
class LedgerEntrySetEntry : private IS_INSTANCE(LedgerEntrySetEntry)
class LedgerEntrySetEntry : private IS_INSTANCE (LedgerEntrySetEntry)
{
public:
SLE::pointer mEntry;
LedgerEntryAction mAction;
int mSeq;
SLE::pointer mEntry;
LedgerEntryAction mAction;
int mSeq;
LedgerEntrySetEntry(SLE::ref e, LedgerEntryAction a, int s) : mEntry(e), mAction(a), mSeq(s) { ; }
LedgerEntrySetEntry (SLE::ref e, LedgerEntryAction a, int s) : mEntry (e), mAction (a), mSeq (s)
{
;
}
};
/** An LES is a LedgerEntrySet.
@@ -47,148 +50,213 @@ public:
transaction finishes, the LES is committed into the ledger to make
the modifications. The transaction metadata is built from the LES too.
*/
class LedgerEntrySet : private IS_INSTANCE(LedgerEntrySet)
class LedgerEntrySet : private IS_INSTANCE (LedgerEntrySet)
{
public:
LedgerEntrySet(Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false) :
mLedger(ledger), mParams(tep), mSeq(0), mImmutable(immutable) { ; }
LedgerEntrySet (Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false) :
mLedger (ledger), mParams (tep), mSeq (0), mImmutable (immutable)
{
;
}
LedgerEntrySet() : mParams(tapNONE), mSeq(0), mImmutable(false) { ; }
LedgerEntrySet () : mParams (tapNONE), mSeq (0), mImmutable (false)
{
;
}
// set functions
void setImmutable() { mImmutable = true; }
bool isImmutable() const { return mImmutable; }
LedgerEntrySet duplicate() const; // Make a duplicate of this set
void setTo(const LedgerEntrySet&); // Set this set to have the same contents as another
void swapWith(LedgerEntrySet&); // Swap the contents of two sets
void invalidate() { mLedger.reset(); }
bool isValid() const { return !!mLedger; }
// set functions
void setImmutable ()
{
mImmutable = true;
}
bool isImmutable () const
{
return mImmutable;
}
LedgerEntrySet duplicate () const; // Make a duplicate of this set
void setTo (const LedgerEntrySet&); // Set this set to have the same contents as another
void swapWith (LedgerEntrySet&); // Swap the contents of two sets
void invalidate ()
{
mLedger.reset ();
}
bool isValid () const
{
return !!mLedger;
}
int getSeq() const { return mSeq; }
TransactionEngineParams getParams() const { return mParams; }
void bumpSeq() { ++mSeq; }
void init(Ledger::ref ledger, uint256 const& transactionID, uint32 ledgerID, TransactionEngineParams params);
void clear();
int getSeq () const
{
return mSeq;
}
TransactionEngineParams getParams () const
{
return mParams;
}
void bumpSeq ()
{
++mSeq;
}
void init (Ledger::ref ledger, uint256 const & transactionID, uint32 ledgerID, TransactionEngineParams params);
void clear ();
Ledger::pointer& getLedger() { return mLedger; }
Ledger::ref getLedgerRef() const { return mLedger; }
Ledger::pointer& getLedger ()
{
return mLedger;
}
Ledger::ref getLedgerRef () const
{
return mLedger;
}
// basic entry functions
SLE::pointer getEntry(uint256 const& index, LedgerEntryAction&);
LedgerEntryAction hasEntry(uint256 const& index) const;
void entryCache(SLE::ref); // Add this entry to the cache
void entryCreate(SLE::ref); // This entry will be created
void entryDelete(SLE::ref); // This entry will be deleted
void entryModify(SLE::ref); // This entry will be modified
bool hasChanges(); // True if LES has any changes
// basic entry functions
SLE::pointer getEntry (uint256 const & index, LedgerEntryAction&);
LedgerEntryAction hasEntry (uint256 const & index) const;
void entryCache (SLE::ref); // Add this entry to the cache
void entryCreate (SLE::ref); // This entry will be created
void entryDelete (SLE::ref); // This entry will be deleted
void entryModify (SLE::ref); // This entry will be modified
bool hasChanges (); // True if LES has any changes
// higher-level ledger functions
SLE::pointer entryCreate(LedgerEntryType letType, uint256 const& uIndex);
SLE::pointer entryCache(LedgerEntryType letType, uint256 const& uIndex);
// higher-level ledger functions
SLE::pointer entryCreate (LedgerEntryType letType, uint256 const & uIndex);
SLE::pointer entryCache (LedgerEntryType letType, uint256 const & uIndex);
// Directory functions.
TER dirAdd(
uint64& uNodeDir, // Node of entry.
uint256 const& uRootIndex,
uint256 const& uLedgerIndex,
FUNCTION_TYPE<void (SLE::ref)> fDescriber);
// Directory functions.
TER dirAdd (
uint64 & uNodeDir, // Node of entry.
uint256 const & uRootIndex,
uint256 const & uLedgerIndex,
FUNCTION_TYPE<void (SLE::ref)> fDescriber);
TER dirDelete(
const bool bKeepRoot,
const uint64& uNodeDir, // Node item is mentioned in.
uint256 const& uRootIndex,
uint256 const& uLedgerIndex, // Item being deleted
const bool bStable,
const bool bSoft);
TER dirDelete (
const bool bKeepRoot,
const uint64 & uNodeDir, // Node item is mentioned in.
uint256 const & uRootIndex,
uint256 const & uLedgerIndex, // Item being deleted
const bool bStable,
const bool bSoft);
bool dirFirst(uint256 const& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
bool dirNext(uint256 const& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
TER dirCount(uint256 const& uDirIndex, uint32& uCount);
bool dirFirst (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirNext (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
TER dirCount (uint256 const & uDirIndex, uint32 & uCount);
uint256 getNextLedgerIndex(uint256 const& uHash);
uint256 getNextLedgerIndex(uint256 const& uHash, uint256 const& uEnd);
uint256 getNextLedgerIndex (uint256 const & uHash);
uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd);
void ownerCountAdjust(const uint160& uOwnerID, int iAmount, SLE::ref sleAccountRoot=SLE::pointer());
void ownerCountAdjust (const uint160 & uOwnerID, int iAmount, SLE::ref sleAccountRoot = SLE::pointer ());
// Offer functions.
TER offerDelete(uint256 const& uOfferIndex);
TER offerDelete(SLE::ref sleOffer, uint256 const& uOfferIndex, const uint160& uOwnerID);
// Offer functions.
TER offerDelete (uint256 const & uOfferIndex);
TER offerDelete (SLE::ref sleOffer, uint256 const & uOfferIndex, const uint160 & uOwnerID);
// Balance functions.
uint32 rippleTransferRate(const uint160& uIssuerID);
uint32 rippleTransferRate(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID);
STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID,
SField::ref sfLow = sfLowQualityIn, SField::ref sfHigh = sfHighQualityIn);
uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
{ return rippleQualityIn(uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut); }
// Balance functions.
uint32 rippleTransferRate (const uint160 & uIssuerID);
uint32 rippleTransferRate (const uint160 & uSenderID, const uint160 & uReceiverID, const uint160 & uIssuerID);
STAmount rippleOwed (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID);
STAmount rippleLimit (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID);
uint32 rippleQualityIn (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID,
SField::ref sfLow = sfLowQualityIn, SField::ref sfHigh = sfHighQualityIn);
uint32 rippleQualityOut (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID)
{
return rippleQualityIn (uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut);
}
STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
STAmount rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount);
TER rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer=true);
TER rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, STAmount& saActual);
STAmount rippleHolds (const uint160 & uAccountID, const uint160 & uCurrencyID, const uint160 & uIssuerID);
STAmount rippleTransferFee (const uint160 & uSenderID, const uint160 & uReceiverID, const uint160 & uIssuerID, const STAmount & saAmount);
TER rippleCredit (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount, bool bCheckIssuer = true);
TER rippleSend (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount, STAmount & saActual);
STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault);
TER accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount);
STAmount accountHolds (const uint160 & uAccountID, const uint160 & uCurrencyID, const uint160 & uIssuerID);
STAmount accountFunds (const uint160 & uAccountID, const STAmount & saDefault);
TER accountSend (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount);
TER trustCreate(
const bool bSrcHigh,
const uint160& uSrcAccountID,
const uint160& uDstAccountID,
uint256 const& uIndex,
SLE::ref sleAccount,
const bool bAuth,
const STAmount& saSrcBalance,
const STAmount& saSrcLimit,
const uint32 uSrcQualityIn = 0,
const uint32 uSrcQualityOut = 0);
TER trustDelete(SLE::ref sleRippleState, const uint160& uLowAccountID, const uint160& uHighAccountID);
TER trustCreate (
const bool bSrcHigh,
const uint160 & uSrcAccountID,
const uint160 & uDstAccountID,
uint256 const & uIndex,
SLE::ref sleAccount,
const bool bAuth,
const STAmount & saSrcBalance,
const STAmount & saSrcLimit,
const uint32 uSrcQualityIn = 0,
const uint32 uSrcQualityOut = 0);
TER trustDelete (SLE::ref sleRippleState, const uint160 & uLowAccountID, const uint160 & uHighAccountID);
Json::Value getJson(int) const;
void calcRawMeta(Serializer&, TER result, uint32 index);
Json::Value getJson (int) const;
void calcRawMeta (Serializer&, TER result, uint32 index);
// iterator functions
typedef std::map<uint256, LedgerEntrySetEntry>::iterator iterator;
typedef std::map<uint256, LedgerEntrySetEntry>::const_iterator const_iterator;
bool isEmpty() const { return mEntries.empty(); }
std::map<uint256, LedgerEntrySetEntry>::const_iterator begin() const { return mEntries.begin(); }
std::map<uint256, LedgerEntrySetEntry>::const_iterator end() const { return mEntries.end(); }
std::map<uint256, LedgerEntrySetEntry>::iterator begin() { return mEntries.begin(); }
std::map<uint256, LedgerEntrySetEntry>::iterator end() { return mEntries.end(); }
// iterator functions
typedef std::map<uint256, LedgerEntrySetEntry>::iterator iterator;
typedef std::map<uint256, LedgerEntrySetEntry>::const_iterator const_iterator;
bool isEmpty () const
{
return mEntries.empty ();
}
std::map<uint256, LedgerEntrySetEntry>::const_iterator begin () const
{
return mEntries.begin ();
}
std::map<uint256, LedgerEntrySetEntry>::const_iterator end () const
{
return mEntries.end ();
}
std::map<uint256, LedgerEntrySetEntry>::iterator begin ()
{
return mEntries.begin ();
}
std::map<uint256, LedgerEntrySetEntry>::iterator end ()
{
return mEntries.end ();
}
static bool intersect(const LedgerEntrySet& lesLeft, const LedgerEntrySet& lesRight);
static bool intersect (const LedgerEntrySet & lesLeft, const LedgerEntrySet & lesRight);
private:
Ledger::pointer mLedger;
std::map<uint256, LedgerEntrySetEntry> mEntries; // cannot be unordered!
TransactionMetaSet mSet;
TransactionEngineParams mParams;
int mSeq;
bool mImmutable;
Ledger::pointer mLedger;
std::map<uint256, LedgerEntrySetEntry> mEntries; // cannot be unordered!
TransactionMetaSet mSet;
TransactionEngineParams mParams;
int mSeq;
bool mImmutable;
LedgerEntrySet(Ledger::ref ledger, const std::map<uint256, LedgerEntrySetEntry> &e,
const TransactionMetaSet& s, int m) :
mLedger(ledger), mEntries(e), mSet(s), mParams(tapNONE), mSeq(m), mImmutable(false) { ; }
LedgerEntrySet (Ledger::ref ledger, const std::map<uint256, LedgerEntrySetEntry>& e,
const TransactionMetaSet & s, int m) :
mLedger (ledger), mEntries (e), mSet (s), mParams (tapNONE), mSeq (m), mImmutable (false)
{
;
}
SLE::pointer getForMod(uint256 const& node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
SLE::pointer getForMod (uint256 const & node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(const RippleAddress& threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx (const RippleAddress & threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx (SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners (SLE::ref node, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
};
inline LedgerEntrySet::iterator range_begin(LedgerEntrySet& x) { return x.begin(); }
inline LedgerEntrySet::iterator range_end(LedgerEntrySet &x) { return x.end(); }
inline LedgerEntrySet::iterator range_begin (LedgerEntrySet& x)
{
return x.begin ();
}
inline LedgerEntrySet::iterator range_end (LedgerEntrySet& x)
{
return x.end ();
}
namespace boost
{
template<> struct range_mutable_iterator<LedgerEntrySet> { typedef LedgerEntrySet::iterator type; };
template<> struct range_const_iterator<LedgerEntrySet> { typedef LedgerEntrySet::const_iterator type; };
template<> struct range_mutable_iterator<LedgerEntrySet>
{
typedef LedgerEntrySet::iterator type;
};
template<> struct range_const_iterator<LedgerEntrySet>
{
typedef LedgerEntrySet::const_iterator type;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -11,11 +11,11 @@
class LedgerMaster
{
public:
typedef FUNCTION_TYPE <void(Ledger::ref)> callback;
typedef FUNCTION_TYPE <void (Ledger::ref)> callback;
public:
LedgerMaster ()
: mHeldTransactions (uint256())
LedgerMaster ()
: mHeldTransactions (uint256 ())
, mMissingSeq (0)
, mMinValidations (0)
, mLastValidateSeq (0)
@@ -23,153 +23,188 @@ public:
, mPathFindThread (false)
, mPathFindNewLedger (false)
, mPathFindNewRequest (false)
{
{
}
uint32 getCurrentLedgerIndex();
uint32 getCurrentLedgerIndex ();
ScopedLock getLock() { return ScopedLock(mLock); }
ScopedLock getLock ()
{
return ScopedLock (mLock);
}
// The current ledger is the ledger we believe new transactions should go in
Ledger::ref getCurrentLedger() { return mCurrentLedger; }
// The current ledger is the ledger we believe new transactions should go in
Ledger::ref getCurrentLedger ()
{
return mCurrentLedger;
}
// An immutable snapshot of the current ledger
Ledger::ref getCurrentSnapshot();
// An immutable snapshot of the current ledger
Ledger::ref getCurrentSnapshot ();
// The finalized ledger is the last closed/accepted ledger
Ledger::ref getClosedLedger() { return mFinalizedLedger; }
// The finalized ledger is the last closed/accepted ledger
Ledger::ref getClosedLedger ()
{
return mFinalizedLedger;
}
// The published ledger is the last fully validated ledger
Ledger::ref getValidatedLedger() { return mPubLedger; }
int getValidatedLedgerAge();
// The published ledger is the last fully validated ledger
Ledger::ref getValidatedLedger ()
{
return mPubLedger;
}
int getValidatedLedgerAge ();
TER doTransaction(SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply);
TER doTransaction (SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply);
int getMinValidations() { return mMinValidations; }
void setMinValidations(int v) { mMinValidations = v; }
int getMinValidations ()
{
return mMinValidations;
}
void setMinValidations (int v)
{
mMinValidations = v;
}
void pushLedger(Ledger::pointer newLedger);
void pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL, bool fromConsensus);
void storeLedger(Ledger::pointer);
void pushLedger (Ledger::pointer newLedger);
void pushLedger (Ledger::pointer newLCL, Ledger::pointer newOL, bool fromConsensus);
void storeLedger (Ledger::pointer);
void setFullLedger(Ledger::pointer ledger);
void setFullLedger (Ledger::pointer ledger);
void switchLedgers(Ledger::pointer lastClosed, Ledger::pointer newCurrent);
void switchLedgers (Ledger::pointer lastClosed, Ledger::pointer newCurrent);
std::string getCompleteLedgers()
{
boost::recursive_mutex::scoped_lock sl(mLock);
return mCompleteLedgers.toString();
}
std::string getCompleteLedgers ()
{
boost::recursive_mutex::scoped_lock sl (mLock);
return mCompleteLedgers.toString ();
}
Ledger::pointer closeLedger(bool recoverHeldTransactions);
Ledger::pointer closeLedger (bool recoverHeldTransactions);
uint256 getHashBySeq(uint32 index)
{
uint256 hash = mLedgerHistory.getLedgerHash(index);
if (hash.isNonZero())
return hash;
return Ledger::getHashByIndex(index);
}
uint256 getHashBySeq (uint32 index)
{
uint256 hash = mLedgerHistory.getLedgerHash (index);
Ledger::pointer getLedgerBySeq(uint32 index)
{
if (mCurrentLedger && (mCurrentLedger->getLedgerSeq() == index))
return mCurrentLedger;
if (mFinalizedLedger && (mFinalizedLedger->getLedgerSeq() == index))
return mFinalizedLedger;
Ledger::pointer ret = mLedgerHistory.getLedgerBySeq(index);
if (ret)
return ret;
if (hash.isNonZero ())
return hash;
boost::recursive_mutex::scoped_lock ml(mLock);
mCompleteLedgers.clearValue(index);
return ret;
}
return Ledger::getHashByIndex (index);
}
Ledger::pointer getLedgerByHash(uint256 const& hash)
{
if (hash.isZero())
return boost::make_shared<Ledger>(boost::ref(*mCurrentLedger), false);
Ledger::pointer getLedgerBySeq (uint32 index)
{
if (mCurrentLedger && (mCurrentLedger->getLedgerSeq () == index))
return mCurrentLedger;
if (mCurrentLedger && (mCurrentLedger->getHash() == hash))
return boost::make_shared<Ledger>(boost::ref(*mCurrentLedger), false);
if (mFinalizedLedger && (mFinalizedLedger->getLedgerSeq () == index))
return mFinalizedLedger;
if (mFinalizedLedger && (mFinalizedLedger->getHash() == hash))
return mFinalizedLedger;
Ledger::pointer ret = mLedgerHistory.getLedgerBySeq (index);
return mLedgerHistory.getLedgerByHash(hash);
}
if (ret)
return ret;
void setLedgerRangePresent(uint32 minV, uint32 maxV)
{
boost::recursive_mutex::scoped_lock sl(mLock);
mCompleteLedgers.setRange(minV, maxV);
}
boost::recursive_mutex::scoped_lock ml (mLock);
mCompleteLedgers.clearValue (index);
return ret;
}
void addHeldTransaction(Transaction::ref trans);
void fixMismatch(Ledger::ref ledger);
Ledger::pointer getLedgerByHash (uint256 const& hash)
{
if (hash.isZero ())
return boost::make_shared<Ledger> (boost::ref (*mCurrentLedger), false);
bool haveLedgerRange(uint32 from, uint32 to);
bool haveLedger(uint32 seq);
bool getValidatedRange(uint32& minVal, uint32& maxVal);
if (mCurrentLedger && (mCurrentLedger->getHash () == hash))
return boost::make_shared<Ledger> (boost::ref (*mCurrentLedger), false);
void resumeAcquiring();
if (mFinalizedLedger && (mFinalizedLedger->getHash () == hash))
return mFinalizedLedger;
void tune(int size, int age) { mLedgerHistory.tune(size, age); }
void sweep() { mLedgerHistory.sweep(); }
float getCacheHitRate() { return mLedgerHistory.getCacheHitRate(); }
return mLedgerHistory.getLedgerByHash (hash);
}
void addValidateCallback(callback& c) { mOnValidate.push_back(c); }
void setLedgerRangePresent (uint32 minV, uint32 maxV)
{
boost::recursive_mutex::scoped_lock sl (mLock);
mCompleteLedgers.setRange (minV, maxV);
}
void checkAccept(uint256 const& hash);
void checkAccept(uint256 const& hash, uint32 seq);
void tryPublish();
void newPathRequest();
void addHeldTransaction (Transaction::ref trans);
void fixMismatch (Ledger::ref ledger);
static bool shouldAcquire(uint32 currentLedgerID, uint32 ledgerHistory, uint32 targetLedger);
bool haveLedgerRange (uint32 from, uint32 to);
bool haveLedger (uint32 seq);
bool getValidatedRange (uint32& minVal, uint32& maxVal);
void resumeAcquiring ();
void tune (int size, int age)
{
mLedgerHistory.tune (size, age);
}
void sweep ()
{
mLedgerHistory.sweep ();
}
float getCacheHitRate ()
{
return mLedgerHistory.getCacheHitRate ();
}
void addValidateCallback (callback& c)
{
mOnValidate.push_back (c);
}
void checkAccept (uint256 const& hash);
void checkAccept (uint256 const& hash, uint32 seq);
void tryPublish ();
void newPathRequest ();
static bool shouldAcquire (uint32 currentLedgerID, uint32 ledgerHistory, uint32 targetLedger);
private:
void applyFutureTransactions(uint32 ledgerIndex);
bool isValidTransaction(Transaction::ref trans);
bool isTransactionOnFutureList(Transaction::ref trans);
void applyFutureTransactions (uint32 ledgerIndex);
bool isValidTransaction (Transaction::ref trans);
bool isTransactionOnFutureList (Transaction::ref trans);
bool acquireMissingLedger(Ledger::ref from, uint256 const& ledgerHash, uint32 ledgerSeq);
void asyncAccept(Ledger::pointer);
void missingAcquireComplete(LedgerAcquire::pointer);
void pubThread();
void updatePaths();
bool acquireMissingLedger (Ledger::ref from, uint256 const& ledgerHash, uint32 ledgerSeq);
void asyncAccept (Ledger::pointer);
void missingAcquireComplete (LedgerAcquire::pointer);
void pubThread ();
void updatePaths ();
private:
boost::recursive_mutex mLock;
TransactionEngine mEngine;
TransactionEngine mEngine;
Ledger::pointer mCurrentLedger; // The ledger we are currently processiong
Ledger::pointer mCurrentSnapshot; // Snapshot of the current ledger
Ledger::pointer mFinalizedLedger; // The ledger that most recently closed
Ledger::pointer mValidLedger; // The highest-sequence ledger we have fully accepted
Ledger::pointer mPubLedger; // The last ledger we have published
Ledger::pointer mCurrentLedger; // The ledger we are currently processiong
Ledger::pointer mCurrentSnapshot; // Snapshot of the current ledger
Ledger::pointer mFinalizedLedger; // The ledger that most recently closed
Ledger::pointer mValidLedger; // The highest-sequence ledger we have fully accepted
Ledger::pointer mPubLedger; // The last ledger we have published
LedgerHistory mLedgerHistory;
LedgerHistory mLedgerHistory;
CanonicalTXSet mHeldTransactions;
CanonicalTXSet mHeldTransactions;
RangeSet mCompleteLedgers;
LedgerAcquire::pointer mMissingLedger;
uint32 mMissingSeq;
RangeSet mCompleteLedgers;
LedgerAcquire::pointer mMissingLedger;
uint32 mMissingSeq;
int mMinValidations; // The minimum validations to publish a ledger
uint256 mLastValidateHash;
uint32 mLastValidateSeq;
std::list<callback> mOnValidate; // Called when a ledger has enough validations
int mMinValidations; // The minimum validations to publish a ledger
uint256 mLastValidateHash;
uint32 mLastValidateSeq;
std::list<callback> mOnValidate; // Called when a ledger has enough validations
std::list<Ledger::pointer> mPubLedgers; // List of ledgers to publish
bool mPubThread; // Publish thread is running
std::list<Ledger::pointer> mPubLedgers; // List of ledgers to publish
bool mPubThread; // Publish thread is running
bool mPathFindThread; // Pathfind thread is running
bool mPathFindNewLedger;
bool mPathFindNewRequest;
bool mPathFindThread; // Pathfind thread is running
bool mPathFindNewLedger;
bool mPathFindNewRequest;
};
#endif

View File

@@ -1,100 +1,100 @@
DECLARE_INSTANCE(LedgerProposal);
DECLARE_INSTANCE (LedgerProposal);
LedgerProposal::LedgerProposal(uint256 const& pLgr, uint32 seq, uint256 const& tx, uint32 closeTime,
const RippleAddress& naPeerPublic, uint256 const& suppression) :
mPreviousLedger(pLgr), mCurrentHash(tx), mSuppression(suppression), mCloseTime(closeTime),
mProposeSeq(seq), mPublicKey(naPeerPublic)
LedgerProposal::LedgerProposal (uint256 const& pLgr, uint32 seq, uint256 const& tx, uint32 closeTime,
const RippleAddress& naPeerPublic, uint256 const& suppression) :
mPreviousLedger (pLgr), mCurrentHash (tx), mSuppression (suppression), mCloseTime (closeTime),
mProposeSeq (seq), mPublicKey (naPeerPublic)
{
// XXX Validate key.
// if (!mKey->SetPubKey(pubKey))
// throw std::runtime_error("Invalid public key in proposal");
// XXX Validate key.
// if (!mKey->SetPubKey(pubKey))
// throw std::runtime_error("Invalid public key in proposal");
mPeerID = mPublicKey.getNodeID();
mTime = boost::posix_time::second_clock::universal_time();
mPeerID = mPublicKey.getNodeID ();
mTime = boost::posix_time::second_clock::universal_time ();
}
LedgerProposal::LedgerProposal(const RippleAddress& naPub, const RippleAddress& naPriv,
uint256 const& prevLgr, uint256 const& position, uint32 closeTime) :
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0),
mPublicKey(naPub), mPrivateKey(naPriv)
LedgerProposal::LedgerProposal (const RippleAddress& naPub, const RippleAddress& naPriv,
uint256 const& prevLgr, uint256 const& position, uint32 closeTime) :
mPreviousLedger (prevLgr), mCurrentHash (position), mCloseTime (closeTime), mProposeSeq (0),
mPublicKey (naPub), mPrivateKey (naPriv)
{
mPeerID = mPublicKey.getNodeID();
mTime = boost::posix_time::second_clock::universal_time();
mPeerID = mPublicKey.getNodeID ();
mTime = boost::posix_time::second_clock::universal_time ();
}
LedgerProposal::LedgerProposal(uint256 const& prevLgr, uint256 const& position, uint32 closeTime) :
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0)
LedgerProposal::LedgerProposal (uint256 const& prevLgr, uint256 const& position, uint32 closeTime) :
mPreviousLedger (prevLgr), mCurrentHash (position), mCloseTime (closeTime), mProposeSeq (0)
{
mTime = boost::posix_time::second_clock::universal_time();
mTime = boost::posix_time::second_clock::universal_time ();
}
uint256 LedgerProposal::getSigningHash() const
uint256 LedgerProposal::getSigningHash () const
{
Serializer s((32 + 32 + 32 + 256 + 256) / 8);
Serializer s ((32 + 32 + 32 + 256 + 256) / 8);
s.add32(theConfig.SIGN_PROPOSAL);
s.add32(mProposeSeq);
s.add32(mCloseTime);
s.add256(mPreviousLedger);
s.add256(mCurrentHash);
s.add32 (theConfig.SIGN_PROPOSAL);
s.add32 (mProposeSeq);
s.add32 (mCloseTime);
s.add256 (mPreviousLedger);
s.add256 (mCurrentHash);
return s.getSHA512Half();
return s.getSHA512Half ();
}
bool LedgerProposal::checkSign(const std::string& signature, uint256 const& signingHash)
bool LedgerProposal::checkSign (const std::string& signature, uint256 const& signingHash)
{
return mPublicKey.verifyNodePublic(signingHash, signature);
return mPublicKey.verifyNodePublic (signingHash, signature);
}
bool LedgerProposal::changePosition(uint256 const& newPosition, uint32 closeTime)
bool LedgerProposal::changePosition (uint256 const& newPosition, uint32 closeTime)
{
if (mProposeSeq == seqLeave)
return false;
if (mProposeSeq == seqLeave)
return false;
mCurrentHash = newPosition;
mCloseTime = closeTime;
mTime = boost::posix_time::second_clock::universal_time();
++mProposeSeq;
return true;
mCurrentHash = newPosition;
mCloseTime = closeTime;
mTime = boost::posix_time::second_clock::universal_time ();
++mProposeSeq;
return true;
}
void LedgerProposal::bowOut()
void LedgerProposal::bowOut ()
{
mTime = boost::posix_time::second_clock::universal_time();
mProposeSeq = seqLeave;
mTime = boost::posix_time::second_clock::universal_time ();
mProposeSeq = seqLeave;
}
Blob LedgerProposal::sign(void)
Blob LedgerProposal::sign (void)
{
Blob ret;
Blob ret;
mPrivateKey.signNodePrivate(getSigningHash(), ret);
// XXX If this can fail, find out sooner.
// if (!mPrivateKey.signNodePrivate(getSigningHash(), ret))
// throw std::runtime_error("unable to sign proposal");
mPrivateKey.signNodePrivate (getSigningHash (), ret);
// XXX If this can fail, find out sooner.
// if (!mPrivateKey.signNodePrivate(getSigningHash(), ret))
// throw std::runtime_error("unable to sign proposal");
return ret;
return ret;
}
Json::Value LedgerProposal::getJson() const
Json::Value LedgerProposal::getJson () const
{
Json::Value ret = Json::objectValue;
ret["previous_ledger"] = mPreviousLedger.GetHex();
Json::Value ret = Json::objectValue;
ret["previous_ledger"] = mPreviousLedger.GetHex ();
if (mProposeSeq != seqLeave)
{
ret["transaction_hash"] = mCurrentHash.GetHex();
ret["propose_seq"] = mProposeSeq;
}
if (mProposeSeq != seqLeave)
{
ret["transaction_hash"] = mCurrentHash.GetHex ();
ret["propose_seq"] = mProposeSeq;
}
ret["close_time"] = mCloseTime;
ret["close_time"] = mCloseTime;
if (mPublicKey.isValid())
ret["peer_id"] = mPublicKey.humanNodePublic();
if (mPublicKey.isValid ())
ret["peer_id"] = mPublicKey.humanNodePublic ();
return ret;
return ret;
}
// vim:ts=4

View File

@@ -1,65 +1,116 @@
#ifndef __PROPOSELEDGER__
#define __PROPOSELEDGER__
DEFINE_INSTANCE(LedgerProposal);
DEFINE_INSTANCE (LedgerProposal);
class LedgerProposal : private IS_INSTANCE(LedgerProposal)
class LedgerProposal : private IS_INSTANCE (LedgerProposal)
{
public:
static const uint32 seqLeave = 0xffffffff; // leaving the consensus process
static const uint32 seqLeave = 0xffffffff; // leaving the consensus process
typedef boost::shared_ptr<LedgerProposal> pointer;
typedef const pointer& ref;
typedef boost::shared_ptr<LedgerProposal> pointer;
typedef const pointer& ref;
// proposal from peer
LedgerProposal(uint256 const& prevLgr, uint32 proposeSeq, uint256 const& propose,
uint32 closeTime, const RippleAddress& naPeerPublic, uint256 const& suppress);
// proposal from peer
LedgerProposal (uint256 const & prevLgr, uint32 proposeSeq, uint256 const & propose,
uint32 closeTime, const RippleAddress & naPeerPublic, uint256 const & suppress);
// our first proposal
LedgerProposal(const RippleAddress& pubKey, const RippleAddress& privKey,
uint256 const& prevLedger, uint256 const& position, uint32 closeTime);
// our first proposal
LedgerProposal (const RippleAddress & pubKey, const RippleAddress & privKey,
uint256 const & prevLedger, uint256 const & position, uint32 closeTime);
// an unsigned "dummy" proposal for nodes not validating
LedgerProposal(uint256 const& prevLedger, uint256 const& position, uint32 closeTime);
// an unsigned "dummy" proposal for nodes not validating
LedgerProposal (uint256 const & prevLedger, uint256 const & position, uint32 closeTime);
uint256 getSigningHash() const;
bool checkSign(const std::string& signature, uint256 const& signingHash);
bool checkSign(const std::string& signature) { return checkSign(signature, getSigningHash()); }
bool checkSign() { return checkSign(mSignature, getSigningHash()); }
uint256 getSigningHash () const;
bool checkSign (const std::string & signature, uint256 const & signingHash);
bool checkSign (const std::string & signature)
{
return checkSign (signature, getSigningHash ());
}
bool checkSign ()
{
return checkSign (mSignature, getSigningHash ());
}
const uint160& getPeerID() const { return mPeerID; }
uint256 const& getCurrentHash() const { return mCurrentHash; }
uint256 const& getPrevLedger() const { return mPreviousLedger; }
uint256 const& getHashRouter() const { return mSuppression; }
uint32 getProposeSeq() const { return mProposeSeq; }
uint32 getCloseTime() const { return mCloseTime; }
const RippleAddress& peekPublic() const { return mPublicKey; }
Blob getPubKey() const { return mPublicKey.getNodePublic(); }
Blob sign();
const uint160& getPeerID () const
{
return mPeerID;
}
uint256 const& getCurrentHash () const
{
return mCurrentHash;
}
uint256 const& getPrevLedger () const
{
return mPreviousLedger;
}
uint256 const& getHashRouter () const
{
return mSuppression;
}
uint32 getProposeSeq () const
{
return mProposeSeq;
}
uint32 getCloseTime () const
{
return mCloseTime;
}
const RippleAddress& peekPublic () const
{
return mPublicKey;
}
Blob getPubKey () const
{
return mPublicKey.getNodePublic ();
}
Blob sign ();
void setPrevLedger(uint256 const& prevLedger) { mPreviousLedger = prevLedger; }
void setSignature(const std::string& signature) { mSignature = signature; }
bool hasSignature() { return !mSignature.empty(); }
bool isPrevLedger(uint256 const& pl) { return mPreviousLedger == pl; }
bool isBowOut() { return mProposeSeq == seqLeave; }
void setPrevLedger (uint256 const & prevLedger)
{
mPreviousLedger = prevLedger;
}
void setSignature (const std::string & signature)
{
mSignature = signature;
}
bool hasSignature ()
{
return !mSignature.empty ();
}
bool isPrevLedger (uint256 const & pl)
{
return mPreviousLedger == pl;
}
bool isBowOut ()
{
return mProposeSeq == seqLeave;
}
const boost::posix_time::ptime getCreateTime() { return mTime; }
bool isStale(boost::posix_time::ptime cutoff) { return mTime <= cutoff; }
const boost::posix_time::ptime getCreateTime ()
{
return mTime;
}
bool isStale (boost::posix_time::ptime cutoff)
{
return mTime <= cutoff;
}
bool changePosition(uint256 const& newPosition, uint32 newCloseTime);
void bowOut();
Json::Value getJson() const;
bool changePosition (uint256 const & newPosition, uint32 newCloseTime);
void bowOut ();
Json::Value getJson () const;
private:
uint256 mPreviousLedger, mCurrentHash, mSuppression;
uint32 mCloseTime, mProposeSeq;
uint256 mPreviousLedger, mCurrentHash, mSuppression;
uint32 mCloseTime, mProposeSeq;
uint160 mPeerID;
RippleAddress mPublicKey;
RippleAddress mPrivateKey; // If ours
uint160 mPeerID;
RippleAddress mPublicKey;
RippleAddress mPrivateKey; // If ours
std::string mSignature; // set only if needed
boost::posix_time::ptime mTime;
std::string mSignature; // set only if needed
boost::posix_time::ptime mTime;
};
#endif

View File

@@ -8,128 +8,142 @@ int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 1
// Called when a ledger is open and no close is in progress -- when a transaction is received and no close
// is in process, or when a close completes. Returns the number of seconds the ledger should be be open.
bool ContinuousLedgerTiming::shouldClose(
bool anyTransactions,
int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed this ledgers
int proposersValidated, // proposers who have validated the last closed ledger
int previousMSeconds, // milliseconds the previous ledger took to reach consensus
int currentMSeconds, // milliseconds since the previous ledger closed
int openMSeconds, // milliseconds since the previous LCL was computed
int idleInterval) // network's desired idle interval
bool ContinuousLedgerTiming::shouldClose (
bool anyTransactions,
int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed this ledgers
int proposersValidated, // proposers who have validated the last closed ledger
int previousMSeconds, // milliseconds the previous ledger took to reach consensus
int currentMSeconds, // milliseconds since the previous ledger closed
int openMSeconds, // milliseconds since the previous LCL was computed
int idleInterval) // network's desired idle interval
{
if ((previousMSeconds < -1000) || (previousMSeconds > 600000) ||
(currentMSeconds < -1000) || (currentMSeconds > 600000))
{
WriteLog (lsWARNING, LedgerTimingLog) <<
boost::str(boost::format("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)")
% (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed
% currentMSeconds % previousMSeconds);
return true;
}
if ((previousMSeconds < -1000) || (previousMSeconds > 600000) ||
(currentMSeconds < -1000) || (currentMSeconds > 600000))
{
WriteLog (lsWARNING, LedgerTimingLog) <<
boost::str (boost::format ("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)")
% (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed
% currentMSeconds % previousMSeconds);
return true;
}
if (!anyTransactions)
{
// no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
{
WriteLog (lsTRACE, LedgerTimingLog) << "no transactions, many proposers: now (" << proposersClosed << " closed, "
<< previousProposers << " before)";
return true;
}
if (!anyTransactions)
{ // no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
{
WriteLog (lsTRACE, LedgerTimingLog) << "no transactions, many proposers: now (" << proposersClosed << " closed, "
<< previousProposers << " before)";
return true;
}
#if 0 // This false triggers on the genesis ledger
if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close
{
WriteLog (lsTRACE, LedgerTimingLog) << "was slow to converge (p=" << (previousMSeconds) << ")";
if (previousMSeconds < 2000)
return previousMSeconds;
return previousMSeconds - 1000;
}
if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close
{
WriteLog (lsTRACE, LedgerTimingLog) << "was slow to converge (p=" << (previousMSeconds) << ")";
if (previousMSeconds < 2000)
return previousMSeconds;
return previousMSeconds - 1000;
}
#endif
return currentMSeconds >= (idleInterval * 1000); // normal idle
}
return currentMSeconds >= (idleInterval * 1000); // normal idle
}
if ((openMSeconds < LEDGER_MIN_CLOSE) && ((proposersClosed + proposersValidated) < (previousProposers / 2 )))
{
WriteLog (lsDEBUG, LedgerTimingLog) << "Must wait minimum time before closing";
return false;
}
if ((openMSeconds < LEDGER_MIN_CLOSE) && ((proposersClosed + proposersValidated) < (previousProposers / 2 )))
{
WriteLog (lsDEBUG, LedgerTimingLog) << "Must wait minimum time before closing";
return false;
}
if ((currentMSeconds < previousMSeconds) && ((proposersClosed + proposersValidated) < previousProposers))
{
WriteLog (lsDEBUG, LedgerTimingLog) << "We are waiting for more closes/validations";
return false;
}
if ((currentMSeconds < previousMSeconds) && ((proposersClosed + proposersValidated) < previousProposers))
{
WriteLog (lsDEBUG, LedgerTimingLog) << "We are waiting for more closes/validations";
return false;
}
return true; // this ledger should close now
return true; // this ledger should close now
}
// Returns whether we have a consensus or not. If so, we expect all honest nodes
// to already have everything they need to accept a consensus. Our vote is 'locked in'.
bool ContinuousLedgerTiming::haveConsensus(
int previousProposers, // proposers in the last closing (not including us)
int currentProposers, // proposers in this closing so far (not including us)
int currentAgree, // proposers who agree with us
int currentFinished, // proposers who have validated a ledger after this one
int previousAgreeTime, // how long it took to agree on the last ledger
int currentAgreeTime, // how long we've been trying to agree
bool forReal, // deciding whether to stop consensus process
bool& failed) // we can't reach a consensus
bool ContinuousLedgerTiming::haveConsensus (
int previousProposers, // proposers in the last closing (not including us)
int currentProposers, // proposers in this closing so far (not including us)
int currentAgree, // proposers who agree with us
int currentFinished, // proposers who have validated a ledger after this one
int previousAgreeTime, // how long it took to agree on the last ledger
int currentAgreeTime, // how long we've been trying to agree
bool forReal, // deciding whether to stop consensus process
bool& failed) // we can't reach a consensus
{
WriteLog (lsTRACE, LedgerTimingLog) << boost::str(boost::format("CLC::haveConsensus: prop=%d/%d agree=%d validated=%d time=%d/%d%s") %
currentProposers % previousProposers % currentAgree % currentFinished % currentAgreeTime % previousAgreeTime %
(forReal ? "" : "X"));
WriteLog (lsTRACE, LedgerTimingLog) << boost::str (boost::format ("CLC::haveConsensus: prop=%d/%d agree=%d validated=%d time=%d/%d%s") %
currentProposers % previousProposers % currentAgree % currentFinished % currentAgreeTime % previousAgreeTime %
(forReal ? "" : "X"));
if (currentAgreeTime <= LEDGER_MIN_CONSENSUS)
return false;
if (currentAgreeTime <= LEDGER_MIN_CONSENSUS)
return false;
if (currentProposers < (previousProposers * 3 / 4))
{ // Less than 3/4 of the last ledger's proposers are present, we may need more time
if (currentAgreeTime < (previousAgreeTime + LEDGER_MIN_CONSENSUS))
{
CondLog (forReal, lsTRACE, LedgerTimingLog) << "too fast, not enough proposers";
return false;
}
}
if (currentProposers < (previousProposers * 3 / 4))
{
// Less than 3/4 of the last ledger's proposers are present, we may need more time
if (currentAgreeTime < (previousAgreeTime + LEDGER_MIN_CONSENSUS))
{
CondLog (forReal, lsTRACE, LedgerTimingLog) << "too fast, not enough proposers";
return false;
}
}
// If 80% of current proposers (plus us) agree on a set, we have consensus
if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsINFO, LedgerTimingLog) << "normal consensus";
failed = false;
return true;
}
// If 80% of current proposers (plus us) agree on a set, we have consensus
if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsINFO, LedgerTimingLog) << "normal consensus";
failed = false;
return true;
}
// If 80% of the nodes on your UNL have moved on, you should declare consensus
if (((currentFinished * 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsWARNING, LedgerTimingLog) << "We see no consensus, but 80% of nodes have moved on";
failed = true;
return true;
}
// If 80% of the nodes on your UNL have moved on, you should declare consensus
if (((currentFinished * 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsWARNING, LedgerTimingLog) << "We see no consensus, but 80% of nodes have moved on";
failed = true;
return true;
}
// no consensus yet
CondLog (forReal, lsTRACE, LedgerTimingLog) << "no consensus";
return false;
// no consensus yet
CondLog (forReal, lsTRACE, LedgerTimingLog) << "no consensus";
return false;
}
int ContinuousLedgerTiming::getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq)
int ContinuousLedgerTiming::getNextLedgerTimeResolution (int previousResolution, bool previousAgree, int ledgerSeq)
{
assert(ledgerSeq);
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
{ // reduce resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i + 1];
}
assert (ledgerSeq);
if ((previousAgree) && ((ledgerSeq % LEDGER_RES_INCREASE) == 0))
{ // increase resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i - 1];
}
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
{
// reduce resolution
int i = 1;
return previousResolution;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i + 1];
}
if ((previousAgree) && ((ledgerSeq % LEDGER_RES_INCREASE) == 0))
{
// increase resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i - 1];
}
return previousResolution;
}

View File

@@ -2,80 +2,80 @@
#define __LEDGERTIMING__
// The number of seconds a ledger may remain idle before closing
# define LEDGER_IDLE_INTERVAL 15
# define LEDGER_IDLE_INTERVAL 15
// The number of seconds a validation remains current after its ledger's close time
// This is a safety to protect against very old validations and the time it takes to adjust
// the close time accuracy window
# define LEDGER_VAL_INTERVAL 300
# define LEDGER_VAL_INTERVAL 300
// The number of seconds before a close time that we consider a validation acceptable
// This protects against extreme clock errors
# define LEDGER_EARLY_INTERVAL 180
# define LEDGER_EARLY_INTERVAL 180
// The number of milliseconds we wait minimum to ensure participation
# define LEDGER_MIN_CONSENSUS 2000
# define LEDGER_MIN_CONSENSUS 2000
// The number of milliseconds we wait minimum to ensure others have computed the LCL
# define LEDGER_MIN_CLOSE 2000
# define LEDGER_MIN_CLOSE 2000
// Initial resolution of ledger close time
# define LEDGER_TIME_ACCURACY 30
# define LEDGER_TIME_ACCURACY 30
// How often to increase resolution
# define LEDGER_RES_INCREASE 8
# define LEDGER_RES_INCREASE 8
// How often to decrease resolution
# define LEDGER_RES_DECREASE 1
# define LEDGER_RES_DECREASE 1
// How often we check state or change positions (in milliseconds)
# define LEDGER_GRANULARITY 1000
# define LEDGER_GRANULARITY 1000
// The percentage of active trusted validators that must be able to
// keep up with the network or we consider the network overloaded
# define LEDGER_NET_RATIO 70
# define LEDGER_NET_RATIO 70
// How long we consider a proposal fresh
# define PROPOSE_FRESHNESS 20
# define PROPOSE_FRESHNESS 20
// How often we force generating a new proposal to keep ours fresh
# define PROPOSE_INTERVAL 12
# define PROPOSE_INTERVAL 12
// Avalanche tuning
# define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
# define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
# define AV_MID_CONSENSUS_TIME 50 // percentage of previous close time before we advance
# define AV_MID_CONSENSUS_PCT 65 // percentage of nodes that most vote yes after advancing
# define AV_MID_CONSENSUS_TIME 50 // percentage of previous close time before we advance
# define AV_MID_CONSENSUS_PCT 65 // percentage of nodes that most vote yes after advancing
# define AV_LATE_CONSENSUS_TIME 85 // percentage of previous close time before we advance
# define AV_LATE_CONSENSUS_PCT 70 // percentage of nodes that most vote yes after advancing
# define AV_LATE_CONSENSUS_TIME 85 // percentage of previous close time before we advance
# define AV_LATE_CONSENSUS_PCT 70 // percentage of nodes that most vote yes after advancing
# define AV_STUCK_CONSENSUS_TIME 200
# define AV_STUCK_CONSENSUS_PCT 95
# define AV_STUCK_CONSENSUS_TIME 200
# define AV_STUCK_CONSENSUS_PCT 95
# define AV_CT_CONSENSUS_PCT 75
# define AV_CT_CONSENSUS_PCT 75
class ContinuousLedgerTiming
{
public:
static int LedgerTimeResolution[];
static int LedgerTimeResolution[];
// Returns the number of seconds the ledger was or should be open
// Call when a consensus is reached and when any transaction is relayed to be added
static bool shouldClose(
bool anyTransactions,
int previousProposers, int proposersClosed, int proposerersValidated,
int previousMSeconds, int currentMSeconds, int openMSeconds,
int idleInterval);
// Returns the number of seconds the ledger was or should be open
// Call when a consensus is reached and when any transaction is relayed to be added
static bool shouldClose (
bool anyTransactions,
int previousProposers, int proposersClosed, int proposerersValidated,
int previousMSeconds, int currentMSeconds, int openMSeconds,
int idleInterval);
static bool haveConsensus(
int previousProposers, int currentProposers,
int currentAgree, int currentClosed,
int previousAgreeTime, int currentAgreeTime,
bool forReal, bool& failed);
static bool haveConsensus (
int previousProposers, int currentProposers,
int currentAgree, int currentClosed,
int previousAgreeTime, int currentAgreeTime,
bool forReal, bool& failed);
static int getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq);
static int getNextLedgerTimeResolution (int previousResolution, bool previousAgree, int ledgerSeq);
};
#endif

View File

@@ -2,265 +2,279 @@
SETUP_LOG (LoadManager)
LoadManager::LoadManager (int creditRate, int creditLimit, int debitWarn, int debitLimit)
: mCreditRate(creditRate)
, mCreditLimit(creditLimit)
, mDebitWarn(debitWarn)
, mDebitLimit(debitLimit)
, mShutdown(false)
, mArmed(false)
, mDeadLock(0)
, mCosts(LT_MAX)
: mCreditRate (creditRate)
, mCreditLimit (creditLimit)
, mDebitWarn (debitWarn)
, mDebitLimit (debitLimit)
, mShutdown (false)
, mArmed (false)
, mDeadLock (0)
, mCosts (LT_MAX)
{
addLoadCost(LoadCost(LT_InvalidRequest, -10, LC_CPU | LC_Network));
addLoadCost(LoadCost(LT_RequestNoReply, -1, LC_CPU | LC_Disk));
addLoadCost(LoadCost(LT_InvalidSignature, -100, LC_CPU));
addLoadCost(LoadCost(LT_UnwantedData, -5, LC_CPU | LC_Network));
addLoadCost(LoadCost(LT_BadData, -20, LC_CPU));
addLoadCost (LoadCost (LT_InvalidRequest, -10, LC_CPU | LC_Network));
addLoadCost (LoadCost (LT_RequestNoReply, -1, LC_CPU | LC_Disk));
addLoadCost (LoadCost (LT_InvalidSignature, -100, LC_CPU));
addLoadCost (LoadCost (LT_UnwantedData, -5, LC_CPU | LC_Network));
addLoadCost (LoadCost (LT_BadData, -20, LC_CPU));
addLoadCost(LoadCost(LT_NewTrusted, -10, 0));
addLoadCost(LoadCost(LT_NewTransaction, -2, 0));
addLoadCost(LoadCost(LT_NeededData, -10, 0));
addLoadCost (LoadCost (LT_NewTrusted, -10, 0));
addLoadCost (LoadCost (LT_NewTransaction, -2, 0));
addLoadCost (LoadCost (LT_NeededData, -10, 0));
addLoadCost(LoadCost(LT_RequestData, -5, LC_Disk | LC_Network));
addLoadCost(LoadCost(LT_CheapQuery, -1, LC_CPU));
addLoadCost (LoadCost (LT_RequestData, -5, LC_Disk | LC_Network));
addLoadCost (LoadCost (LT_CheapQuery, -1, LC_CPU));
}
void LoadManager::init()
void LoadManager::init ()
{
UptimeTimer::getInstance().beginManualUpdates ();
UptimeTimer::getInstance ().beginManualUpdates ();
boost::thread(boost::bind(&LoadManager::threadEntry, this)).detach();
boost::thread (boost::bind (&LoadManager::threadEntry, this)).detach ();
}
LoadManager::~LoadManager()
LoadManager::~LoadManager ()
{
UptimeTimer::getInstance().endManualUpdates ();
UptimeTimer::getInstance ().endManualUpdates ();
// VFALCO What is this loop? it doesn't seem to do anything useful.
do
{
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
{
boost::mutex::scoped_lock sl(mLock);
if (!mShutdown)
return;
}
}
while (1);
do
{
boost::this_thread::sleep (boost::posix_time::milliseconds (100));
{
boost::mutex::scoped_lock sl (mLock);
if (!mShutdown)
return;
}
}
while (1);
}
void LoadManager::noDeadLock()
void LoadManager::noDeadLock ()
{
boost::mutex::scoped_lock sl(mLock);
//mDeadLock = mUptime;
mDeadLock = UptimeTimer::getInstance ().getElapsedSeconds ();
boost::mutex::scoped_lock sl (mLock);
//mDeadLock = mUptime;
mDeadLock = UptimeTimer::getInstance ().getElapsedSeconds ();
}
int LoadManager::getCreditRate() const
int LoadManager::getCreditRate () const
{
boost::mutex::scoped_lock sl(mLock);
return mCreditRate;
boost::mutex::scoped_lock sl (mLock);
return mCreditRate;
}
int LoadManager::getCreditLimit() const
int LoadManager::getCreditLimit () const
{
boost::mutex::scoped_lock sl(mLock);
return mCreditLimit;
boost::mutex::scoped_lock sl (mLock);
return mCreditLimit;
}
int LoadManager::getDebitWarn() const
int LoadManager::getDebitWarn () const
{
boost::mutex::scoped_lock sl(mLock);
return mDebitWarn;
boost::mutex::scoped_lock sl (mLock);
return mDebitWarn;
}
int LoadManager::getDebitLimit() const
int LoadManager::getDebitLimit () const
{
boost::mutex::scoped_lock sl(mLock);
return mDebitLimit;
boost::mutex::scoped_lock sl (mLock);
return mDebitLimit;
}
void LoadManager::setCreditRate(int r)
void LoadManager::setCreditRate (int r)
{
boost::mutex::scoped_lock sl(mLock);
mCreditRate = r;
boost::mutex::scoped_lock sl (mLock);
mCreditRate = r;
}
void LoadManager::setCreditLimit(int r)
void LoadManager::setCreditLimit (int r)
{
boost::mutex::scoped_lock sl(mLock);
mCreditLimit = r;
boost::mutex::scoped_lock sl (mLock);
mCreditLimit = r;
}
void LoadManager::setDebitWarn(int r)
void LoadManager::setDebitWarn (int r)
{
boost::mutex::scoped_lock sl(mLock);
mDebitWarn = r;
boost::mutex::scoped_lock sl (mLock);
mDebitWarn = r;
}
void LoadManager::setDebitLimit(int r)
void LoadManager::setDebitLimit (int r)
{
boost::mutex::scoped_lock sl(mLock);
mDebitLimit = r;
boost::mutex::scoped_lock sl (mLock);
mDebitLimit = r;
}
void LoadManager::canonicalize(LoadSource& source, int now) const
void LoadManager::canonicalize (LoadSource& source, int now) const
{
if (source.mLastUpdate != now)
{
if (source.mLastUpdate < now)
{
source.mBalance += mCreditRate * (now - source.mLastUpdate);
if (source.mBalance > mCreditLimit)
{
source.mBalance = mCreditLimit;
source.mLogged = false;
}
}
source.mLastUpdate = now;
}
if (source.mLastUpdate != now)
{
if (source.mLastUpdate < now)
{
source.mBalance += mCreditRate * (now - source.mLastUpdate);
if (source.mBalance > mCreditLimit)
{
source.mBalance = mCreditLimit;
source.mLogged = false;
}
}
source.mLastUpdate = now;
}
}
bool LoadManager::shouldWarn(LoadSource& source) const
bool LoadManager::shouldWarn (LoadSource& source) const
{
{
boost::mutex::scoped_lock sl(mLock);
{
boost::mutex::scoped_lock sl (mLock);
int now = UptimeTimer::getInstance().getElapsedSeconds ();
canonicalize(source, now);
if (source.isPrivileged() || (source.mBalance > mDebitWarn) || (source.mLastWarning == now))
return false;
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
source.mLastWarning = now;
}
logWarning(source.getName());
return true;
if (source.isPrivileged () || (source.mBalance > mDebitWarn) || (source.mLastWarning == now))
return false;
source.mLastWarning = now;
}
logWarning (source.getName ());
return true;
}
bool LoadManager::shouldCutoff(LoadSource& source) const
bool LoadManager::shouldCutoff (LoadSource& source) const
{
{
boost::mutex::scoped_lock sl(mLock);
int now = UptimeTimer::getInstance().getElapsedSeconds ();
canonicalize(source, now);
if (source.isPrivileged() || (source.mBalance > mDebitLimit))
return false;
if (source.mLogged)
return true;
source.mLogged = true;
}
logDisconnect(source.getName());
return true;
{
boost::mutex::scoped_lock sl (mLock);
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
if (source.isPrivileged () || (source.mBalance > mDebitLimit))
return false;
if (source.mLogged)
return true;
source.mLogged = true;
}
logDisconnect (source.getName ());
return true;
}
bool LoadManager::adjust(LoadSource& source, LoadType t) const
{ // FIXME: Scale by category
LoadCost cost = mCosts[static_cast<int>(t)];
return adjust(source, cost.mCost);
}
bool LoadManager::adjust(LoadSource& source, int credits) const
{ // return: true = need to warn/cutoff
// We do it this way in case we want to add exponential decay later
int now = UptimeTimer::getInstance().getElapsedSeconds ();
canonicalize(source, now);
source.mBalance += credits;
if (source.mBalance > mCreditLimit)
source.mBalance = mCreditLimit;
if (source.isPrivileged()) // privileged sources never warn/cutoff
return false;
if ((source.mBalance >= mDebitLimit) && (source.mLastWarning == now)) // no need to warn
return false;
return true;
}
static void LogDeadLock(int dlTime)
bool LoadManager::adjust (LoadSource& source, LoadType t) const
{
WriteLog (lsWARNING, LoadManager) << "Server stalled for " << dlTime << " seconds.";
// FIXME: Scale by category
LoadCost cost = mCosts[static_cast<int> (t)];
return adjust (source, cost.mCost);
}
void LoadManager::threadEntry()
bool LoadManager::adjust (LoadSource& source, int credits) const
{
setCallingThreadName ("loadmgr");
// return: true = need to warn/cutoff
// We do it this way in case we want to add exponential decay later
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
source.mBalance += credits;
if (source.mBalance > mCreditLimit)
source.mBalance = mCreditLimit;
if (source.isPrivileged ()) // privileged sources never warn/cutoff
return false;
if ((source.mBalance >= mDebitLimit) && (source.mLastWarning == now)) // no need to warn
return false;
return true;
}
static void LogDeadLock (int dlTime)
{
WriteLog (lsWARNING, LoadManager) << "Server stalled for " << dlTime << " seconds.";
}
void LoadManager::threadEntry ()
{
setCallingThreadName ("loadmgr");
// VFALCO TODO replace this with a beast Time object
boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time();
while (1)
{
{
boost::mutex::scoped_lock sl(mLock);
if (mShutdown)
{
mShutdown = false;
return;
}
UptimeTimer::getInstance ().incrementElapsedTime ();
boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time ();
int dlTime = UptimeTimer::getInstance ().getElapsedSeconds () - mDeadLock;
if (mArmed && (dlTime >= 10))
{
if ((dlTime % 10) == 0)
{
boost::thread(BIND_TYPE(&LogDeadLock, dlTime)).detach();
}
while (1)
{
{
boost::mutex::scoped_lock sl (mLock);
assert (dlTime < 500);
}
if (mShutdown)
{
mShutdown = false;
return;
}
}
UptimeTimer::getInstance ().incrementElapsedTime ();
int dlTime = UptimeTimer::getInstance ().getElapsedSeconds () - mDeadLock;
if (mArmed && (dlTime >= 10))
{
if ((dlTime % 10) == 0)
{
boost::thread (BIND_TYPE (&LogDeadLock, dlTime)).detach ();
}
assert (dlTime < 500);
}
}
// VFALCO TODO Eliminate the dependence on the Application object by
// constructing with the job queue and the fee tracker.
bool change;
if (theApp->getJobQueue().isOverloaded())
{
WriteLog (lsINFO, LoadManager) << theApp->getJobQueue().getJson(0);
change = theApp->getFeeTrack().raiseLocalFee();
}
else
bool change;
if (theApp->getJobQueue ().isOverloaded ())
{
change = theApp->getFeeTrack().lowerLocalFee();
WriteLog (lsINFO, LoadManager) << theApp->getJobQueue ().getJson (0);
change = theApp->getFeeTrack ().raiseLocalFee ();
}
else
{
change = theApp->getFeeTrack ().lowerLocalFee ();
}
if (change)
{
// VFALCO TODO replace this with a Listener / observer and subscribe in NetworkOPs or Application
theApp->getOPs().reportFeeChange();
theApp->getOPs ().reportFeeChange ();
}
t += boost::posix_time::seconds(1);
boost::posix_time::time_duration when = t - boost::posix_time::microsec_clock::universal_time();
t += boost::posix_time::seconds (1);
boost::posix_time::time_duration when = t - boost::posix_time::microsec_clock::universal_time ();
if ((when.is_negative()) || (when.total_seconds() > 1))
{
WriteLog (lsWARNING, LoadManager) << "time jump";
t = boost::posix_time::microsec_clock::universal_time();
}
else
boost::this_thread::sleep(when);
}
if ((when.is_negative ()) || (when.total_seconds () > 1))
{
WriteLog (lsWARNING, LoadManager) << "time jump";
t = boost::posix_time::microsec_clock::universal_time ();
}
else
boost::this_thread::sleep (when);
}
}
void LoadManager::logWarning(const std::string& source) const
void LoadManager::logWarning (const std::string& source) const
{
if (source.empty())
WriteLog (lsDEBUG, LoadManager) << "Load warning from empty source";
else
WriteLog (lsINFO, LoadManager) << "Load warning: " << source;
if (source.empty ())
WriteLog (lsDEBUG, LoadManager) << "Load warning from empty source";
else
WriteLog (lsINFO, LoadManager) << "Load warning: " << source;
}
void LoadManager::logDisconnect(const std::string& source) const
void LoadManager::logDisconnect (const std::string& source) const
{
if (source.empty())
WriteLog (lsINFO, LoadManager) << "Disconnect for empty source";
else
WriteLog (lsWARNING, LoadManager) << "Disconnect for: " << source;
if (source.empty ())
WriteLog (lsINFO, LoadManager) << "Disconnect for empty source";
else
WriteLog (lsWARNING, LoadManager) << "Disconnect for: " << source;
}
// vim:ts=4

View File

@@ -5,144 +5,186 @@
// VFALCO TODO replace LT_ with loadType in constants
enum LoadType
{
// Bad things
LT_InvalidRequest, // A request that we can immediately tell is invalid
LT_RequestNoReply, // A request that we cannot satisfy
LT_InvalidSignature, // An object whose signature we had to check and it failed
LT_UnwantedData, // Data we have no use for
LT_BadPoW, // Proof of work not valid
LT_BadData, // Data we have to verify before rejecting
// Bad things
LT_InvalidRequest, // A request that we can immediately tell is invalid
LT_RequestNoReply, // A request that we cannot satisfy
LT_InvalidSignature, // An object whose signature we had to check and it failed
LT_UnwantedData, // Data we have no use for
LT_BadPoW, // Proof of work not valid
LT_BadData, // Data we have to verify before rejecting
// Good things
LT_NewTrusted, // A new transaction/validation/proposal we trust
LT_NewTransaction, // A new, valid transaction
LT_NeededData, // Data we requested
// Good things
LT_NewTrusted, // A new transaction/validation/proposal we trust
LT_NewTransaction, // A new, valid transaction
LT_NeededData, // Data we requested
// Requests
LT_RequestData, // A request that is hard to satisfy, disk access
LT_CheapQuery, // A query that is trivial, cached data
// Requests
LT_RequestData, // A request that is hard to satisfy, disk access
LT_CheapQuery, // A query that is trivial, cached data
LT_MAX // MUST BE LAST
LT_MAX // MUST BE LAST
};
// load categories
static const int LC_Disk = 1;
static const int LC_CPU = 2;
static const int LC_Network = 4;
static const int LC_Disk = 1;
static const int LC_CPU = 2;
static const int LC_Network = 4;
class LoadCost
{
public:
LoadType mType;
int mCost;
int mCategories;
LoadType mType;
int mCost;
int mCategories;
LoadCost() : mType(), mCost(0), mCategories(0) { ; }
LoadCost(LoadType t, int cost, int cat) : mType(t), mCost(cost), mCategories(cat) { ; }
LoadCost () : mType (), mCost (0), mCategories (0)
{
;
}
LoadCost (LoadType t, int cost, int cat) : mType (t), mCost (cost), mCategories (cat)
{
;
}
};
// a single endpoint that can impose load
class LoadSource
{
{
private:
// VFALCO Make this not a friend
friend class LoadManager;
friend class LoadManager;
public:
// load source flags
static const int lsfPrivileged = 1;
static const int lsfOutbound = 2; // outbound connection
// load source flags
static const int lsfPrivileged = 1;
static const int lsfOutbound = 2; // outbound connection
public:
explicit LoadSource (bool admin)
: mBalance(0)
, mFlags(admin ? lsfPrivileged : 0)
, mLastUpdate(UptimeTimer::getInstance().getElapsedSeconds ())
, mLastWarning(0)
, mLogged(false)
{
}
explicit LoadSource (std::string const& name)
: mName(name)
, mBalance(0)
, mFlags(0)
, mLastUpdate(UptimeTimer::getInstance().getElapsedSeconds ())
, mLastWarning(0)
, mLogged(false)
{
}
explicit LoadSource (bool admin)
: mBalance (0)
, mFlags (admin ? lsfPrivileged : 0)
, mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
, mLastWarning (0)
, mLogged (false)
{
}
void rename (std::string const & name) { mName = name; }
std::string const& getName() { return mName; }
explicit LoadSource (std::string const& name)
: mName (name)
, mBalance (0)
, mFlags (0)
, mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
, mLastWarning (0)
, mLogged (false)
{
}
bool isPrivileged() const { return (mFlags & lsfPrivileged) != 0; }
void setPrivileged() { mFlags |= lsfPrivileged; }
int getBalance() const { return mBalance; }
void rename (std::string const& name)
{
mName = name;
}
std::string const& getName ()
{
return mName;
}
bool isLogged() const { return mLogged; }
void clearLogged() { mLogged = false; }
bool isPrivileged () const
{
return (mFlags & lsfPrivileged) != 0;
}
void setPrivileged ()
{
mFlags |= lsfPrivileged;
}
int getBalance () const
{
return mBalance;
}
void setOutbound() { mFlags |= lsfOutbound; }
bool isOutbound() const { return (mFlags & lsfOutbound) != 0; }
bool isLogged () const
{
return mLogged;
}
void clearLogged ()
{
mLogged = false;
}
void setOutbound ()
{
mFlags |= lsfOutbound;
}
bool isOutbound () const
{
return (mFlags & lsfOutbound) != 0;
}
private:
std::string mName;
int mBalance;
int mFlags;
int mLastUpdate;
int mLastWarning;
bool mLogged;
std::string mName;
int mBalance;
int mFlags;
int mLastUpdate;
int mLastWarning;
bool mLogged;
};
// a collection of load sources
class LoadManager
{
public:
LoadManager(int creditRate = 100, int creditLimit = 500, int debitWarn = -500, int debitLimit = -1000);
~LoadManager();
void init();
LoadManager (int creditRate = 100, int creditLimit = 500, int debitWarn = -500, int debitLimit = -1000);
~LoadManager ();
void init ();
int getCreditRate() const;
int getCreditLimit() const;
int getDebitWarn() const;
int getDebitLimit() const;
void setCreditRate(int);
void setCreditLimit(int);
void setDebitWarn(int);
void setDebitLimit(int);
int getCreditRate () const;
int getCreditLimit () const;
int getDebitWarn () const;
int getDebitLimit () const;
void setCreditRate (int);
void setCreditLimit (int);
void setDebitWarn (int);
void setDebitLimit (int);
bool shouldWarn(LoadSource&) const;
bool shouldCutoff(LoadSource&) const;
bool adjust(LoadSource&, int credits) const; // return value: false=balance okay, true=warn/cutoff
bool adjust(LoadSource&, LoadType l) const;
bool shouldWarn (LoadSource&) const;
bool shouldCutoff (LoadSource&) const;
bool adjust (LoadSource&, int credits) const; // return value: false=balance okay, true=warn/cutoff
bool adjust (LoadSource&, LoadType l) const;
void logWarning(const std::string&) const;
void logDisconnect(const std::string&) const;
void logWarning (const std::string&) const;
void logDisconnect (const std::string&) const;
int getCost(LoadType t) { return mCosts[static_cast<int>(t)].mCost; }
void noDeadLock();
void arm() { mArmed = true; }
int getCost (LoadType t)
{
return mCosts[static_cast<int> (t)].mCost;
}
void noDeadLock ();
void arm ()
{
mArmed = true;
}
private:
void canonicalize(LoadSource&, int upTime) const;
void addLoadCost(const LoadCost& c) { mCosts[static_cast<int>(c.mType)] = c; }
void threadEntry();
void canonicalize (LoadSource&, int upTime) const;
void addLoadCost (const LoadCost& c)
{
mCosts[static_cast<int> (c.mType)] = c;
}
void threadEntry ();
private:
int mCreditRate; // credits gained/lost per second
int mCreditLimit; // the most credits a source can have
int mDebitWarn; // when a source drops below this, we warn
int mDebitLimit; // when a source drops below this, we cut it off (should be negative)
int mCreditRate; // credits gained/lost per second
int mCreditLimit; // the most credits a source can have
int mDebitWarn; // when a source drops below this, we warn
int mDebitLimit; // when a source drops below this, we cut it off (should be negative)
bool mShutdown;
bool mArmed;
bool mShutdown;
bool mArmed;
int mDeadLock; // Detect server deadlocks
int mDeadLock; // Detect server deadlocks
mutable boost::mutex mLock;
mutable boost::mutex mLock;
std::vector<LoadCost> mCosts;
std::vector<LoadCost> mCosts;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -10,20 +10,22 @@ class LedgerConsensus;
class NetworkOPs
{
public:
enum Fault
{ // exceptions these functions can throw
IO_ERROR = 1,
NO_NETWORK = 2,
};
enum Fault
{
// exceptions these functions can throw
IO_ERROR = 1,
NO_NETWORK = 2,
};
enum OperatingMode
{ // how we process transactions or account balance requests
omDISCONNECTED = 0, // not ready to process requests
omCONNECTED = 1, // convinced we are talking to the network
omSYNCING = 2, // fallen slightly behind
omTRACKING = 3, // convinced we agree with the network
omFULL = 4 // we have the ledger and can even validate
};
enum OperatingMode
{
// how we process transactions or account balance requests
omDISCONNECTED = 0, // not ready to process requests
omCONNECTED = 1, // convinced we are talking to the network
omSYNCING = 2, // fallen slightly behind
omTRACKING = 3, // convinced we agree with the network
omFULL = 4 // we have the ledger and can even validate
};
#if 0
/** Subscription data interface.
@@ -32,108 +34,149 @@ public:
{
public:
typedef boost::weak_ptr <Subscriber> WeakPtr;
/** Called every time new JSON data is available.
*/
virtual void onSubscriberReceiveJSON (Json::Value const& json) { }
};
typedef boost::unordered_map <uint64, Subscriber::WeakPtr> subMapType;
#endif
typedef boost::unordered_map <uint64, InfoSub::wptr> subMapType;
typedef boost::unordered_map <uint64, InfoSub::wptr> subMapType;
public:
NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster);
NetworkOPs (boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster);
// network information
uint32 getNetworkTimeNC(); // Our best estimate of wall time in seconds from 1/1/2000
uint32 getCloseTimeNC(); // Our best estimate of current ledger close time
uint32 getValidationTimeNC(); // Use *only* to timestamp our own validation
void closeTimeOffset(int);
boost::posix_time::ptime getNetworkTimePT();
uint32 getLedgerID(uint256 const& hash);
uint32 getCurrentLedgerID();
OperatingMode getOperatingMode() { return mMode; }
std::string strOperatingMode();
// network information
uint32 getNetworkTimeNC (); // Our best estimate of wall time in seconds from 1/1/2000
uint32 getCloseTimeNC (); // Our best estimate of current ledger close time
uint32 getValidationTimeNC (); // Use *only* to timestamp our own validation
void closeTimeOffset (int);
boost::posix_time::ptime getNetworkTimePT ();
uint32 getLedgerID (uint256 const& hash);
uint32 getCurrentLedgerID ();
OperatingMode getOperatingMode ()
{
return mMode;
}
std::string strOperatingMode ();
Ledger::ref getClosedLedger() { return mLedgerMaster->getClosedLedger(); }
Ledger::ref getValidatedLedger() { return mLedgerMaster->getValidatedLedger(); }
Ledger::ref getCurrentLedger() { return mLedgerMaster->getCurrentLedger(); }
Ledger::ref getCurrentSnapshot() { return mLedgerMaster->getCurrentSnapshot(); }
Ledger::pointer getLedgerByHash(uint256 const& hash) { return mLedgerMaster->getLedgerByHash(hash); }
Ledger::pointer getLedgerBySeq(const uint32 seq);
void missingNodeInLedger(const uint32 seq);
Ledger::ref getClosedLedger ()
{
return mLedgerMaster->getClosedLedger ();
}
Ledger::ref getValidatedLedger ()
{
return mLedgerMaster->getValidatedLedger ();
}
Ledger::ref getCurrentLedger ()
{
return mLedgerMaster->getCurrentLedger ();
}
Ledger::ref getCurrentSnapshot ()
{
return mLedgerMaster->getCurrentSnapshot ();
}
Ledger::pointer getLedgerByHash (uint256 const& hash)
{
return mLedgerMaster->getLedgerByHash (hash);
}
Ledger::pointer getLedgerBySeq (const uint32 seq);
void missingNodeInLedger (const uint32 seq);
uint256 getClosedLedgerHash() { return mLedgerMaster->getClosedLedger()->getHash(); }
uint256 getClosedLedgerHash ()
{
return mLedgerMaster->getClosedLedger ()->getHash ();
}
// Do we have this inclusive range of ledgers in our database
bool haveLedgerRange(uint32 from, uint32 to);
bool haveLedger(uint32 seq);
uint32 getValidatedSeq();
bool isValidated(uint32 seq);
bool isValidated(uint32 seq, uint256 const& hash);
bool isValidated(Ledger::ref l) { return isValidated(l->getLedgerSeq(), l->getHash()); }
bool getValidatedRange(uint32& minVal, uint32& maxVal) { return mLedgerMaster->getValidatedRange(minVal, maxVal); }
// Do we have this inclusive range of ledgers in our database
bool haveLedgerRange (uint32 from, uint32 to);
bool haveLedger (uint32 seq);
uint32 getValidatedSeq ();
bool isValidated (uint32 seq);
bool isValidated (uint32 seq, uint256 const& hash);
bool isValidated (Ledger::ref l)
{
return isValidated (l->getLedgerSeq (), l->getHash ());
}
bool getValidatedRange (uint32& minVal, uint32& maxVal)
{
return mLedgerMaster->getValidatedRange (minVal, maxVal);
}
SerializedValidation::ref getLastValidation() { return mLastValidation; }
void setLastValidation(SerializedValidation::ref v) { mLastValidation = v; }
SerializedValidation::ref getLastValidation ()
{
return mLastValidation;
}
void setLastValidation (SerializedValidation::ref v)
{
mLastValidation = v;
}
SLE::pointer getSLE(Ledger::pointer lpLedger, uint256 const& uHash) { return lpLedger->getSLE(uHash); }
SLE::pointer getSLEi(Ledger::pointer lpLedger, uint256 const& uHash) { return lpLedger->getSLEi(uHash); }
SLE::pointer getSLE (Ledger::pointer lpLedger, uint256 const& uHash)
{
return lpLedger->getSLE (uHash);
}
SLE::pointer getSLEi (Ledger::pointer lpLedger, uint256 const& uHash)
{
return lpLedger->getSLEi (uHash);
}
//
// Transaction operations
//
typedef FUNCTION_TYPE<void (Transaction::pointer, TER)> stCallback; // must complete immediately
void submitTransaction(Job&, SerializedTransaction::pointer, stCallback callback = stCallback());
Transaction::pointer submitTransactionSync(Transaction::ref tpTrans, bool bAdmin, bool bSubmit);
//
// Transaction operations
//
typedef FUNCTION_TYPE<void (Transaction::pointer, TER)> stCallback; // must complete immediately
void submitTransaction (Job&, SerializedTransaction::pointer, stCallback callback = stCallback ());
Transaction::pointer submitTransactionSync (Transaction::ref tpTrans, bool bAdmin, bool bSubmit);
void runTransactionQueue();
Transaction::pointer processTransaction(Transaction::pointer, bool bAdmin, stCallback);
Transaction::pointer processTransaction(Transaction::pointer transaction, bool bAdmin)
{ return processTransaction(transaction, bAdmin, stCallback()); }
void runTransactionQueue ();
Transaction::pointer processTransaction (Transaction::pointer, bool bAdmin, stCallback);
Transaction::pointer processTransaction (Transaction::pointer transaction, bool bAdmin)
{
return processTransaction (transaction, bAdmin, stCallback ());
}
Transaction::pointer findTransactionByID(uint256 const& transactionID);
Transaction::pointer findTransactionByID (uint256 const& transactionID);
#if 0
int findTransactionsBySource(uint256 const& uLedger, std::list<Transaction::pointer>&, const RippleAddress& sourceAccount,
uint32 minSeq, uint32 maxSeq);
int findTransactionsBySource (uint256 const& uLedger, std::list<Transaction::pointer>&, const RippleAddress& sourceAccount,
uint32 minSeq, uint32 maxSeq);
#endif
int findTransactionsByDestination(std::list<Transaction::pointer>&, const RippleAddress& destinationAccount,
uint32 startLedgerSeq, uint32 endLedgerSeq, int maxTransactions);
int findTransactionsByDestination (std::list<Transaction::pointer>&, const RippleAddress& destinationAccount,
uint32 startLedgerSeq, uint32 endLedgerSeq, int maxTransactions);
//
// Account functions
//
//
// Account functions
//
AccountState::pointer getAccountState(Ledger::ref lrLedger, const RippleAddress& accountID);
SLE::pointer getGenerator(Ledger::ref lrLedger, const uint160& uGeneratorID);
AccountState::pointer getAccountState (Ledger::ref lrLedger, const RippleAddress& accountID);
SLE::pointer getGenerator (Ledger::ref lrLedger, const uint160& uGeneratorID);
//
// Directory functions
//
//
// Directory functions
//
STVector256 getDirNodeInfo(Ledger::ref lrLedger, uint256 const& uRootIndex,
uint64& uNodePrevious, uint64& uNodeNext);
STVector256 getDirNodeInfo (Ledger::ref lrLedger, uint256 const& uRootIndex,
uint64& uNodePrevious, uint64& uNodeNext);
#if 0
//
// Nickname functions
//
//
// Nickname functions
//
NicknameState::pointer getNicknameState(uint256 const& uLedger, const std::string& strNickname);
NicknameState::pointer getNicknameState (uint256 const& uLedger, const std::string& strNickname);
#endif
//
// Owner functions
//
//
// Owner functions
//
Json::Value getOwnerInfo(Ledger::pointer lpLedger, const RippleAddress& naAccount);
Json::Value getOwnerInfo (Ledger::pointer lpLedger, const RippleAddress& naAccount);
//
// Book functions
//
//
// Book functions
//
void getBookPage (Ledger::pointer lpLedger,
void getBookPage (Ledger::pointer lpLedger,
const uint160& uTakerPaysCurrencyID,
const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrencyID,
@@ -144,197 +187,250 @@ public:
const Json::Value& jvMarker,
Json::Value& jvResult);
// raw object operations
bool findRawLedger(uint256 const& ledgerHash, Blob& rawLedger);
bool findRawTransaction(uint256 const& transactionHash, Blob& rawTransaction);
bool findAccountNode(uint256 const& nodeHash, Blob& rawAccountNode);
bool findTransactionNode(uint256 const& nodeHash, Blob& rawTransactionNode);
// raw object operations
bool findRawLedger (uint256 const& ledgerHash, Blob& rawLedger);
bool findRawTransaction (uint256 const& transactionHash, Blob& rawTransaction);
bool findAccountNode (uint256 const& nodeHash, Blob& rawAccountNode);
bool findTransactionNode (uint256 const& nodeHash, Blob& rawTransactionNode);
// tree synchronization operations
bool getTransactionTreeNodes(uint32 ledgerSeq, uint256 const& myNodeID,
Blob const& myNode, std::list< Blob >& newNodes);
bool getAccountStateNodes(uint32 ledgerSeq, uint256 const& myNodeId,
Blob const& myNode, std::list< Blob >& newNodes);
// tree synchronization operations
bool getTransactionTreeNodes (uint32 ledgerSeq, uint256 const& myNodeID,
Blob const& myNode, std::list< Blob >& newNodes);
bool getAccountStateNodes (uint32 ledgerSeq, uint256 const& myNodeId,
Blob const& myNode, std::list< Blob >& newNodes);
// ledger proposal/close functions
void processTrustedProposal(LedgerProposal::pointer proposal, boost::shared_ptr<ripple::TMProposeSet> set,
RippleAddress nodePublic, uint256 checkLedger, bool sigGood);
SHAMapAddNode gotTXData(const boost::shared_ptr<Peer>& peer, uint256 const& hash,
const std::list<SHAMapNode>& nodeIDs, const std::list< Blob >& nodeData);
bool recvValidation(SerializedValidation::ref val, const std::string& source);
void takePosition(int seq, SHAMap::ref position);
SHAMap::pointer getTXMap(uint256 const& hash);
bool hasTXSet(const boost::shared_ptr<Peer>& peer, uint256 const& set, ripple::TxSetStatus status);
void mapComplete(uint256 const& hash, SHAMap::ref map);
bool stillNeedTXSet(uint256 const& hash);
void makeFetchPack(Job&, boost::weak_ptr<Peer> peer, boost::shared_ptr<ripple::TMGetObjectByHash> request,
Ledger::pointer wantLedger, Ledger::pointer haveLedger, uint32 uUptime);
bool shouldFetchPack(uint32 seq);
void gotFetchPack(bool progress, uint32 seq);
void addFetchPack(uint256 const& hash, boost::shared_ptr< Blob >& data);
bool getFetchPack(uint256 const& hash, Blob& data);
int getFetchSize();
void sweepFetchPack();
// ledger proposal/close functions
void processTrustedProposal (LedgerProposal::pointer proposal, boost::shared_ptr<ripple::TMProposeSet> set,
RippleAddress nodePublic, uint256 checkLedger, bool sigGood);
SHAMapAddNode gotTXData (const boost::shared_ptr<Peer>& peer, uint256 const& hash,
const std::list<SHAMapNode>& nodeIDs, const std::list< Blob >& nodeData);
bool recvValidation (SerializedValidation::ref val, const std::string& source);
void takePosition (int seq, SHAMap::ref position);
SHAMap::pointer getTXMap (uint256 const& hash);
bool hasTXSet (const boost::shared_ptr<Peer>& peer, uint256 const& set, ripple::TxSetStatus status);
void mapComplete (uint256 const& hash, SHAMap::ref map);
bool stillNeedTXSet (uint256 const& hash);
void makeFetchPack (Job&, boost::weak_ptr<Peer> peer, boost::shared_ptr<ripple::TMGetObjectByHash> request,
Ledger::pointer wantLedger, Ledger::pointer haveLedger, uint32 uUptime);
bool shouldFetchPack (uint32 seq);
void gotFetchPack (bool progress, uint32 seq);
void addFetchPack (uint256 const& hash, boost::shared_ptr< Blob >& data);
bool getFetchPack (uint256 const& hash, Blob& data);
int getFetchSize ();
void sweepFetchPack ();
float getJSONHitRate() { return mJSONCache.getHitRate(); }
float getJSONHitRate ()
{
return mJSONCache.getHitRate ();
}
// VFALCO TODO Rename this to getNumberOfCachedJSONItems or something similar
int getJSONEntries() { return mJSONCache.getNumberOfEntries(); }
int getJSONEntries ()
{
return mJSONCache.getNumberOfEntries ();
}
void storeJSONCache(JSONCache::Kind kind, const uint256& ledger, const uint160& object,
const boost::shared_ptr <Json::Value>& data)
{ mJSONCache.storeEntry(kind, ledger, object, data); }
void storeJSONCache (JSONCache::Kind kind, const uint256& ledger, const uint160& object,
const boost::shared_ptr <Json::Value>& data)
{
mJSONCache.storeEntry (kind, ledger, object, data);
}
boost::shared_ptr<Json::Value> getJSONCache(JSONCache::Kind kind, const uint256& ledger, const uint160& object)
{ return mJSONCache.getEntry(kind, ledger, object); }
boost::shared_ptr<Json::Value> getJSONCache (JSONCache::Kind kind, const uint256& ledger, const uint160& object)
{
return mJSONCache.getEntry (kind, ledger, object);
}
// network state machine
void checkState(const boost::system::error_code& result);
void switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus); // Used for the "jump" case
bool checkLastClosedLedger(const std::vector<Peer::pointer>&, uint256& networkClosed);
int beginConsensus(uint256 const& networkClosed, Ledger::pointer closingLedger);
void tryStartConsensus();
void endConsensus(bool correctLCL);
void setStandAlone() { setMode(omFULL); }
void setStateTimer();
void newLCL(int proposers, int convergeTime, uint256 const& ledgerHash);
void needNetworkLedger() { mNeedNetworkLedger = true; }
void clearNeedNetworkLedger() { mNeedNetworkLedger = false; }
bool isNeedNetworkLedger() { return mNeedNetworkLedger; }
bool isFull() { return !mNeedNetworkLedger && (mMode == omFULL); }
void setProposing(bool p, bool v) { mProposing = p; mValidating = v; }
bool isProposing() { return mProposing; }
bool isValidating() { return mValidating; }
bool isFeatureBlocked() { return mFeatureBlocked; }
void setFeatureBlocked();
void consensusViewChange();
int getPreviousProposers() { return mLastCloseProposers; }
int getPreviousConvergeTime() { return mLastCloseConvergeTime; }
uint32 getLastCloseTime() { return mLastCloseTime; }
void setLastCloseTime(uint32 t) { mLastCloseTime = t; }
Json::Value getConsensusInfo();
Json::Value getServerInfo(bool human, bool admin);
uint32 acceptLedger();
boost::unordered_map<uint160,
std::list<LedgerProposal::pointer> >& peekStoredProposals() { return mStoredProposals; }
void storeProposal(LedgerProposal::ref proposal, const RippleAddress& peerPublic);
uint256 getConsensusLCL();
void reportFeeChange();
// network state machine
void checkState (const boost::system::error_code& result);
void switchLastClosedLedger (Ledger::pointer newLedger, bool duringConsensus); // Used for the "jump" case
bool checkLastClosedLedger (const std::vector<Peer::pointer>&, uint256& networkClosed);
int beginConsensus (uint256 const& networkClosed, Ledger::pointer closingLedger);
void tryStartConsensus ();
void endConsensus (bool correctLCL);
void setStandAlone ()
{
setMode (omFULL);
}
void setStateTimer ();
void newLCL (int proposers, int convergeTime, uint256 const& ledgerHash);
void needNetworkLedger ()
{
mNeedNetworkLedger = true;
}
void clearNeedNetworkLedger ()
{
mNeedNetworkLedger = false;
}
bool isNeedNetworkLedger ()
{
return mNeedNetworkLedger;
}
bool isFull ()
{
return !mNeedNetworkLedger && (mMode == omFULL);
}
void setProposing (bool p, bool v)
{
mProposing = p;
mValidating = v;
}
bool isProposing ()
{
return mProposing;
}
bool isValidating ()
{
return mValidating;
}
bool isFeatureBlocked ()
{
return mFeatureBlocked;
}
void setFeatureBlocked ();
void consensusViewChange ();
int getPreviousProposers ()
{
return mLastCloseProposers;
}
int getPreviousConvergeTime ()
{
return mLastCloseConvergeTime;
}
uint32 getLastCloseTime ()
{
return mLastCloseTime;
}
void setLastCloseTime (uint32 t)
{
mLastCloseTime = t;
}
Json::Value getConsensusInfo ();
Json::Value getServerInfo (bool human, bool admin);
uint32 acceptLedger ();
boost::unordered_map < uint160,
std::list<LedgerProposal::pointer> > & peekStoredProposals ()
{
return mStoredProposals;
}
void storeProposal (LedgerProposal::ref proposal, const RippleAddress& peerPublic);
uint256 getConsensusLCL ();
void reportFeeChange ();
//Helper function to generate SQL query to get transactions
std::string transactionsSQL(std::string selection, const RippleAddress& account,
int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit,
bool binary, bool count, bool bAdmin);
//Helper function to generate SQL query to get transactions
std::string transactionsSQL (std::string selection, const RippleAddress& account,
int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit,
bool binary, bool count, bool bAdmin);
// client information retrieval functions
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
getAccountTxs(const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin);
// client information retrieval functions
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
getAccountTxs (const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin);
typedef boost::tuple<std::string, std::string, uint32> txnMetaLedgerType;
std::vector<txnMetaLedgerType>
getAccountTxsB(const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin);
typedef boost::tuple<std::string, std::string, uint32> txnMetaLedgerType;
std::vector<txnMetaLedgerType>
getAccountTxsB (const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin);
std::vector<RippleAddress> getLedgerAffectedAccounts(uint32 ledgerSeq);
std::vector<SerializedTransaction> getLedgerTransactions(uint32 ledgerSeq);
uint32 countAccountTxs(const RippleAddress& account, int32 minLedger, int32 maxLedger);
//
// Monitoring: publisher side
//
void pubLedger(Ledger::ref lpAccepted);
void pubProposedTransaction(Ledger::ref lpCurrent, SerializedTransaction::ref stTxn, TER terResult);
std::vector<RippleAddress> getLedgerAffectedAccounts (uint32 ledgerSeq);
std::vector<SerializedTransaction> getLedgerTransactions (uint32 ledgerSeq);
uint32 countAccountTxs (const RippleAddress& account, int32 minLedger, int32 maxLedger);
//
// Monitoring: publisher side
//
void pubLedger (Ledger::ref lpAccepted);
void pubProposedTransaction (Ledger::ref lpCurrent, SerializedTransaction::ref stTxn, TER terResult);
//
// Monitoring: subscriber side
//
void subAccount(InfoSub::ref ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs, uint32 uLedgerIndex, bool rt);
void unsubAccount(uint64 uListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs, bool rt);
//
// Monitoring: subscriber side
//
void subAccount (InfoSub::ref ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs, uint32 uLedgerIndex, bool rt);
void unsubAccount (uint64 uListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs, bool rt);
bool subLedger(InfoSub::ref ispListener, Json::Value& jvResult);
bool unsubLedger(uint64 uListener);
bool subLedger (InfoSub::ref ispListener, Json::Value& jvResult);
bool unsubLedger (uint64 uListener);
bool subServer(InfoSub::ref ispListener, Json::Value& jvResult);
bool unsubServer(uint64 uListener);
bool subServer (InfoSub::ref ispListener, Json::Value& jvResult);
bool unsubServer (uint64 uListener);
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 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);
bool subTransactions (InfoSub::ref ispListener);
bool unsubTransactions (uint64 uListener);
bool subRTTransactions(InfoSub::ref ispListener);
bool unsubRTTransactions(uint64 uListener);
bool subRTTransactions (InfoSub::ref ispListener);
bool unsubRTTransactions (uint64 uListener);
InfoSub::pointer findRpcSub(const std::string& strUrl);
InfoSub::pointer addRpcSub(const std::string& strUrl, InfoSub::ref rspEntry);
InfoSub::pointer findRpcSub (const std::string& strUrl);
InfoSub::pointer addRpcSub (const std::string& strUrl, InfoSub::ref rspEntry);
private:
typedef boost::unordered_map<uint160, subMapType> subInfoMapType;
typedef boost::unordered_map<uint160, subMapType>::value_type subInfoMapValue;
typedef boost::unordered_map<uint160, subMapType>::iterator subInfoMapIterator;
typedef boost::unordered_map<uint160, subMapType> subInfoMapType;
typedef boost::unordered_map<uint160, subMapType>::value_type subInfoMapValue;
typedef boost::unordered_map<uint160, subMapType>::iterator subInfoMapIterator;
typedef boost::unordered_map<std::string, InfoSub::pointer> subRpcMapType;
typedef boost::unordered_map<std::string, InfoSub::pointer> subRpcMapType;
OperatingMode mMode;
bool mNeedNetworkLedger;
bool mProposing, mValidating;
bool mFeatureBlocked;
boost::posix_time::ptime mConnectTime;
boost::asio::deadline_timer mNetTimer;
boost::shared_ptr<LedgerConsensus> mConsensus;
boost::unordered_map<uint160,
std::list<LedgerProposal::pointer> > mStoredProposals;
OperatingMode mMode;
bool mNeedNetworkLedger;
bool mProposing, mValidating;
bool mFeatureBlocked;
boost::posix_time::ptime mConnectTime;
boost::asio::deadline_timer mNetTimer;
boost::shared_ptr<LedgerConsensus> mConsensus;
boost::unordered_map < uint160,
std::list<LedgerProposal::pointer> > mStoredProposals;
LedgerMaster* mLedgerMaster;
LedgerAcquire::pointer mAcquiringLedger;
LedgerMaster* mLedgerMaster;
LedgerAcquire::pointer mAcquiringLedger;
int mCloseTimeOffset;
int mCloseTimeOffset;
// last ledger close
int mLastCloseProposers, mLastCloseConvergeTime;
uint256 mLastCloseHash;
uint32 mLastCloseTime;
uint32 mLastValidationTime;
SerializedValidation::pointer mLastValidation;
// last ledger close
int mLastCloseProposers, mLastCloseConvergeTime;
uint256 mLastCloseHash;
uint32 mLastCloseTime;
uint32 mLastValidationTime;
SerializedValidation::pointer mLastValidation;
// Recent positions taken
std::map<uint256, std::pair<int, SHAMap::pointer> > mRecentPositions;
// Recent positions taken
std::map<uint256, std::pair<int, SHAMap::pointer> > mRecentPositions;
// XXX Split into more locks.
boost::recursive_mutex mMonitorLock;
subInfoMapType mSubAccount;
subInfoMapType mSubRTAccount;
// XXX Split into more locks.
boost::recursive_mutex mMonitorLock;
subInfoMapType mSubAccount;
subInfoMapType mSubRTAccount;
subRpcMapType mRpcSubMap;
subRpcMapType mRpcSubMap;
subMapType mSubLedger; // accepted ledgers
subMapType mSubServer; // when server changes connectivity state
subMapType mSubTransactions; // all accepted transactions
subMapType mSubRTTransactions; // all proposed and accepted transactions
subMapType mSubLedger; // accepted ledgers
subMapType mSubServer; // when server changes connectivity state
subMapType mSubTransactions; // all accepted transactions
subMapType mSubRTTransactions; // all proposed and accepted transactions
JSONCache mJSONCache;
JSONCache mJSONCache;
TaggedCache< uint256, Blob , UptimeTimerAdapter > mFetchPack;
uint32 mLastFetchPack;
uint32 mFetchSeq;
TaggedCache< uint256, Blob , UptimeTimerAdapter > mFetchPack;
uint32 mLastFetchPack;
uint32 mFetchSeq;
uint32 mLastLoadBase;
uint32 mLastLoadFactor;
uint32 mLastLoadBase;
uint32 mLastLoadFactor;
void setMode(OperatingMode);
void setMode (OperatingMode);
Json::Value transJson(const SerializedTransaction& stTxn, TER terResult, bool bValidated, Ledger::ref lpCurrent);
bool haveConsensusObject();
Json::Value transJson (const SerializedTransaction& stTxn, TER terResult, bool bValidated, Ledger::ref lpCurrent);
bool haveConsensusObject ();
Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const RippleAddress& naAccountID);
Json::Value pubBootstrapAccountInfo (Ledger::ref lpAccepted, const RippleAddress& naAccountID);
void pubValidatedTransaction(Ledger::ref alAccepted, const AcceptedLedgerTx& alTransaction);
void pubAccountTransaction(Ledger::ref lpCurrent, const AcceptedLedgerTx& alTransaction, bool isAccepted);
void pubValidatedTransaction (Ledger::ref alAccepted, const AcceptedLedgerTx& alTransaction);
void pubAccountTransaction (Ledger::ref lpCurrent, const AcceptedLedgerTx& alTransaction, bool isAccepted);
void pubServer();
void pubServer ();
};
#endif

View File

@@ -1,28 +1,28 @@
NicknameState::NicknameState(SerializedLedgerEntry::pointer ledgerEntry) :
mLedgerEntry(ledgerEntry)
NicknameState::NicknameState (SerializedLedgerEntry::pointer ledgerEntry) :
mLedgerEntry (ledgerEntry)
{
if (!mLedgerEntry || mLedgerEntry->getType() != ltNICKNAME) return;
if (!mLedgerEntry || mLedgerEntry->getType () != ltNICKNAME) return;
}
bool NicknameState::haveMinimumOffer() const
bool NicknameState::haveMinimumOffer () const
{
return mLedgerEntry->isFieldPresent(sfMinimumOffer);
return mLedgerEntry->isFieldPresent (sfMinimumOffer);
}
STAmount NicknameState::getMinimumOffer() const
STAmount NicknameState::getMinimumOffer () const
{
return mLedgerEntry->isFieldPresent(sfMinimumOffer)
? mLedgerEntry->getFieldAmount(sfMinimumOffer)
: STAmount();
return mLedgerEntry->isFieldPresent (sfMinimumOffer)
? mLedgerEntry->getFieldAmount (sfMinimumOffer)
: STAmount ();
}
RippleAddress NicknameState::getAccountID() const
RippleAddress NicknameState::getAccountID () const
{
return mLedgerEntry->getFieldAccount(sfAccount);
return mLedgerEntry->getFieldAccount (sfAccount);
}
void NicknameState::addJson(Json::Value& val)
void NicknameState::addJson (Json::Value& val)
{
val = mLedgerEntry->getJson(0);
val = mLedgerEntry->getJson (0);
}

View File

@@ -9,24 +9,33 @@
class NicknameState
{
public:
typedef boost::shared_ptr <NicknameState> pointer;
typedef boost::shared_ptr <NicknameState> pointer;
public:
explicit NicknameState (SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
explicit NicknameState (SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
bool haveMinimumOffer() const;
STAmount getMinimumOffer() const;
RippleAddress getAccountID() const;
bool haveMinimumOffer () const;
STAmount getMinimumOffer () const;
RippleAddress getAccountID () const;
SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; }
const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; }
SerializedLedgerEntry& peekSLE() { return *mLedgerEntry; }
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
const SerializedLedgerEntry& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Blob getRaw() const;
void addJson(Json::Value& value);
Blob getRaw () const;
void addJson (Json::Value& value);
private:
SerializedLedgerEntry::pointer mLedgerEntry;
SerializedLedgerEntry::pointer mLedgerEntry;
};
#endif

View File

@@ -1,25 +1,28 @@
AccountItem::pointer Offer::makeItem(const uint160& ,SerializedLedgerEntry::ref ledgerEntry)
AccountItem::pointer Offer::makeItem (const uint160& , SerializedLedgerEntry::ref ledgerEntry)
{
if (!ledgerEntry || ledgerEntry->getType() != ltOFFER) return(AccountItem::pointer());
Offer* offer=new Offer(ledgerEntry);
return(AccountItem::pointer(offer));
if (!ledgerEntry || ledgerEntry->getType () != ltOFFER) return (AccountItem::pointer ());
Offer* offer = new Offer (ledgerEntry);
return (AccountItem::pointer (offer));
}
Offer::Offer(SerializedLedgerEntry::pointer ledgerEntry) : AccountItem(ledgerEntry),
mAccount(mLedgerEntry->getFieldAccount(sfAccount)),
mTakerGets(mLedgerEntry->getFieldAmount(sfTakerGets)),
mTakerPays(mLedgerEntry->getFieldAmount(sfTakerPays)),
mSeq(mLedgerEntry->getFieldU32(sfSequence))
{ ; }
Json::Value Offer::getJson(int)
Offer::Offer (SerializedLedgerEntry::pointer ledgerEntry) : AccountItem (ledgerEntry),
mAccount (mLedgerEntry->getFieldAccount (sfAccount)),
mTakerGets (mLedgerEntry->getFieldAmount (sfTakerGets)),
mTakerPays (mLedgerEntry->getFieldAmount (sfTakerPays)),
mSeq (mLedgerEntry->getFieldU32 (sfSequence))
{
Json::Value ret(Json::objectValue);
ret["account"] = mAccount.humanAccountID();
ret["taker_gets"] = getTakerGets().getFullText();
ret["taker_pays"] = getTakerPays().getFullText();
return ret;
;
}
Json::Value Offer::getJson (int)
{
Json::Value ret (Json::objectValue);
ret["account"] = mAccount.humanAccountID ();
ret["taker_gets"] = getTakerGets ().getFullText ();
ret["taker_pays"] = getTakerPays ().getFullText ();
return ret;
}
// vim:ts=4

View File

@@ -4,29 +4,44 @@
class Offer : public AccountItem
{
public:
Offer () {}
virtual ~Offer(){}
AccountItem::pointer makeItem (const uint160&, SerializedLedgerEntry::ref ledgerEntry);
LedgerEntryType getType(){ return(ltOFFER); }
Offer () {}
const STAmount& getTakerPays(){ return(mTakerPays); }
const STAmount& getTakerGets(){ return(mTakerGets); }
const RippleAddress& getAccount(){ return(mAccount); }
int getSeq(){ return(mSeq); }
Json::Value getJson(int);
virtual ~Offer () {}
AccountItem::pointer makeItem (const uint160&, SerializedLedgerEntry::ref ledgerEntry);
LedgerEntryType getType ()
{
return (ltOFFER);
}
const STAmount& getTakerPays ()
{
return (mTakerPays);
}
const STAmount& getTakerGets ()
{
return (mTakerGets);
}
const RippleAddress& getAccount ()
{
return (mAccount);
}
int getSeq ()
{
return (mSeq);
}
Json::Value getJson (int);
private:
// For accounts in a ledger
explicit Offer (SerializedLedgerEntry::pointer ledgerEntry);
explicit Offer (SerializedLedgerEntry::pointer ledgerEntry);
private:
RippleAddress mAccount;
STAmount mTakerGets;
STAmount mTakerPays;
int mSeq;
RippleAddress mAccount;
STAmount mTakerGets;
STAmount mTakerPays;
int mSeq;
};
#endif

View File

@@ -1,52 +1,52 @@
SETUP_LOG (OfferCancelTransactor)
TER OfferCancelTransactor::doApply()
TER OfferCancelTransactor::doApply ()
{
TER terResult;
const uint32 uOfferSequence = mTxn.getFieldU32(sfOfferSequence);
const uint32 uAccountSequenceNext = mTxnAccount->getFieldU32(sfSequence);
TER terResult;
const uint32 uOfferSequence = mTxn.getFieldU32 (sfOfferSequence);
const uint32 uAccountSequenceNext = mTxnAccount->getFieldU32 (sfSequence);
WriteLog (lsDEBUG, OfferCancelTransactor) << "OfferCancel: uAccountSequenceNext=" << uAccountSequenceNext << " uOfferSequence=" << uOfferSequence;
WriteLog (lsDEBUG, OfferCancelTransactor) << "OfferCancel: uAccountSequenceNext=" << uAccountSequenceNext << " uOfferSequence=" << uOfferSequence;
const uint32 uTxFlags = mTxn.getFlags();
const uint32 uTxFlags = mTxn.getFlags ();
if (uTxFlags)
{
WriteLog (lsINFO, OfferCancelTransactor) << "OfferCancel: Malformed transaction: Invalid flags set.";
if (uTxFlags)
{
WriteLog (lsINFO, OfferCancelTransactor) << "OfferCancel: Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
return temINVALID_FLAG;
}
if (!uOfferSequence || uAccountSequenceNext-1 <= uOfferSequence)
{
WriteLog (lsINFO, OfferCancelTransactor) << "OfferCancel: uAccountSequenceNext=" << uAccountSequenceNext << " uOfferSequence=" << uOfferSequence;
if (!uOfferSequence || uAccountSequenceNext - 1 <= uOfferSequence)
{
WriteLog (lsINFO, OfferCancelTransactor) << "OfferCancel: uAccountSequenceNext=" << uAccountSequenceNext << " uOfferSequence=" << uOfferSequence;
terResult = temBAD_SEQUENCE;
}
else
{
const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uOfferSequence);
SLE::pointer sleOffer = mEngine->entryCache(ltOFFER, uOfferIndex);
terResult = temBAD_SEQUENCE;
}
else
{
const uint256 uOfferIndex = Ledger::getOfferIndex (mTxnAccountID, uOfferSequence);
SLE::pointer sleOffer = mEngine->entryCache (ltOFFER, uOfferIndex);
if (sleOffer)
{
WriteLog (lsWARNING, OfferCancelTransactor) << "OfferCancel: uOfferSequence=" << uOfferSequence;
if (sleOffer)
{
WriteLog (lsWARNING, OfferCancelTransactor) << "OfferCancel: uOfferSequence=" << uOfferSequence;
terResult = mEngine->getNodes().offerDelete(sleOffer, uOfferIndex, mTxnAccountID);
}
else
{
WriteLog (lsWARNING, OfferCancelTransactor) << "OfferCancel: offer not found: "
<< RippleAddress::createHumanAccountID(mTxnAccountID)
<< " : " << uOfferSequence
<< " : " << uOfferIndex.ToString();
terResult = mEngine->getNodes ().offerDelete (sleOffer, uOfferIndex, mTxnAccountID);
}
else
{
WriteLog (lsWARNING, OfferCancelTransactor) << "OfferCancel: offer not found: "
<< RippleAddress::createHumanAccountID (mTxnAccountID)
<< " : " << uOfferSequence
<< " : " << uOfferIndex.ToString ();
terResult = tesSUCCESS;
}
}
terResult = tesSUCCESS;
}
}
return terResult;
return terResult;
}
// vim:ts=4

View File

@@ -6,9 +6,9 @@
class OfferCancelTransactor : public Transactor
{
public:
OfferCancelTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {}
OfferCancelTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : Transactor (txn, params, engine) {}
TER doApply();
TER doApply ();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -6,36 +6,36 @@
class OfferCreateTransactor : public Transactor
{
public:
OfferCreateTransactor (const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {}
TER doApply();
OfferCreateTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : Transactor (txn, params, engine) {}
TER doApply ();
private:
bool bValidOffer(
SLE::ref sleOfferDir,
uint256 const& uOffer,
const uint160& uOfferOwnerID,
const STAmount& saOfferPays,
const STAmount& saOfferGets,
const uint160& uTakerAccountID,
boost::unordered_set<uint256>& usOfferUnfundedFound,
boost::unordered_set<uint256>& usOfferUnfundedBecame,
boost::unordered_set<uint160>& usAccountTouched,
STAmount& saOfferFunds);
bool bValidOffer (
SLE::ref sleOfferDir,
uint256 const& uOffer,
const uint160& uOfferOwnerID,
const STAmount& saOfferPays,
const STAmount& saOfferGets,
const uint160& uTakerAccountID,
boost::unordered_set<uint256>& usOfferUnfundedFound,
boost::unordered_set<uint256>& usOfferUnfundedBecame,
boost::unordered_set<uint160>& usAccountTouched,
STAmount& saOfferFunds);
TER takeOffers(
const bool bOpenLedger,
const bool bPassive,
const bool bSell,
uint256 const& uBookBase,
const uint160& uTakerAccountID,
SLE::ref sleTakerAccount,
const STAmount& saTakerPays,
const STAmount& saTakerGets,
STAmount& saTakerPaid,
STAmount& saTakerGot,
bool& bUnfunded);
TER takeOffers (
const bool bOpenLedger,
const bool bPassive,
const bool bSell,
uint256 const& uBookBase,
const uint160& uTakerAccountID,
SLE::ref sleTakerAccount,
const STAmount& saTakerPays,
const STAmount& saTakerGets,
STAmount& saTakerPaid,
STAmount& saTakerGot,
bool& bUnfunded);
boost::unordered_set<uint256> usOfferUnfundedFound; // Offers found unfunded.
boost::unordered_set<uint256> usOfferUnfundedFound; // Offers found unfunded.
};

View File

@@ -4,12 +4,13 @@ We also need to charge for each op
*/
namespace Script {
int Operation::getFee()
namespace Script
{
return(theConfig.FEE_CONTRACT_OPERATION);
int Operation::getFee ()
{
return (theConfig.FEE_CONTRACT_OPERATION);
}
}

View File

@@ -1,7 +1,8 @@
#ifndef OPERATION_H
#define OPERATION_H
namespace Script {
namespace Script
{
// Contracts are non typed have variable data types
@@ -9,311 +10,347 @@ namespace Script {
class Operation
{
public:
// returns false if there was an error
virtual bool work(Interpreter* interpreter)=0;
// returns false if there was an error
virtual bool work (Interpreter* interpreter) = 0;
virtual int getFee();
virtual int getFee ();
virtual ~Operation() { ; }
virtual ~Operation ()
{
;
}
};
// this is just an Int in the code
class IntOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->getIntData();
if(data->isInt32())
{
interpreter->pushStack( data );
return(true);
}
return(false);
}
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getIntData ();
if (data->isInt32 ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class FloatOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->getFloatData();
if(data->isFloat())
{
interpreter->pushStack( data );
return(true);
}
return(false);
}
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getFloatData ();
if (data->isFloat ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class Uint160Op : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->getUint160Data();
if(data->isUint160())
{
interpreter->pushStack( data );
return(true);
}
return(false);
}
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getUint160Data ();
if (data->isUint160 ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class AddOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()+data2->getFloat())));
else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()+data2->getInt())));
return(true);
}else
{
return(false);
}
}
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () + data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () + data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class SubOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()-data2->getFloat())));
else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()-data2->getInt())));
return(true);
}else
{
return(false);
}
}
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () - data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () - data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class MulOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()*data2->getFloat())));
else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()*data2->getInt())));
return(true);
}else
{
return(false);
}
}
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat ()*data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt ()*data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class DivOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()/data2->getFloat())));
else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()/data2->getInt())));
return(true);
}else
{
return(false);
}
}
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () / data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () / data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class GtrOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
interpreter->pushStack(Data::pointer(new BoolData(data1->getFloat()>data2->getFloat())));
return(true);
}else
{
return(false);
}
}
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
interpreter->pushStack (Data::pointer (new BoolData (data1->getFloat () > data2->getFloat ())));
return (true);
}
else
{
return (false);
}
}
};
class LessOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( (data1->isInt32() || data1->isFloat()) &&
(data2->isInt32() || data2->isFloat()) )
{
interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()<data2->getFloat())));
return(true);
}else
{
return(false);
}
}
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () < data2->getFloat ())));
return (true);
}
else
{
return (false);
}
}
};
class ModOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data1=interpreter->popStack();
Data::pointer data2=interpreter->popStack();
if( data1->isInt32() && data2->isInt32() )
{
interpreter->pushStack(Data::pointer(new IntData(data1->getInt()%data2->getInt())));
return(true);
}else
{
return(false);
}
}
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( data1->isInt32 () && data2->isInt32 () )
{
interpreter->pushStack (Data::pointer (new IntData (data1->getInt () % data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class StartBlockOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer offset=interpreter->getIntData();
return(interpreter->startBlock(offset->getInt()));
}
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
return (interpreter->startBlock (offset->getInt ()));
}
};
class EndBlockOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
return(interpreter->endBlock());
}
bool work (Interpreter* interpreter)
{
return (interpreter->endBlock ());
}
};
class StopOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
interpreter->stop();
return(true);
}
bool work (Interpreter* interpreter)
{
interpreter->stop ();
return (true);
}
};
class AcceptDataOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer data=interpreter->popStack();
if(data->isInt32())
{
interpreter->pushStack( interpreter->getAcceptData(data->getInt()) );
return(true);
}
return(false);
}
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->popStack ();
if (data->isInt32 ())
{
interpreter->pushStack ( interpreter->getAcceptData (data->getInt ()) );
return (true);
}
return (false);
}
};
class JumpIfOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer offset=interpreter->getIntData();
Data::pointer cond=interpreter->popStack();
if(cond->isBool() && offset->isInt32())
{
if(cond->isTrue())
{
return(interpreter->jumpTo(offset->getInt()));
}
return(true);
}
return(false);
}
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
Data::pointer cond = interpreter->popStack ();
if (cond->isBool () && offset->isInt32 ())
{
if (cond->isTrue ())
{
return (interpreter->jumpTo (offset->getInt ()));
}
return (true);
}
return (false);
}
};
class JumpOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer offset=interpreter->getIntData();
if(offset->isInt32())
{
return(interpreter->jumpTo(offset->getInt()));
}
return(false);
}
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
if (offset->isInt32 ())
{
return (interpreter->jumpTo (offset->getInt ()));
}
return (false);
}
};
class SendXRPOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer sourceID=interpreter->popStack();
Data::pointer destID=interpreter->popStack();
Data::pointer amount=interpreter->popStack();
if(sourceID->isUint160() && destID->isUint160() && amount->isInt32() && interpreter->canSign(sourceID->getUint160()))
{
// make sure:
// source is either, this contract, issuer, or acceptor
bool work (Interpreter* interpreter)
{
Data::pointer sourceID = interpreter->popStack ();
Data::pointer destID = interpreter->popStack ();
Data::pointer amount = interpreter->popStack ();
// TODO do the send
//interpreter->pushStack( send result);
if (sourceID->isUint160 () && destID->isUint160 () && amount->isInt32 () && interpreter->canSign (sourceID->getUint160 ()))
{
// make sure:
// source is either, this contract, issuer, or acceptor
return(true);
}
// TODO do the send
//interpreter->pushStack( send result);
return(false);
}
return (true);
}
return (false);
}
};
class GetDataOp : public Operation
{
public:
bool work(Interpreter* interpreter)
{
Data::pointer index=interpreter->popStack();
if(index->isInt32())
{
interpreter->pushStack( interpreter->getContractData(index->getInt()));
return(true);
}
bool work (Interpreter* interpreter)
{
Data::pointer index = interpreter->popStack ();
return(false);
}
if (index->isInt32 ())
{
interpreter->pushStack ( interpreter->getContractData (index->getInt ()));
return (true);
}
return (false);
}
};
}

View File

@@ -1,220 +1,237 @@
SETUP_LOG (OrderBookDB)
OrderBookDB::OrderBookDB() : mSeq(0)
OrderBookDB::OrderBookDB () : mSeq (0)
{
}
void OrderBookDB::invalidate()
void OrderBookDB::invalidate ()
{
boost::recursive_mutex::scoped_lock sl(mLock);
mSeq = 0;
boost::recursive_mutex::scoped_lock sl (mLock);
mSeq = 0;
}
void OrderBookDB::setup(Ledger::ref ledger)
void OrderBookDB::setup (Ledger::ref ledger)
{
boost::unordered_set<uint256> mSeen;
boost::unordered_set<uint256> mSeen;
boost::recursive_mutex::scoped_lock sl(mLock);
boost::recursive_mutex::scoped_lock sl (mLock);
if (ledger->getLedgerSeq() == mSeq)
return;
mSeq = ledger->getLedgerSeq();
if (ledger->getLedgerSeq () == mSeq)
return;
LoadEvent::autoptr ev = theApp->getJobQueue().getLoadEventAP(jtOB_SETUP, "OrderBookDB::setup");
mSeq = ledger->getLedgerSeq ();
mDestMap.clear();
mSourceMap.clear();
LoadEvent::autoptr ev = theApp->getJobQueue ().getLoadEventAP (jtOB_SETUP, "OrderBookDB::setup");
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB>";
mDestMap.clear ();
mSourceMap.clear ();
// walk through the entire ledger looking for orderbook entries
uint256 currentIndex = ledger->getFirstLedgerIndex();
while (currentIndex.isNonZero())
{
SLE::pointer entry = ledger->getSLEi(currentIndex);
if ((entry->getType() == ltDIR_NODE) && (entry->isFieldPresent(sfExchangeRate)) &&
(entry->getFieldH256(sfRootIndex) == currentIndex))
{
const uint160& ci = entry->getFieldH160(sfTakerPaysCurrency);
const uint160& co = entry->getFieldH160(sfTakerGetsCurrency);
const uint160& ii = entry->getFieldH160(sfTakerPaysIssuer);
const uint160& io = entry->getFieldH160(sfTakerGetsIssuer);
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB>";
uint256 index = Ledger::getBookBase(ci, ii, co, io);
if (mSeen.insert(index).second)
{
// walk through the entire ledger looking for orderbook entries
uint256 currentIndex = ledger->getFirstLedgerIndex ();
while (currentIndex.isNonZero ())
{
SLE::pointer entry = ledger->getSLEi (currentIndex);
if ((entry->getType () == ltDIR_NODE) && (entry->isFieldPresent (sfExchangeRate)) &&
(entry->getFieldH256 (sfRootIndex) == currentIndex))
{
const uint160& ci = entry->getFieldH160 (sfTakerPaysCurrency);
const uint160& co = entry->getFieldH160 (sfTakerGetsCurrency);
const uint160& ii = entry->getFieldH160 (sfTakerPaysIssuer);
const uint160& io = entry->getFieldH160 (sfTakerGetsIssuer);
uint256 index = Ledger::getBookBase (ci, ii, co, io);
if (mSeen.insert (index).second)
{
// VFALCO TODO Reduce the clunkiness of these parameter wrappers
OrderBook::pointer book = boost::make_shared<OrderBook>(boost::cref(index),
boost::cref(ci), boost::cref(co), boost::cref(ii), boost::cref(io));
OrderBook::pointer book = boost::make_shared<OrderBook> (boost::cref (index),
boost::cref (ci), boost::cref (co), boost::cref (ii), boost::cref (io));
mSourceMap[currencyIssuer_ct(ci, ii)].push_back(book);
mDestMap[currencyIssuer_ct(co, io)].push_back(book);
}
}
mSourceMap[currencyIssuer_ct (ci, ii)].push_back (book);
mDestMap[currencyIssuer_ct (co, io)].push_back (book);
}
}
currentIndex = ledger->getNextLedgerIndex(currentIndex);
}
currentIndex = ledger->getNextLedgerIndex (currentIndex);
}
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB<";
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB<";
}
// return list of all orderbooks that want this issuerID and currencyID
void OrderBookDB::getBooksByTakerPays(const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet)
void OrderBookDB::getBooksByTakerPays (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet)
{
boost::recursive_mutex::scoped_lock sl(mLock);
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> >::const_iterator
it = mSourceMap.find(currencyIssuer_ct(currencyID, issuerID));
if (it != mSourceMap.end())
bookRet = it->second;
else
bookRet.clear();
boost::recursive_mutex::scoped_lock sl (mLock);
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> >::const_iterator
it = mSourceMap.find (currencyIssuer_ct (currencyID, issuerID));
if (it != mSourceMap.end ())
bookRet = it->second;
else
bookRet.clear ();
}
// return list of all orderbooks that give this issuerID and currencyID
void OrderBookDB::getBooksByTakerGets(const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet)
void OrderBookDB::getBooksByTakerGets (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet)
{
boost::recursive_mutex::scoped_lock sl(mLock);
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> >::const_iterator
it = mDestMap.find(currencyIssuer_ct(currencyID, issuerID));
if (it != mDestMap.end())
bookRet = it->second;
else
bookRet.clear();
boost::recursive_mutex::scoped_lock sl (mLock);
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> >::const_iterator
it = mDestMap.find (currencyIssuer_ct (currencyID, issuerID));
if (it != mDestMap.end ())
bookRet = it->second;
else
bookRet.clear ();
}
BookListeners::pointer OrderBookDB::makeBookListeners(const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets)
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(currencyPays, currencyGets, issuerPays, issuerGets);
if (!ret)
{
ret = boost::make_shared<BookListeners>();
mListeners[issuerPays][issuerGets][currencyPays][currencyGets] = ret;
}
return ret;
boost::recursive_mutex::scoped_lock sl (mLock);
BookListeners::pointer ret = getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
if (!ret)
{
ret = boost::make_shared<BookListeners> ();
mListeners[issuerPays][issuerGets][currencyPays][currencyGets] = ret;
}
return ret;
}
BookListeners::pointer OrderBookDB::getBookListeners(const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets)
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);
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(issuerPays);
if(it0 == mListeners.end())
return ret;
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > >::iterator
it0 = mListeners.find (issuerPays);
std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > >::iterator
it1 = (*it0).second.find(issuerGets);
if(it1 == (*it0).second.end())
return ret;
if (it0 == mListeners.end ())
return ret;
std::map<uint160, std::map<uint160, BookListeners::pointer> >::iterator it2 = (*it1).second.find(currencyPays);
if(it2 == (*it1).second.end())
return ret;
std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > >::iterator
it1 = (*it0).second.find (issuerGets);
std::map<uint160, BookListeners::pointer>::iterator it3 = (*it2).second.find(currencyGets);
if(it3 == (*it2).second.end())
return ret;
if (it1 == (*it0).second.end ())
return ret;
return (*it3).second;
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 (currencyGets);
if (it3 == (*it2).second.end ())
return ret;
return (*it3).second;
}
// Based on the meta, send the meta to the streams that are listening
// Based on the meta, send the meta to the streams that are listening
// We need to determine which streams a given meta effects
void OrderBookDB::processTxn(Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value& jvObj)
void OrderBookDB::processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value& jvObj)
{
boost::recursive_mutex::scoped_lock sl(mLock);
if (alTx.getResult() == tesSUCCESS)
{
// check if this is an offer or an offer cancel or a payment that consumes an offer
//check to see what the meta looks like
BOOST_FOREACH(STObject& node, alTx.getMeta()->getNodes())
{
try
{
if (node.getFieldU16(sfLedgerEntryType) == ltOFFER)
{
SField* field=NULL;
boost::recursive_mutex::scoped_lock sl (mLock);
if (node.getFName() == sfModifiedNode)
{
field = &sfPreviousFields;
}
else if (node.getFName() == sfCreatedNode)
{
field = &sfNewFields;
}
else if (node.getFName() == sfDeletedNode)
{
field = &sfFinalFields;
}
if (alTx.getResult () == tesSUCCESS)
{
// check if this is an offer or an offer cancel or a payment that consumes an offer
//check to see what the meta looks like
BOOST_FOREACH (STObject & node, alTx.getMeta ()->getNodes ())
{
try
{
if (node.getFieldU16 (sfLedgerEntryType) == ltOFFER)
{
SField* field = NULL;
if (field)
{
const STObject* data = dynamic_cast<const STObject*>(node.peekAtPField(*field));
if (data)
{
const STAmount& takerGets = data->getFieldAmount(sfTakerGets);
const uint160& currencyGets = takerGets.getCurrency();
const uint160& issuerGets = takerGets.getIssuer();
if (node.getFName () == sfModifiedNode)
{
field = &sfPreviousFields;
}
else if (node.getFName () == sfCreatedNode)
{
field = &sfNewFields;
}
else if (node.getFName () == sfDeletedNode)
{
field = &sfFinalFields;
}
const STAmount& takerPays = data->getFieldAmount(sfTakerPays);
const uint160& currencyPays = takerPays.getCurrency();
const uint160& issuerPays = takerPays.getIssuer();
if (field)
{
const STObject* data = dynamic_cast<const STObject*> (node.peekAtPField (*field));
// determine the OrderBook
BookListeners::pointer book =
getBookListeners(currencyPays, currencyGets, issuerPays, issuerGets);
if (book)
book->publish(jvObj);
}
}
}
}
catch (...)
{
WriteLog (lsINFO, OrderBookDB) << "Fields not found in OrderBookDB::processTxn";
}
}
}
if (data)
{
const STAmount& takerGets = data->getFieldAmount (sfTakerGets);
const uint160& currencyGets = takerGets.getCurrency ();
const uint160& issuerGets = takerGets.getIssuer ();
const STAmount& takerPays = data->getFieldAmount (sfTakerPays);
const uint160& currencyPays = takerPays.getCurrency ();
const uint160& issuerPays = takerPays.getIssuer ();
// determine the OrderBook
BookListeners::pointer book =
getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
if (book)
book->publish (jvObj);
}
}
}
}
catch (...)
{
WriteLog (lsINFO, OrderBookDB) << "Fields not found in OrderBookDB::processTxn";
}
}
}
}
void BookListeners::addSubscriber(InfoSub::ref sub)
void BookListeners::addSubscriber (InfoSub::ref sub)
{
boost::recursive_mutex::scoped_lock sl(mLock);
mListeners[sub->getSeq()] = sub;
boost::recursive_mutex::scoped_lock sl (mLock);
mListeners[sub->getSeq ()] = sub;
}
void BookListeners::removeSubscriber(uint64 seq)
void BookListeners::removeSubscriber (uint64 seq)
{
boost::recursive_mutex::scoped_lock sl(mLock);
mListeners.erase(seq);
boost::recursive_mutex::scoped_lock sl (mLock);
mListeners.erase (seq);
}
void BookListeners::publish(Json::Value& jvObj)
void BookListeners::publish (Json::Value& jvObj)
{
Json::FastWriter jfwWriter;
std::string sObj = jfwWriter.write(jvObj);
Json::FastWriter jfwWriter;
std::string sObj = jfwWriter.write (jvObj);
boost::recursive_mutex::scoped_lock sl(mLock);
NetworkOPs::subMapType::const_iterator it = mListeners.begin();
while (it != mListeners.end())
{
InfoSub::pointer p = it->second.lock();
if (p)
{
p->send(jvObj, sObj, true);
++it;
}
else
it = mListeners.erase(it);
}
boost::recursive_mutex::scoped_lock sl (mLock);
NetworkOPs::subMapType::const_iterator it = mListeners.begin ();
while (it != mListeners.end ())
{
InfoSub::pointer p = it->second.lock ();
if (p)
{
p->send (jvObj, sObj, true);
++it;
}
else
it = mListeners.erase (it);
}
}
// vim:ts=4

View File

@@ -18,48 +18,48 @@ typedef std::pair<uint160, uint160> currencyIssuer_ct; // C++ defect 106
class BookListeners
{
public:
typedef boost::shared_ptr<BookListeners> pointer;
typedef boost::shared_ptr<BookListeners> pointer;
void addSubscriber(InfoSub::ref sub);
void removeSubscriber(uint64 sub);
void publish(Json::Value& jvObj);
void addSubscriber (InfoSub::ref sub);
void removeSubscriber (uint64 sub);
void publish (Json::Value& jvObj);
private:
boost::unordered_map<uint64, InfoSub::wptr> mListeners;
boost::recursive_mutex mLock;
boost::unordered_map<uint64, InfoSub::wptr> mListeners;
boost::recursive_mutex mLock;
};
class OrderBookDB
{
public:
OrderBookDB();
void setup(Ledger::ref ledger);
void invalidate();
OrderBookDB ();
void setup (Ledger::ref ledger);
void invalidate ();
// return list of all orderbooks that want this issuerID and currencyID
void getBooksByTakerPays(const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet);
void getBooksByTakerGets(const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet);
// return list of all orderbooks that want this issuerID and currencyID
void getBooksByTakerPays (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet);
void getBooksByTakerGets (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet);
BookListeners::pointer getBookListeners(const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets);
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);
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 AcceptedLedgerTx& alTx, Json::Value& jvObj);
// see if this txn effects any orderbook
void processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value& jvObj);
private:
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> > mSourceMap; // by ci/ii
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> > mDestMap; // by co/io
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> > mSourceMap; // by ci/ii
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> > mDestMap; // by co/io
// issuerPays, issuerGets, currencyPays, currencyGets
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;
uint32 mSeq;
boost::recursive_mutex mLock;
};

View File

@@ -3,155 +3,175 @@
#include <boost/make_shared.hpp>
#include <boost/foreach.hpp>
bool ParameterNode::setValue(const std::string& name, const Json::Value& value, Json::Value& error)
bool ParameterNode::setValue (const std::string& name, const Json::Value& value, Json::Value& error)
{
if (name.empty()) // this node
return setValue(value, error);
if (name.empty ()) // this node
return setValue (value, error);
size_t dot = name.find('.');
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find(name);
if (it == mChildren.end())
{
error = Json::objectValue;
error["error"] = "Name not found";
error["name"] = name;
return false;
}
return it->second->setValue(value, error);
}
size_t dot = name.find ('.');
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find(name.substr(0, dot));
if (it == mChildren.end())
{
error = Json::objectValue;
error["error"] = "Name not found";
error["name"] = name;
return false;
}
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name);
ParameterNode* n = dynamic_cast<ParameterNode*>(it->second.get());
if (!n)
{
error = Json::objectValue;
error["error"] = "Node has no children";
error["name"] = it->second->getName();
return false;
}
if (it == mChildren.end ())
{
error = Json::objectValue;
error["error"] = "Name not found";
error["name"] = name;
return false;
}
return n->setValue(name.substr(dot + 1), value, error);
return it->second->setValue (value, error);
}
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name.substr (0, dot));
if (it == mChildren.end ())
{
error = Json::objectValue;
error["error"] = "Name not found";
error["name"] = name;
return false;
}
ParameterNode* n = dynamic_cast<ParameterNode*> (it->second.get ());
if (!n)
{
error = Json::objectValue;
error["error"] = "Node has no children";
error["name"] = it->second->getName ();
return false;
}
return n->setValue (name.substr (dot + 1), value, error);
}
bool ParameterNode::addNode(const std::string& name, Parameter::ref node)
bool ParameterNode::addNode (const std::string& name, Parameter::ref node)
{
if (name.empty()) // this node
return false;
if (name.empty ()) // this node
return false;
size_t dot = name.find('.');
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find(name);
if (it != mChildren.end())
return false;
mChildren[name] = node;
return true;
}
size_t dot = name.find ('.');
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find(name.substr(0, dot));
ParameterNode* n;
if (it == mChildren.end())
{ // create a new inner node
ParameterNode::pointer node = boost::make_shared<ParameterNode>(getShared(), name.substr(0, dot));
n = dynamic_cast<ParameterNode*>(node.get());
assert(n);
mChildren[name] = node;
}
else
{ // existing node passed through must be inner
ParameterNode* n = dynamic_cast<ParameterNode*>(it->second.get());
if (!n)
return false;
}
return n->addNode(name.substr(dot + 1), node);
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name);
if (it != mChildren.end ())
return false;
mChildren[name] = node;
return true;
}
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name.substr (0, dot));
ParameterNode* n;
if (it == mChildren.end ())
{
// create a new inner node
ParameterNode::pointer node = boost::make_shared<ParameterNode> (getShared (), name.substr (0, dot));
n = dynamic_cast<ParameterNode*> (node.get ());
assert (n);
mChildren[name] = node;
}
else
{
// existing node passed through must be inner
ParameterNode* n = dynamic_cast<ParameterNode*> (it->second.get ());
if (!n)
return false;
}
return n->addNode (name.substr (dot + 1), node);
}
Json::Value ParameterNode::getValue(int i) const
Json::Value ParameterNode::getValue (int i) const
{
Json::Value v(Json::objectValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH(const string_ref_pair& it, mChildren)
{
v[it.first] = it.second->getValue(i);
}
return v;
Json::Value v (Json::objectValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH (const string_ref_pair & it, mChildren)
{
v[it.first] = it.second->getValue (i);
}
return v;
}
bool ParameterNode::setValue(const Json::Value& value, Json::Value& error)
bool ParameterNode::setValue (const Json::Value& value, Json::Value& error)
{
error = Json::objectValue;
error["error"] = "Cannot end on an inner node";
error = Json::objectValue;
error["error"] = "Cannot end on an inner node";
Json::Value nodes(Json::arrayValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH(const string_ref_pair& it, mChildren)
{
nodes.append(it.first);
}
error["legal_nodes"] = nodes;
return false;
Json::Value nodes (Json::arrayValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH (const string_ref_pair & it, mChildren)
{
nodes.append (it.first);
}
error["legal_nodes"] = nodes;
return false;
}
ParameterString::ParameterString(Parameter::ref parent, const std::string& name, const std::string& value)
: Parameter(parent, name), mValue(value)
{ ; }
Json::Value ParameterString::getValue(int) const
ParameterString::ParameterString (Parameter::ref parent, const std::string& name, const std::string& value)
: Parameter (parent, name), mValue (value)
{
return Json::Value(mValue);
;
}
bool ParameterString::setValue(const Json::Value& value, Json::Value& error)
Json::Value ParameterString::getValue (int) const
{
if (!value.isConvertibleTo(Json::stringValue))
{
error = Json::objectValue;
error["error"] = "Cannot convert to string";
error["value"] = value;
return false;
}
mValue = value.asString();
return true;
return Json::Value (mValue);
}
ParameterInt::ParameterInt(Parameter::ref parent, const std::string& name, int value)
: Parameter(parent, name), mValue(value)
{ ; }
Json::Value ParameterInt::getValue(int) const
bool ParameterString::setValue (const Json::Value& value, Json::Value& error)
{
return Json::Value(mValue);
if (!value.isConvertibleTo (Json::stringValue))
{
error = Json::objectValue;
error["error"] = "Cannot convert to string";
error["value"] = value;
return false;
}
mValue = value.asString ();
return true;
}
bool ParameterInt::setValue(const Json::Value& value, Json::Value& error)
ParameterInt::ParameterInt (Parameter::ref parent, const std::string& name, int value)
: Parameter (parent, name), mValue (value)
{
if (value.isConvertibleTo(Json::intValue))
{
mValue = value.asInt();
return true;
}
if (value.isConvertibleTo(Json::stringValue))
{
try
{
mValue = lexical_cast_st<int>(value.asString());
}
catch (...)
{
}
}
error = Json::objectValue;
error["error"] = "Cannot convert to integer";
error["value"] = value;
return false;
;
}
Json::Value ParameterInt::getValue (int) const
{
return Json::Value (mValue);
}
bool ParameterInt::setValue (const Json::Value& value, Json::Value& error)
{
if (value.isConvertibleTo (Json::intValue))
{
mValue = value.asInt ();
return true;
}
if (value.isConvertibleTo (Json::stringValue))
{
try
{
mValue = lexical_cast_st<int> (value.asString ());
}
catch (...)
{
}
}
error = Json::objectValue;
error["error"] = "Cannot convert to integer";
error["value"] = value;
return false;
}

View File

@@ -2,63 +2,79 @@
#define RIPPLE_PARAMETERTABLE_H
class Parameter : public boost::enable_shared_from_this<Parameter>
{ // abstract base class parameters are derived from
{
// abstract base class parameters are derived from
public:
typedef boost::shared_ptr<Parameter> pointer;
typedef const boost::shared_ptr<Parameter>& ref;
typedef boost::shared_ptr<Parameter> pointer;
typedef const boost::shared_ptr<Parameter>& ref;
public:
Parameter(Parameter::ref parent, const std::string& name) : mParent(parent), mName(name) { ; }
virtual ~Parameter() { ; }
Parameter (Parameter::ref parent, const std::string& name) : mParent (parent), mName (name)
{
;
}
virtual ~Parameter ()
{
;
}
const std::string& getName() const { return mName; }
const std::string& getName () const
{
return mName;
}
virtual Json::Value getValue(int) const = 0;
virtual bool setValue(const Json::Value& value, Json::Value& error) = 0;
virtual Json::Value getValue (int) const = 0;
virtual bool setValue (const Json::Value& value, Json::Value& error) = 0;
Parameter::pointer getShared() { return shared_from_this(); }
Parameter::pointer getShared ()
{
return shared_from_this ();
}
private:
pointer mParent;
std::string mName;
pointer mParent;
std::string mName;
};
class ParameterNode : public Parameter
class ParameterNode : public Parameter
{
public:
ParameterNode(Parameter::ref parent, const std::string& name) : Parameter(parent, name) { ; }
bool addChildNode(Parameter::ref node);
ParameterNode (Parameter::ref parent, const std::string& name) : Parameter (parent, name)
{
;
}
bool addChildNode (Parameter::ref node);
bool setValue(const std::string& name, const Json::Value& value, Json::Value& error);
bool addNode(const std::string& name, Parameter::ref node);
virtual Json::Value getValue(int) const;
virtual bool setValue(const Json::Value& value, Json::Value& error);
bool setValue (const std::string& name, const Json::Value& value, Json::Value& error);
bool addNode (const std::string& name, Parameter::ref node);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
std::map<std::string, Parameter::pointer> mChildren;
std::map<std::string, Parameter::pointer> mChildren;
};
class ParameterString : public Parameter
{
public:
ParameterString(Parameter::ref parent, const std::string& name, const std::string& value);
virtual Json::Value getValue(int) const;
virtual bool setValue(const Json::Value& value, Json::Value& error);
ParameterString (Parameter::ref parent, const std::string& name, const std::string& value);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
std::string mValue;
std::string mValue;
};
class ParameterInt : public Parameter
{
public:
ParameterInt(Parameter::ref parent, const std::string& name, int value);
virtual Json::Value getValue(int) const;
virtual bool setValue(const Json::Value& value, Json::Value& error);
ParameterInt (Parameter::ref parent, const std::string& name, int value);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
int mValue;
int mValue;
};
#endif

View File

@@ -4,127 +4,129 @@
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#define SECTION_DEFAULT_NAME ""
#define SECTION_DEFAULT_NAME ""
// for logging
struct ParseSectionLog { };
SETUP_LOG (ParseSectionLog)
section ParseSection(const std::string& strInput, const bool bTrim)
section ParseSection (const std::string& strInput, const bool bTrim)
{
std::string strData(strInput);
std::string strData (strInput);
std::vector<std::string> vLines;
section secResult;
// Convert DOS format to unix.
boost::algorithm::replace_all(strData, "\r\n", "\n");
boost::algorithm::replace_all (strData, "\r\n", "\n");
// Convert MacOS format to unix.
boost::algorithm::replace_all(strData, "\r", "\n");
boost::algorithm::replace_all (strData, "\r", "\n");
boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of("\n"));
boost::algorithm::split (vLines, strData, boost::algorithm::is_any_of ("\n"));
// Set the default section name.
std::string strSection = SECTION_DEFAULT_NAME;
// Initialize the default section.
secResult[strSection] = section::mapped_type();
secResult[strSection] = section::mapped_type ();
// Parse each line.
BOOST_FOREACH(std::string& strValue, vLines)
BOOST_FOREACH (std::string & strValue, vLines)
{
if (strValue.empty() || strValue[0] == '#')
{
// Blank line or comment, do nothing.
if (strValue.empty () || strValue[0] == '#')
{
// Blank line or comment, do nothing.
nothing();
}
else if (strValue[0] == '[' && strValue[strValue.length()-1] == ']') {
// New section.
nothing ();
}
else if (strValue[0] == '[' && strValue[strValue.length () - 1] == ']')
{
// New section.
strSection = strValue.substr(1, strValue.length()-2);
secResult[strSection] = section::mapped_type();
}
else
{
// Another line for section.
if (bTrim)
boost::algorithm::trim(strValue);
strSection = strValue.substr (1, strValue.length () - 2);
secResult[strSection] = section::mapped_type ();
}
else
{
// Another line for section.
if (bTrim)
boost::algorithm::trim (strValue);
if (!strValue.empty())
secResult[strSection].push_back(strValue);
}
if (!strValue.empty ())
secResult[strSection].push_back (strValue);
}
}
return secResult;
}
void sectionEntriesPrint(std::vector<std::string>* vspEntries, const std::string& strSection)
void sectionEntriesPrint (std::vector<std::string>* vspEntries, const std::string& strSection)
{
std::cerr << "[" << strSection << "]" << std::endl;
std::cerr << "[" << strSection << "]" << std::endl;
if (vspEntries)
{
BOOST_FOREACH(std::string& strValue, *vspEntries)
{
std::cerr << strValue << std::endl;
}
}
}
void sectionPrint(section secInput)
{
BOOST_FOREACH(section::value_type& pairSection, secInput)
if (vspEntries)
{
sectionEntriesPrint(&pairSection.second, pairSection.first);
BOOST_FOREACH (std::string & strValue, *vspEntries)
{
std::cerr << strValue << std::endl;
}
}
}
section::mapped_type* sectionEntries(section& secSource, const std::string& strSection)
void sectionPrint (section secInput)
{
section::iterator it;
section::mapped_type* smtResult;
it = secSource.find(strSection);
if (it == secSource.end())
BOOST_FOREACH (section::value_type & pairSection, secInput)
{
smtResult = 0;
}
else
{
//section::mapped_type& vecEntries = it->second;
smtResult = &(it->second);
}
return smtResult;
}
int sectionCount(section& secSource, const std::string& strSection)
{
section::mapped_type* pmtEntries = sectionEntries(secSource, strSection);
return pmtEntries ? -1 : pmtEntries->size();
}
bool sectionSingleB(section& secSource, const std::string& strSection, std::string& strValue)
{
section::mapped_type* pmtEntries = sectionEntries(secSource, strSection);
bool bSingle = pmtEntries && 1 == pmtEntries->size();
if (bSingle)
{
strValue = (*pmtEntries)[0];
sectionEntriesPrint (&pairSection.second, pairSection.first);
}
else if (pmtEntries)
{
WriteLog (lsWARNING, ParseSectionLog) << boost::str(boost::format("Section [%s]: requires 1 line not %d lines.")
% strSection
% pmtEntries->size());
}
}
return bSingle;
section::mapped_type* sectionEntries (section& secSource, const std::string& strSection)
{
section::iterator it;
section::mapped_type* smtResult;
it = secSource.find (strSection);
if (it == secSource.end ())
{
smtResult = 0;
}
else
{
//section::mapped_type& vecEntries = it->second;
smtResult = & (it->second);
}
return smtResult;
}
int sectionCount (section& secSource, const std::string& strSection)
{
section::mapped_type* pmtEntries = sectionEntries (secSource, strSection);
return pmtEntries ? -1 : pmtEntries->size ();
}
bool sectionSingleB (section& secSource, const std::string& strSection, std::string& strValue)
{
section::mapped_type* pmtEntries = sectionEntries (secSource, strSection);
bool bSingle = pmtEntries && 1 == pmtEntries->size ();
if (bSingle)
{
strValue = (*pmtEntries)[0];
}
else if (pmtEntries)
{
WriteLog (lsWARNING, ParseSectionLog) << boost::str (boost::format ("Section [%s]: requires 1 line not %d lines.")
% strSection
% pmtEntries->size ());
}
return bSingle;
}
// vim:ts=4

View File

@@ -7,11 +7,11 @@
typedef std::map<const std::string, std::vector<std::string> > section;
section ParseSection(const std::string& strInput, const bool bTrim);
void sectionPrint(section secInput);
void sectionEntriesPrint(std::vector<std::string>* vspEntries, const std::string& strSection);
bool sectionSingleB(section& secSource, const std::string& strSection, std::string& strValue);
int sectionCount(section& secSource, const std::string& strSection);
section::mapped_type* sectionEntries(section& secSource, const std::string& strSection);
section ParseSection (const std::string& strInput, const bool bTrim);
void sectionPrint (section secInput);
void sectionEntriesPrint (std::vector<std::string>* vspEntries, const std::string& strSection);
bool sectionSingleB (section& secSource, const std::string& strSection, std::string& strValue);
int sectionCount (section& secSource, const std::string& strSection);
section::mapped_type* sectionEntries (section& secSource, const std::string& strSection);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -16,87 +16,93 @@ be to flood from both directions.
class PathOption
{
public:
typedef boost::shared_ptr<PathOption> pointer;
typedef const boost::shared_ptr<PathOption>& ref;
typedef boost::shared_ptr<PathOption> pointer;
typedef const boost::shared_ptr<PathOption>& ref;
STPath mPath;
bool mCorrectCurrency; // for the sorting
uint160 mCurrencyID; // what currency we currently have at the end of the path
uint160 mCurrentAccount; // what account is at the end of the path
int mTotalCost; // in send currency
STAmount mMinWidth; // in dest currency
float mQuality;
STPath mPath;
bool mCorrectCurrency; // for the sorting
uint160 mCurrencyID; // what currency we currently have at the end of the path
uint160 mCurrentAccount; // what account is at the end of the path
int mTotalCost; // in send currency
STAmount mMinWidth; // in dest currency
float mQuality;
PathOption(uint160& srcAccount,uint160& srcCurrencyID,const uint160& dstCurrencyID);
PathOption(PathOption::pointer other);
PathOption (uint160& srcAccount, uint160& srcCurrencyID, const uint160& dstCurrencyID);
PathOption (PathOption::pointer other);
};
#endif
class RLCache
{
public:
typedef boost::shared_ptr<RLCache> pointer;
typedef const pointer& ref;
typedef boost::shared_ptr<RLCache> pointer;
typedef const pointer& ref;
RLCache(Ledger::ref l) : mLedger(l) { ; }
Ledger::ref getLedger() { return mLedger; }
RLCache (Ledger::ref l) : mLedger (l)
{
;
}
Ledger::ref getLedger ()
{
return mLedger;
}
AccountItems& getRippleLines(const uint160& accountID);
AccountItems& getRippleLines (const uint160& accountID);
private:
boost::mutex mLock;
Ledger::pointer mLedger;
boost::unordered_map<uint160, AccountItems::pointer> mRLMap;
boost::mutex mLock;
Ledger::pointer mLedger;
boost::unordered_map<uint160, AccountItems::pointer> mRLMap;
};
class Pathfinder
{
public:
Pathfinder(RLCache::ref cache,
const RippleAddress& srcAccountID, const RippleAddress& dstAccountID,
const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount, bool& bValid);
Pathfinder (RLCache::ref cache,
const RippleAddress& srcAccountID, const RippleAddress& dstAccountID,
const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount, bool& bValid);
bool findPaths(const unsigned int iMaxSteps, const unsigned int iMaxPaths, STPathSet& spsDst);
bool findPaths (const unsigned int iMaxSteps, const unsigned int iMaxPaths, STPathSet& spsDst);
bool bDefaultPath(const STPath& spPath);
bool bDefaultPath (const STPath& spPath);
private:
uint160 mSrcAccountID;
uint160 mDstAccountID;
STAmount mDstAmount;
uint160 mSrcCurrencyID;
uint160 mSrcIssuerID;
STAmount mSrcAmount;
uint160 mSrcAccountID;
uint160 mDstAccountID;
STAmount mDstAmount;
uint160 mSrcCurrencyID;
uint160 mSrcIssuerID;
STAmount mSrcAmount;
Ledger::pointer mLedger;
PathState::pointer mPsDefault;
LoadEvent::pointer m_loadEvent;
RLCache::pointer mRLCache;
Ledger::pointer mLedger;
PathState::pointer mPsDefault;
LoadEvent::pointer m_loadEvent;
RLCache::pointer mRLCache;
boost::unordered_map<uint160, AccountItems::pointer> mRLMap;
boost::unordered_map<std::pair<uint160, uint160>, int> mPOMap;
boost::unordered_map<uint160, AccountItems::pointer> mRLMap;
boost::unordered_map<std::pair<uint160, uint160>, int> mPOMap;
// std::list<PathOption::pointer> mBuildingPaths;
// std::list<PathOption::pointer> mCompletePaths;
// std::list<PathOption::pointer> mBuildingPaths;
// std::list<PathOption::pointer> mCompletePaths;
// void addOptions(PathOption::pointer tail);
// void addOptions(PathOption::pointer tail);
// returns true if any building paths are now complete?
bool checkComplete(STPathSet& retPathSet);
// returns true if any building paths are now complete?
bool checkComplete (STPathSet& retPathSet);
// void addPathOption(PathOption::pointer pathOption);
// void addPathOption(PathOption::pointer pathOption);
bool matchesOrigin(const uint160& currency, const uint160& issuer);
bool matchesOrigin (const uint160& currency, const uint160& issuer);
int getPathsOut(const uint160& currency, const uint160& accountID,
bool isAuthRequired, bool isDestCurrency, const uint160& dest);
int getPathsOut (const uint160& currency, const uint160& accountID,
bool isAuthRequired, bool isDestCurrency, const uint160& dest);
};
boost::unordered_set<uint160> usAccountDestCurrencies(const RippleAddress& raAccountID, Ledger::ref lrLedger,
bool includeXRP);
boost::unordered_set<uint160> usAccountDestCurrencies (const RippleAddress& raAccountID, Ledger::ref lrLedger,
bool includeXRP);
boost::unordered_set<uint160> usAccountSourceCurrencies(const RippleAddress& raAccountID, Ledger::ref lrLedger,
bool includeXRP);
boost::unordered_set<uint160> usAccountSourceCurrencies (const RippleAddress& raAccountID, Ledger::ref lrLedger,
bool includeXRP);
#endif

View File

@@ -1,240 +1,241 @@
SETUP_LOG (PaymentTransactor)
#define RIPPLE_PATHS_MAX 6
#define RIPPLE_PATHS_MAX 6
TER PaymentTransactor::doApply()
TER PaymentTransactor::doApply ()
{
// Ripple if source or destination is non-native or if there are paths.
const uint32 uTxFlags = mTxn.getFlags();
const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment);
const bool bLimitQuality = isSetBit(uTxFlags, tfLimitQuality);
const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect);
const bool bPaths = mTxn.isFieldPresent(sfPaths);
const bool bMax = mTxn.isFieldPresent(sfSendMax);
const uint160 uDstAccountID = mTxn.getFieldAccount160(sfDestination);
const STAmount saDstAmount = mTxn.getFieldAmount(sfAmount);
const STAmount saMaxAmount = bMax
? mTxn.getFieldAmount(sfSendMax)
: saDstAmount.isNative()
? saDstAmount
: STAmount(saDstAmount.getCurrency(), mTxnAccountID, saDstAmount.getMantissa(), saDstAmount.getExponent(), saDstAmount.isNegative());
const uint160 uSrcCurrency = saMaxAmount.getCurrency();
const uint160 uDstCurrency = saDstAmount.getCurrency();
const bool bXRPDirect = uSrcCurrency.isZero() && uDstCurrency.isZero();
// Ripple if source or destination is non-native or if there are paths.
const uint32 uTxFlags = mTxn.getFlags ();
const bool bPartialPayment = isSetBit (uTxFlags, tfPartialPayment);
const bool bLimitQuality = isSetBit (uTxFlags, tfLimitQuality);
const bool bNoRippleDirect = isSetBit (uTxFlags, tfNoRippleDirect);
const bool bPaths = mTxn.isFieldPresent (sfPaths);
const bool bMax = mTxn.isFieldPresent (sfSendMax);
const uint160 uDstAccountID = mTxn.getFieldAccount160 (sfDestination);
const STAmount saDstAmount = mTxn.getFieldAmount (sfAmount);
const STAmount saMaxAmount = bMax
? mTxn.getFieldAmount (sfSendMax)
: saDstAmount.isNative ()
? saDstAmount
: STAmount (saDstAmount.getCurrency (), mTxnAccountID, saDstAmount.getMantissa (), saDstAmount.getExponent (), saDstAmount.isNegative ());
const uint160 uSrcCurrency = saMaxAmount.getCurrency ();
const uint160 uDstCurrency = saDstAmount.getCurrency ();
const bool bXRPDirect = uSrcCurrency.isZero () && uDstCurrency.isZero ();
WriteLog (lsINFO, PaymentTransactor) << boost::str(boost::format("Payment> saMaxAmount=%s saDstAmount=%s")
% saMaxAmount.getFullText()
% saDstAmount.getFullText());
WriteLog (lsINFO, PaymentTransactor) << boost::str (boost::format ("Payment> saMaxAmount=%s saDstAmount=%s")
% saMaxAmount.getFullText ()
% saDstAmount.getFullText ());
if (!saDstAmount.isLegalNet() || !saMaxAmount.isLegalNet())
return temBAD_AMOUNT;
if (!saDstAmount.isLegalNet () || !saMaxAmount.isLegalNet ())
return temBAD_AMOUNT;
if (uTxFlags & tfPaymentMask)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Invalid flags set.";
if (uTxFlags & tfPaymentMask)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
else if (!uDstAccountID)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Payment destination account not specified.";
return temINVALID_FLAG;
}
else if (!uDstAccountID)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Payment destination account not specified.";
return temDST_NEEDED;
}
else if (bMax && !saMaxAmount.isPositive())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: bad max amount: " << saMaxAmount.getFullText();
return temDST_NEEDED;
}
else if (bMax && !saMaxAmount.isPositive ())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: bad max amount: " << saMaxAmount.getFullText ();
return temBAD_AMOUNT;
}
else if (!saDstAmount.isPositive())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: bad dst amount: " << saDstAmount.getFullText();
return temBAD_AMOUNT;
}
else if (!saDstAmount.isPositive ())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: bad dst amount: " << saDstAmount.getFullText ();
return temBAD_AMOUNT;
}
else if (CURRENCY_BAD == uSrcCurrency || CURRENCY_BAD == uDstCurrency)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Bad currency.";
return temBAD_AMOUNT;
}
else if (CURRENCY_BAD == uSrcCurrency || CURRENCY_BAD == uDstCurrency)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Bad currency.";
return temBAD_CURRENCY;
}
else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
{
WriteLog (lsINFO, PaymentTransactor) << boost::str(boost::format("Payment: Malformed transaction: Redundant transaction: src=%s, dst=%s, src_cur=%s, dst_cur=%s")
% mTxnAccountID.ToString()
% uDstAccountID.ToString()
% uSrcCurrency.ToString()
% uDstCurrency.ToString());
return temBAD_CURRENCY;
}
else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
{
WriteLog (lsINFO, PaymentTransactor) << boost::str (boost::format ("Payment: Malformed transaction: Redundant transaction: src=%s, dst=%s, src_cur=%s, dst_cur=%s")
% mTxnAccountID.ToString ()
% uDstAccountID.ToString ()
% uSrcCurrency.ToString ()
% uDstCurrency.ToString ());
return temREDUNDANT;
}
else if (bMax && saMaxAmount == saDstAmount && saMaxAmount.getCurrency() == saDstAmount.getCurrency())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Redundant SendMax.";
return temREDUNDANT;
}
else if (bMax && saMaxAmount == saDstAmount && saMaxAmount.getCurrency () == saDstAmount.getCurrency ())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Redundant SendMax.";
return temREDUNDANT_SEND_MAX;
}
else if (bXRPDirect && bMax)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: SendMax specified for XRP to XRP.";
return temREDUNDANT_SEND_MAX;
}
else if (bXRPDirect && bMax)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: SendMax specified for XRP to XRP.";
return temBAD_SEND_XRP_MAX;
}
else if (bXRPDirect && bPaths)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Paths specified for XRP to XRP.";
return temBAD_SEND_XRP_MAX;
}
else if (bXRPDirect && bPaths)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Paths specified for XRP to XRP.";
return temBAD_SEND_XRP_PATHS;
}
else if (bXRPDirect && bPartialPayment)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Partial payment specified for XRP to XRP.";
return temBAD_SEND_XRP_PATHS;
}
else if (bXRPDirect && bPartialPayment)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Partial payment specified for XRP to XRP.";
return temBAD_SEND_XRP_PARTIAL;
}
else if (bXRPDirect && bLimitQuality)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Limit quality specified for XRP to XRP.";
return temBAD_SEND_XRP_PARTIAL;
}
else if (bXRPDirect && bLimitQuality)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: Limit quality specified for XRP to XRP.";
return temBAD_SEND_XRP_LIMIT;
}
else if (bXRPDirect && bNoRippleDirect)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: No ripple direct specified for XRP to XRP.";
return temBAD_SEND_XRP_LIMIT;
}
else if (bXRPDirect && bNoRippleDirect)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: No ripple direct specified for XRP to XRP.";
return temBAD_SEND_XRP_NO_DIRECT;
}
return temBAD_SEND_XRP_NO_DIRECT;
}
SLE::pointer sleDst = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
if (!sleDst)
{
// Destination account does not exist.
SLE::pointer sleDst = mEngine->entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uDstAccountID));
if (!saDstAmount.isNative())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Delay transaction: Destination account does not exist.";
if (!sleDst)
{
// Destination account does not exist.
// Another transaction could create the account and then this transaction would succeed.
return tecNO_DST;
}
else if (isSetBit(mParams, tapOPEN_LEDGER) && bPartialPayment)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Delay transaction: Partial payment not allowed to create account.";
// Make retry work smaller, by rejecting this.
if (!saDstAmount.isNative ())
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Delay transaction: Destination account does not exist.";
// Another transaction could create the account and then this transaction would succeed.
return telNO_DST_PARTIAL;
}
else if (saDstAmount.getNValue() < mEngine->getLedger()->getReserve(0)) // Reserve is not scaled by load.
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Delay transaction: Destination account does not exist. Insufficent payment to create account.";
// Another transaction could create the account and then this transaction would succeed.
return tecNO_DST;
}
else if (isSetBit (mParams, tapOPEN_LEDGER) && bPartialPayment)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Delay transaction: Partial payment not allowed to create account.";
// Make retry work smaller, by rejecting this.
// Another transaction could create the account and then this transaction would succeed.
return tecNO_DST_INSUF_XRP;
}
// Another transaction could create the account and then this transaction would succeed.
return telNO_DST_PARTIAL;
}
else if (saDstAmount.getNValue () < mEngine->getLedger ()->getReserve (0)) // Reserve is not scaled by load.
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Delay transaction: Destination account does not exist. Insufficent payment to create account.";
// Create the account.
sleDst = mEngine->entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
// Another transaction could create the account and then this transaction would succeed.
return tecNO_DST_INSUF_XRP;
}
sleDst->setFieldAccount(sfAccount, uDstAccountID);
sleDst->setFieldU32(sfSequence, 1);
}
else if ((sleDst->getFlags() & lsfRequireDestTag) && !mTxn.isFieldPresent(sfDestinationTag))
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: DestinationTag required.";
// Create the account.
sleDst = mEngine->entryCreate (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uDstAccountID));
return tefDST_TAG_NEEDED;
}
else
{
mEngine->entryModify(sleDst);
}
sleDst->setFieldAccount (sfAccount, uDstAccountID);
sleDst->setFieldU32 (sfSequence, 1);
}
else if ((sleDst->getFlags () & lsfRequireDestTag) && !mTxn.isFieldPresent (sfDestinationTag))
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Malformed transaction: DestinationTag required.";
TER terResult;
// XXX Should bMax be sufficient to imply ripple?
const bool bRipple = bPaths || bMax || !saDstAmount.isNative();
return tefDST_TAG_NEEDED;
}
else
{
mEngine->entryModify (sleDst);
}
if (bRipple)
{
// Ripple payment
TER terResult;
// XXX Should bMax be sufficient to imply ripple?
const bool bRipple = bPaths || bMax || !saDstAmount.isNative ();
STPathSet spsPaths = mTxn.getFieldPathSet(sfPaths);
std::vector<PathState::pointer> vpsExpanded;
STAmount saMaxAmountAct;
STAmount saDstAmountAct;
if (bRipple)
{
// Ripple payment
try
{
terResult = isSetBit(mParams, tapOPEN_LEDGER) && spsPaths.size() > RIPPLE_PATHS_MAX
? telBAD_PATH_COUNT // Too many paths for proposed ledger.
: RippleCalc::rippleCalc(
mEngine->getNodes(),
saMaxAmountAct,
saDstAmountAct,
vpsExpanded,
saMaxAmount,
saDstAmount,
uDstAccountID,
mTxnAccountID,
spsPaths,
bPartialPayment,
bLimitQuality,
bNoRippleDirect, // Always compute for finalizing ledger.
false, // Not standalone, delete unfundeds.
isSetBit(mParams, tapOPEN_LEDGER));
}
catch (const std::exception& e)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Caught throw: " << e.what();
STPathSet spsPaths = mTxn.getFieldPathSet (sfPaths);
std::vector<PathState::pointer> vpsExpanded;
STAmount saMaxAmountAct;
STAmount saDstAmountAct;
terResult = tefEXCEPTION;
}
}
else
{
// Direct XRP payment.
try
{
terResult = isSetBit (mParams, tapOPEN_LEDGER) && spsPaths.size () > RIPPLE_PATHS_MAX
? telBAD_PATH_COUNT // Too many paths for proposed ledger.
: RippleCalc::rippleCalc (
mEngine->getNodes (),
saMaxAmountAct,
saDstAmountAct,
vpsExpanded,
saMaxAmount,
saDstAmount,
uDstAccountID,
mTxnAccountID,
spsPaths,
bPartialPayment,
bLimitQuality,
bNoRippleDirect, // Always compute for finalizing ledger.
false, // Not standalone, delete unfundeds.
isSetBit (mParams, tapOPEN_LEDGER));
}
catch (const std::exception& e)
{
WriteLog (lsINFO, PaymentTransactor) << "Payment: Caught throw: " << e.what ();
const uint32 uOwnerCount = mTxnAccount->getFieldU32(sfOwnerCount);
const uint64 uReserve = mEngine->getLedger()->getReserve(uOwnerCount);
terResult = tefEXCEPTION;
}
}
else
{
// Direct XRP payment.
// Make sure have enough reserve to send. Allow final spend to use reserve for fee.
if (mPriorBalance < saDstAmount + uReserve) // Reserve is not scaled by fee.
{
// Vote no. However, transaction might succeed, if applied in a different order.
WriteLog (lsINFO, PaymentTransactor) << "";
WriteLog (lsINFO, PaymentTransactor) << boost::str(boost::format("Payment: Delay transaction: Insufficient funds: %s / %s (%d)")
% mPriorBalance.getText() % (saDstAmount + uReserve).getText() % uReserve);
const uint32 uOwnerCount = mTxnAccount->getFieldU32 (sfOwnerCount);
const uint64 uReserve = mEngine->getLedger ()->getReserve (uOwnerCount);
terResult = tecUNFUNDED_PAYMENT;
}
else
{
mTxnAccount->setFieldAmount(sfBalance, mSourceBalance - saDstAmount);
sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount);
// Make sure have enough reserve to send. Allow final spend to use reserve for fee.
if (mPriorBalance < saDstAmount + uReserve) // Reserve is not scaled by fee.
{
// Vote no. However, transaction might succeed, if applied in a different order.
WriteLog (lsINFO, PaymentTransactor) << "";
WriteLog (lsINFO, PaymentTransactor) << boost::str (boost::format ("Payment: Delay transaction: Insufficient funds: %s / %s (%d)")
% mPriorBalance.getText () % (saDstAmount + uReserve).getText () % uReserve);
// re-arm the password change fee if we can and need to
if ((sleDst->getFlags() & lsfPasswordSpent))
sleDst->clearFlag(lsfPasswordSpent);
terResult = tecUNFUNDED_PAYMENT;
}
else
{
mTxnAccount->setFieldAmount (sfBalance, mSourceBalance - saDstAmount);
sleDst->setFieldAmount (sfBalance, sleDst->getFieldAmount (sfBalance) + saDstAmount);
terResult = tesSUCCESS;
}
}
// re-arm the password change fee if we can and need to
if ((sleDst->getFlags () & lsfPasswordSpent))
sleDst->clearFlag (lsfPasswordSpent);
std::string strToken;
std::string strHuman;
terResult = tesSUCCESS;
}
}
if (transResultInfo(terResult, strToken, strHuman))
{
WriteLog (lsINFO, PaymentTransactor) << boost::str(boost::format("Payment: %s: %s") % strToken % strHuman);
}
else
{
assert(false);
}
std::string strToken;
std::string strHuman;
return terResult;
if (transResultInfo (terResult, strToken, strHuman))
{
WriteLog (lsINFO, PaymentTransactor) << boost::str (boost::format ("Payment: %s: %s") % strToken % strHuman);
}
else
{
assert (false);
}
return terResult;
}
// vim:ts=4

View File

@@ -6,9 +6,9 @@
class PaymentTransactor : public Transactor
{
public:
PaymentTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {}
PaymentTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : Transactor (txn, params, engine) {}
TER doApply();
TER doApply ();
};
#endif

View File

@@ -1,24 +1,24 @@
#ifndef RIPPLE_PEER_H
#define RIPPLE_PEER_H
typedef std::pair <std::string,int> ipPort;
typedef std::pair <std::string, int> ipPort;
class Peer : public boost::enable_shared_from_this <Peer>
{
public:
typedef boost::shared_ptr<Peer> pointer;
typedef const boost::shared_ptr<Peer>& ref;
typedef boost::shared_ptr<Peer> pointer;
typedef const boost::shared_ptr<Peer>& ref;
static int const psbGotHello = 0;
static int const psbGotHello = 0;
static int const psbSentHello = 1;
static int const psbInMap = 2;
static int const psbTrusted = 3;
static int const psbNoLedgers = 4;
static int const psbNoLedgers = 4;
static int const psbNoTransactions = 5;
static int const psbDownLevel = 6;
public:
static pointer New (boost::asio::io_service& io_service,
static pointer New (boost::asio::io_service& io_service,
boost::asio::ssl::context& ctx,
uint64 id,
bool inbound);
@@ -28,55 +28,55 @@ public:
boost::asio::ip::tcp::resolver::iterator it) = 0;
virtual std::string& getIP () = 0;
virtual std::string getDisplayName() = 0;
virtual std::string getDisplayName () = 0;
virtual int getPort () = 0;
virtual void setIpPort (const std::string& strIP, int iPort) = 0;
virtual void setIpPort (const std::string& strIP, int iPort) = 0;
virtual boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::lowest_layer_type& getSocket() = 0;
virtual boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::lowest_layer_type& getSocket () = 0;
virtual void connect (const std::string& strIp, int iPort) = 0;
virtual void connect (const std::string& strIp, int iPort) = 0;
virtual void connected (const boost::system::error_code& error) = 0;
virtual void detach (const char *, bool onIOStrand) = 0;
virtual void detach (const char*, bool onIOStrand) = 0;
//virtual bool samePeer (Peer::ref p) = 0;
//virtual bool samePeer (const Peer& p) = 0;
virtual void sendPacket (const PackedMessage::pointer& packet, bool onStrand) = 0;
virtual void sendPacket (const PackedMessage::pointer& packet, bool onStrand) = 0;
virtual void sendGetPeers () = 0;
virtual void punishPeer (LoadType) = 0;
virtual void punishPeer (LoadType) = 0;
// VFALCO: NOTE, what's with this odd parameter passing? Why the static member?
static void punishPeer (const boost::weak_ptr<Peer>&, LoadType);
static void punishPeer (const boost::weak_ptr<Peer>&, LoadType);
virtual Json::Value getJson () = 0;
virtual Json::Value getJson () = 0;
virtual bool isConnected () const = 0;
virtual bool isInbound () const = 0;
virtual bool isOutbound () const = 0;
virtual const uint256& getClosedLedgerHash () const = 0;
virtual bool hasLedger (const uint256& hash, uint32 seq) const = 0;
virtual bool hasTxSet (const uint256& hash) const = 0;
virtual uint64 getPeerId () const = 0;
virtual const RippleAddress& getNodePublic () const = 0;
virtual void cycleStatus () = 0;
virtual bool hasProto (int version) = 0;
virtual bool hasRange (uint32 uMin, uint32 uMax) = 0;
};

View File

@@ -4,132 +4,144 @@ SETUP_LOG (PeerDoor)
using namespace std;
using namespace boost::asio::ip;
PeerDoor::PeerDoor(boost::asio::io_service& io_service) :
mAcceptor(io_service,
tcp::endpoint(address().from_string(theConfig.PEER_IP.empty() ? "0.0.0.0" : theConfig.PEER_IP),
theConfig.PEER_PORT)),
mCtx(boost::asio::ssl::context::sslv23), mDelayTimer(io_service)
PeerDoor::PeerDoor (boost::asio::io_service& io_service) :
mAcceptor (io_service,
tcp::endpoint (address ().from_string (theConfig.PEER_IP.empty () ? "0.0.0.0" : theConfig.PEER_IP),
theConfig.PEER_PORT)),
mCtx (boost::asio::ssl::context::sslv23), mDelayTimer (io_service)
{
mCtx.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
mCtx.set_options (
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
SSL_CTX_set_tmp_dh_callback(mCtx.native_handle(), handleTmpDh);
if (1 != SSL_CTX_set_cipher_list(mCtx.native_handle(), theConfig.PEER_SSL_CIPHER_LIST.c_str()))
std::runtime_error("Error setting cipher list (no valid ciphers).");
SSL_CTX_set_tmp_dh_callback (mCtx.native_handle (), handleTmpDh);
if (1 != SSL_CTX_set_cipher_list (mCtx.native_handle (), theConfig.PEER_SSL_CIPHER_LIST.c_str ()))
std::runtime_error ("Error setting cipher list (no valid ciphers).");
if (!theConfig.PEER_IP.empty() && theConfig.PEER_PORT)
{
Log(lsINFO) << "Peer port: " << theConfig.PEER_IP << " " << theConfig.PEER_PORT;
startListening();
}
}
void PeerDoor::startListening()
{
Peer::pointer new_connection = Peer::New (
mAcceptor.get_io_service(),
mCtx,
theApp->getPeers().assignPeerId(),
true);
mAcceptor.async_accept(new_connection->getSocket(),
boost::bind(&PeerDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
void PeerDoor::handleConnect(Peer::pointer new_connection,
const boost::system::error_code& error)
{
bool delay = false;
if (!error)
{
new_connection->connected(error);
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsERROR, PeerDoor) << error;
}
if (delay)
{
mDelayTimer.expires_from_now(boost::posix_time::milliseconds(500));
mDelayTimer.async_wait(boost::bind(&PeerDoor::startListening, this));
}
else
if (!theConfig.PEER_IP.empty () && theConfig.PEER_PORT)
{
startListening();
Log (lsINFO) << "Peer port: " << theConfig.PEER_IP << " " << theConfig.PEER_PORT;
startListening ();
}
}
void PeerDoor::startListening ()
{
Peer::pointer new_connection = Peer::New (
mAcceptor.get_io_service (),
mCtx,
theApp->getPeers ().assignPeerId (),
true);
mAcceptor.async_accept (new_connection->getSocket (),
boost::bind (&PeerDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
void PeerDoor::handleConnect (Peer::pointer new_connection,
const boost::system::error_code& error)
{
bool delay = false;
if (!error)
{
new_connection->connected (error);
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsERROR, PeerDoor) << error;
}
if (delay)
{
mDelayTimer.expires_from_now (boost::posix_time::milliseconds (500));
mDelayTimer.async_wait (boost::bind (&PeerDoor::startListening, this));
}
else
{
startListening ();
}
}
void initSSLContext (boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file)
std::string key_file, std::string cert_file, std::string chain_file)
{
SSL_CTX* sslContext = context.native_handle();
SSL_CTX* sslContext = context.native_handle ();
context.set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
context.set_options (boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
bool cert_set = false;
bool cert_set = false;
if (!cert_file.empty())
{
boost::system::error_code error;
context.use_certificate_file(cert_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error("Unable to use certificate file");
cert_set = true;
}
if (!cert_file.empty ())
{
boost::system::error_code error;
context.use_certificate_file (cert_file, boost::asio::ssl::context::pem, error);
if (!chain_file.empty())
{
if (error)
throw std::runtime_error ("Unable to use certificate file");
cert_set = true;
}
if (!chain_file.empty ())
{
// VFALCO Replace fopen() with RAII
FILE *f = fopen(chain_file.c_str(), "r");
if (!f)
throw std::runtime_error("Unable to open chain file");
try
{
while (true)
{
X509 *x = PEM_read_X509(f, NULL, NULL, NULL);
if (x == NULL)
break;
if (!cert_set)
{
if (SSL_CTX_use_certificate(sslContext, x) != 1)
throw std::runtime_error("Unable to get certificate from chain file");
cert_set = true;
}
else if (SSL_CTX_add_extra_chain_cert(sslContext, x) != 1)
{
X509_free(x);
throw std::runtime_error("Unable to add chain certificate");
}
}
fclose(f);
}
catch (...)
{
fclose(f);
throw;
}
}
FILE* f = fopen (chain_file.c_str (), "r");
if (!key_file.empty())
{
boost::system::error_code error;
context.use_private_key_file(key_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error("Unable to use private key file");
}
if (!f)
throw std::runtime_error ("Unable to open chain file");
if (SSL_CTX_check_private_key(sslContext) != 1)
throw std::runtime_error("Private key not valid");
try
{
while (true)
{
X509* x = PEM_read_X509 (f, NULL, NULL, NULL);
if (x == NULL)
break;
if (!cert_set)
{
if (SSL_CTX_use_certificate (sslContext, x) != 1)
throw std::runtime_error ("Unable to get certificate from chain file");
cert_set = true;
}
else if (SSL_CTX_add_extra_chain_cert (sslContext, x) != 1)
{
X509_free (x);
throw std::runtime_error ("Unable to add chain certificate");
}
}
fclose (f);
}
catch (...)
{
fclose (f);
throw;
}
}
if (!key_file.empty ())
{
boost::system::error_code error;
context.use_private_key_file (key_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error ("Unable to use private key file");
}
if (SSL_CTX_check_private_key (sslContext) != 1)
throw std::runtime_error ("Private key not valid");
}
// vim:ts=4

View File

@@ -11,17 +11,20 @@ Handles incoming connections from other Peers
class PeerDoor
{
public:
PeerDoor (boost::asio::io_service& io_service);
PeerDoor (boost::asio::io_service& io_service);
boost::asio::ssl::context& getSSLContext() { return mCtx; }
boost::asio::ssl::context& getSSLContext ()
{
return mCtx;
}
private:
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::ssl::context mCtx;
boost::asio::deadline_timer mDelayTimer;
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::ssl::context mCtx;
boost::asio::deadline_timer mDelayTimer;
void startListening();
void handleConnect(Peer::pointer new_connection, const boost::system::error_code& error);
void startListening ();
void handleConnect (Peer::pointer new_connection, const boost::system::error_code& error);
};
#endif

View File

@@ -6,39 +6,39 @@
enum http_status_type
{
ok = 200,
created = 201,
accepted = 202,
no_content = 204,
multiple_choices = 300,
moved_permanently = 301,
moved_temporarily = 302,
not_modified = 304,
bad_request = 400,
unauthorized = 401,
forbidden = 403,
not_found = 404,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503
ok = 200,
created = 201,
accepted = 202,
no_content = 204,
multiple_choices = 300,
moved_permanently = 301,
moved_temporarily = 302,
not_modified = 304,
bad_request = 400,
unauthorized = 401,
forbidden = 403,
not_found = 404,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503
};
extern std::string JSONRPCRequest(const std::string& strMethod, const Json::Value& params,
const Json::Value& id);
extern std::string JSONRPCRequest (const std::string& strMethod, const Json::Value& params,
const Json::Value& id);
extern std::string createHTTPPost(const std::string& strHost, const std::string& strPath, const std::string& strMsg,
const std::map<std::string, std::string>& mapRequestHeaders);
extern std::string createHTTPPost (const std::string& strHost, const std::string& strPath, const std::string& strMsg,
const std::map<std::string, std::string>& mapRequestHeaders);
extern int ReadHTTP(std::basic_istream<char>& stream,
std::map<std::string, std::string>& mapHeadersRet, std::string& strMessageRet);
extern int ReadHTTP (std::basic_istream<char>& stream,
std::map<std::string, std::string>& mapHeadersRet, std::string& strMessageRet);
extern std::string HTTPReply(int nStatus, const std::string& strMsg);
extern std::string HTTPReply (int nStatus, const std::string& strMsg);
extern std::string JSONRPCReply(const Json::Value& result, const Json::Value& error, const Json::Value& id);
extern std::string JSONRPCReply (const Json::Value& result, const Json::Value& error, const Json::Value& id);
extern Json::Value JSONRPCError(int code, const std::string& message);
extern Json::Value JSONRPCError (int code, const std::string& message);
extern bool HTTPAuthorized(const std::map<std::string, std::string>& mapHeaders);
extern bool HTTPAuthorized (const std::map<std::string, std::string>& mapHeaders);
#endif

View File

@@ -7,83 +7,86 @@ SETUP_LOG (RPCDoor)
using namespace std;
using namespace boost::asio::ip;
extern void initSSLContext(boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file);
extern void initSSLContext (boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file);
RPCDoor::RPCDoor(boost::asio::io_service& io_service) :
mAcceptor(io_service, tcp::endpoint(address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT)),
mDelayTimer(io_service), mSSLContext(boost::asio::ssl::context::sslv23)
RPCDoor::RPCDoor (boost::asio::io_service& io_service) :
mAcceptor (io_service, tcp::endpoint (address::from_string (theConfig.RPC_IP), theConfig.RPC_PORT)),
mDelayTimer (io_service), mSSLContext (boost::asio::ssl::context::sslv23)
{
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
if (theConfig.RPC_SECURE != 0)
initSSLContext(mSSLContext, theConfig.RPC_SSL_KEY, theConfig.RPC_SSL_CERT, theConfig.RPC_SSL_CHAIN);
if (theConfig.RPC_SECURE != 0)
initSSLContext (mSSLContext, theConfig.RPC_SSL_KEY, theConfig.RPC_SSL_CERT, theConfig.RPC_SSL_CHAIN);
startListening();
startListening ();
}
RPCDoor::~RPCDoor()
RPCDoor::~RPCDoor ()
{
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
}
void RPCDoor::startListening()
void RPCDoor::startListening ()
{
RPCServer::pointer new_connection = RPCServer::create(mAcceptor.get_io_service(), mSSLContext, &theApp->getOPs());
mAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
RPCServer::pointer new_connection = RPCServer::create (mAcceptor.get_io_service (), mSSLContext, &theApp->getOPs ());
mAcceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true));
mAcceptor.async_accept(new_connection->getRawSocket(),
boost::bind(&RPCDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error));
mAcceptor.async_accept (new_connection->getRawSocket (),
boost::bind (&RPCDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
bool RPCDoor::isClientAllowed(const std::string& ip)
bool RPCDoor::isClientAllowed (const std::string& ip)
{
if (theConfig.RPC_ALLOW_REMOTE)
return true;
if (theConfig.RPC_ALLOW_REMOTE)
return true;
if (ip == "127.0.0.1")
return true;
if (ip == "127.0.0.1")
return true;
return false;
return false;
}
void RPCDoor::handleConnect(RPCServer::pointer new_connection, const boost::system::error_code& error)
void RPCDoor::handleConnect (RPCServer::pointer new_connection, const boost::system::error_code& error)
{
bool delay = false;
if (!error)
{
// Restrict callers by IP
try
{
if (!isClientAllowed(new_connection->getRawSocket().remote_endpoint().address().to_string()))
{
startListening();
return;
}
}
catch (...)
{ // client may have disconnected
startListening();
return;
}
bool delay = false;
new_connection->getSocket().async_handshake(AutoSocket::ssl_socket::server,
boost::bind(&RPCServer::connected, new_connection));
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsINFO, RPCDoor) << "RPCDoor::handleConnect Error: " << error;
}
if (!error)
{
// Restrict callers by IP
try
{
if (!isClientAllowed (new_connection->getRawSocket ().remote_endpoint ().address ().to_string ()))
{
startListening ();
return;
}
}
catch (...)
{
// client may have disconnected
startListening ();
return;
}
if (delay)
{
mDelayTimer.expires_from_now(boost::posix_time::milliseconds(1000));
mDelayTimer.async_wait(boost::bind(&RPCDoor::startListening, this));
}
else
startListening();
new_connection->getSocket ().async_handshake (AutoSocket::ssl_socket::server,
boost::bind (&RPCServer::connected, new_connection));
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsINFO, RPCDoor) << "RPCDoor::handleConnect Error: " << error;
}
if (delay)
{
mDelayTimer.expires_from_now (boost::posix_time::milliseconds (1000));
mDelayTimer.async_wait (boost::bind (&RPCDoor::startListening, this));
}
else
startListening ();
}
// vim:ts=4

View File

@@ -10,19 +10,19 @@ Handles incoming connections from people making RPC Requests
class RPCDoor
{
public:
explicit RPCDoor (boost::asio::io_service& io_service);
~RPCDoor ();
explicit RPCDoor (boost::asio::io_service& io_service);
~RPCDoor ();
private:
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::deadline_timer mDelayTimer;
boost::asio::ssl::context mSSLContext;
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::deadline_timer mDelayTimer;
boost::asio::ssl::context mSSLContext;
void startListening();
void handleConnect(RPCServer::pointer new_connection,
const boost::system::error_code& error);
void startListening ();
void handleConnect (RPCServer::pointer new_connection,
const boost::system::error_code& error);
bool isClientAllowed(const std::string& ip);
bool isClientAllowed (const std::string& ip);
};
#endif

View File

@@ -6,97 +6,99 @@ struct RPCErr { };
SETUP_LOG (RPCErr)
Json::Value rpcError(int iError, Json::Value jvResult)
Json::Value rpcError (int iError, Json::Value jvResult)
{
static struct {
int iError;
const char* pToken;
const char* pMessage;
} errorInfoA[] = {
{ rpcACT_BITCOIN, "actBitcoin", "Account is bitcoin address." },
{ rpcACT_EXISTS, "actExists", "Account already exists." },
{ rpcACT_MALFORMED, "actMalformed", "Account malformed." },
{ rpcACT_NOT_FOUND, "actNotFound", "Account not found." },
{ rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string." },
{ rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid." },
{ rpcBAD_ISSUER, "badIssuer", "Issuer account malformed." },
{ rpcBAD_MARKET, "badMarket", "No such market." },
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
{ rpcBAD_SEED, "badSeed", "Disallowed seed." },
{ rpcBAD_SYNTAX, "badSyntax", "Syntax error." },
{ rpcCOMMAND_MISSING, "commandMissing", "Missing command entry." },
{ rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." },
{ rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exist." },
{ rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." },
{ rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed." },
{ rpcFORBIDDEN, "forbidden", "Bad credentials." },
{ rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." },
{ rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." },
{ rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." },
{ rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." },
{ rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." },
{ rpcINTERNAL, "internal", "Internal error." },
{ rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." },
{ rpcJSON_RPC, "json_rpc", "JSON-RPC transport error." },
{ rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." },
{ rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." },
{ rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." },
{ rpcNICKNAME_MALFORMED, "nicknameMalformed","Nickname is malformed." },
{ rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." },
{ rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." },
{ rpcNOT_IMPL, "notImpl", "Not implemented." },
{ rpcNO_ACCOUNT, "noAccount", "No such account." },
{ rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." },
{ rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." },
{ rpcNO_EVENTS, "noEvents", "Current transport does not support events." },
{ rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." },
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
{ rpcNO_PATH, "noPath", "Unable to find a ripple path." },
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
{ rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress." },
{ rpcNOT_STANDALONE, "notStandAlone", "Operation valid in debug mode only." },
{ rpcNOT_SUPPORTED, "notSupported", "Operation not supported." },
{ rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." },
{ rpcPAYS_ACT_MALFORMED, "paysActMalformed", "Pays account malformed." },
{ rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed." },
{ rpcPORT_MALFORMED, "portMalformed", "Port is malformed." },
{ rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." },
{ rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." },
{ rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." },
{ rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided." },
{ rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found." },
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." },
{ rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed." },
{ rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." },
{ rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." },
{ rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." },
{ rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method." },
{ rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." },
{ rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now." },
{ rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server." },
};
static struct
{
int iError;
const char* pToken;
const char* pMessage;
} errorInfoA[] =
{
{ rpcACT_BITCOIN, "actBitcoin", "Account is bitcoin address." },
{ rpcACT_EXISTS, "actExists", "Account already exists." },
{ rpcACT_MALFORMED, "actMalformed", "Account malformed." },
{ rpcACT_NOT_FOUND, "actNotFound", "Account not found." },
{ rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string." },
{ rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid." },
{ rpcBAD_ISSUER, "badIssuer", "Issuer account malformed." },
{ rpcBAD_MARKET, "badMarket", "No such market." },
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
{ rpcBAD_SEED, "badSeed", "Disallowed seed." },
{ rpcBAD_SYNTAX, "badSyntax", "Syntax error." },
{ rpcCOMMAND_MISSING, "commandMissing", "Missing command entry." },
{ rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." },
{ rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exist." },
{ rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." },
{ rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed." },
{ rpcFORBIDDEN, "forbidden", "Bad credentials." },
{ rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." },
{ rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." },
{ rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." },
{ rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." },
{ rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." },
{ rpcINTERNAL, "internal", "Internal error." },
{ rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." },
{ rpcJSON_RPC, "json_rpc", "JSON-RPC transport error." },
{ rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." },
{ rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." },
{ rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." },
{ rpcNICKNAME_MALFORMED, "nicknameMalformed", "Nickname is malformed." },
{ rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." },
{ rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." },
{ rpcNOT_IMPL, "notImpl", "Not implemented." },
{ rpcNO_ACCOUNT, "noAccount", "No such account." },
{ rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." },
{ rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." },
{ rpcNO_EVENTS, "noEvents", "Current transport does not support events." },
{ rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." },
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
{ rpcNO_PATH, "noPath", "Unable to find a ripple path." },
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
{ rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress." },
{ rpcNOT_STANDALONE, "notStandAlone", "Operation valid in debug mode only." },
{ rpcNOT_SUPPORTED, "notSupported", "Operation not supported." },
{ rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." },
{ rpcPAYS_ACT_MALFORMED, "paysActMalformed", "Pays account malformed." },
{ rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed." },
{ rpcPORT_MALFORMED, "portMalformed", "Port is malformed." },
{ rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." },
{ rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." },
{ rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." },
{ rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided." },
{ rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found." },
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." },
{ rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed." },
{ rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." },
{ rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." },
{ rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." },
{ rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method." },
{ rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." },
{ rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now." },
{ rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server." },
};
int i;
int i;
for (i=NUMBER(errorInfoA); i-- && errorInfoA[i].iError != iError;)
;
for (i = NUMBER (errorInfoA); i-- && errorInfoA[i].iError != iError;)
;
jvResult["error"] = i >= 0 ? errorInfoA[i].pToken : lexical_cast_i(iError);
jvResult["error_message"] = i >= 0 ? errorInfoA[i].pMessage : lexical_cast_i(iError);
jvResult["error_code"] = iError;
jvResult["error"] = i >= 0 ? errorInfoA[i].pToken : lexical_cast_i (iError);
jvResult["error_message"] = i >= 0 ? errorInfoA[i].pMessage : lexical_cast_i (iError);
jvResult["error_code"] = iError;
if (i >= 0)
{
WriteLog (lsDEBUG, RPCErr) << "rpcError: "
<< errorInfoA[i].pToken << ": " << errorInfoA[i].pMessage << std::endl;
}
if (i >= 0)
{
WriteLog (lsDEBUG, RPCErr) << "rpcError: "
<< errorInfoA[i].pToken << ": " << errorInfoA[i].pMessage << std::endl;
}
return jvResult;
return jvResult;
}
bool isRpcError(Json::Value jvResult)
bool isRpcError (Json::Value jvResult)
{
return jvResult.isObject() && jvResult.isMember("error");
return jvResult.isObject () && jvResult.isMember ("error");
}
// vim:ts=4

View File

@@ -1,90 +1,91 @@
#ifndef __RPCERR__
#define __RPCERR__
enum {
rpcSUCCESS = 0,
rpcBAD_SYNTAX, // Must be 1 to print usage to command line.
rpcJSON_RPC,
rpcFORBIDDEN,
enum
{
rpcSUCCESS = 0,
rpcBAD_SYNTAX, // Must be 1 to print usage to command line.
rpcJSON_RPC,
rpcFORBIDDEN,
// Error numbers beyond this line are not stable between versions.
// Programs should use error tokens.
// Error numbers beyond this line are not stable between versions.
// Programs should use error tokens.
// Misc failure
rpcLOAD_FAILED,
rpcNO_PERMISSION,
rpcNO_EVENTS,
rpcNOT_STANDALONE,
rpcTOO_BUSY,
rpcSLOW_DOWN,
// Misc failure
rpcLOAD_FAILED,
rpcNO_PERMISSION,
rpcNO_EVENTS,
rpcNOT_STANDALONE,
rpcTOO_BUSY,
rpcSLOW_DOWN,
// Networking
rpcNO_CLOSED,
rpcNO_CURRENT,
rpcNO_NETWORK,
// Networking
rpcNO_CLOSED,
rpcNO_CURRENT,
rpcNO_NETWORK,
// Ledger state
rpcACT_EXISTS,
rpcACT_NOT_FOUND,
rpcINSUF_FUNDS,
rpcLGR_NOT_FOUND,
rpcNICKNAME_MISSING,
rpcNO_ACCOUNT,
rpcNO_PATH,
rpcPASSWD_CHANGED,
rpcSRC_MISSING,
rpcSRC_UNCLAIMED,
rpcTXN_NOT_FOUND,
rpcWRONG_SEED,
// Ledger state
rpcACT_EXISTS,
rpcACT_NOT_FOUND,
rpcINSUF_FUNDS,
rpcLGR_NOT_FOUND,
rpcNICKNAME_MISSING,
rpcNO_ACCOUNT,
rpcNO_PATH,
rpcPASSWD_CHANGED,
rpcSRC_MISSING,
rpcSRC_UNCLAIMED,
rpcTXN_NOT_FOUND,
rpcWRONG_SEED,
// Malformed command
rpcINVALID_PARAMS,
rpcUNKNOWN_COMMAND,
rpcNO_PF_REQUEST,
// Malformed command
rpcINVALID_PARAMS,
rpcUNKNOWN_COMMAND,
rpcNO_PF_REQUEST,
// Bad parameter
rpcACT_BITCOIN,
rpcACT_MALFORMED,
rpcQUALITY_MALFORMED,
rpcBAD_BLOB,
rpcBAD_FEATURE,
rpcBAD_ISSUER,
rpcBAD_MARKET,
rpcBAD_SECRET,
rpcBAD_SEED,
rpcCOMMAND_MISSING,
rpcDST_ACT_MALFORMED,
rpcDST_ACT_MISSING,
rpcDST_AMT_MALFORMED,
rpcDST_ISR_MALFORMED,
rpcGETS_ACT_MALFORMED,
rpcGETS_AMT_MALFORMED,
rpcHOST_IP_MALFORMED,
rpcLGR_IDXS_INVALID,
rpcLGR_IDX_MALFORMED,
rpcNICKNAME_MALFORMED,
rpcNICKNAME_PERM,
rpcPAYS_ACT_MALFORMED,
rpcPAYS_AMT_MALFORMED,
rpcPORT_MALFORMED,
rpcPUBLIC_MALFORMED,
rpcSRC_ACT_MALFORMED,
rpcSRC_ACT_MISSING,
rpcSRC_ACT_NOT_FOUND,
rpcSRC_AMT_MALFORMED,
rpcSRC_CUR_MALFORMED,
rpcSRC_ISR_MALFORMED,
// Bad parameter
rpcACT_BITCOIN,
rpcACT_MALFORMED,
rpcQUALITY_MALFORMED,
rpcBAD_BLOB,
rpcBAD_FEATURE,
rpcBAD_ISSUER,
rpcBAD_MARKET,
rpcBAD_SECRET,
rpcBAD_SEED,
rpcCOMMAND_MISSING,
rpcDST_ACT_MALFORMED,
rpcDST_ACT_MISSING,
rpcDST_AMT_MALFORMED,
rpcDST_ISR_MALFORMED,
rpcGETS_ACT_MALFORMED,
rpcGETS_AMT_MALFORMED,
rpcHOST_IP_MALFORMED,
rpcLGR_IDXS_INVALID,
rpcLGR_IDX_MALFORMED,
rpcNICKNAME_MALFORMED,
rpcNICKNAME_PERM,
rpcPAYS_ACT_MALFORMED,
rpcPAYS_AMT_MALFORMED,
rpcPORT_MALFORMED,
rpcPUBLIC_MALFORMED,
rpcSRC_ACT_MALFORMED,
rpcSRC_ACT_MISSING,
rpcSRC_ACT_NOT_FOUND,
rpcSRC_AMT_MALFORMED,
rpcSRC_CUR_MALFORMED,
rpcSRC_ISR_MALFORMED,
// Internal error (should never happen)
rpcINTERNAL, // Generic internal error.
rpcFAIL_GEN_DECRPYT,
rpcNOT_IMPL,
rpcNOT_SUPPORTED,
rpcNO_GEN_DECRPYT,
// Internal error (should never happen)
rpcINTERNAL, // Generic internal error.
rpcFAIL_GEN_DECRPYT,
rpcNOT_IMPL,
rpcNOT_SUPPORTED,
rpcNO_GEN_DECRPYT,
};
bool isRpcError(Json::Value jvResult);
Json::Value rpcError(int iError, Json::Value jvResult=Json::Value(Json::objectValue));
bool isRpcError (Json::Value jvResult);
Json::Value rpcError (int iError, Json::Value jvResult = Json::Value (Json::objectValue));
#endif
// vim:ts=4

File diff suppressed because it is too large Load Diff

View File

@@ -5,9 +5,9 @@
#include "Ledger.h"
#define LEDGER_CURRENT -1
#define LEDGER_CLOSED -2
#define LEDGER_VALIDATED -3
#define LEDGER_CURRENT -1
#define LEDGER_CLOSED -2
#define LEDGER_VALIDATED -3
// used by the RPCServer or WSDoor to carry out these RPC commands
class NetworkOPs;
@@ -15,132 +15,133 @@ class InfoSub;
class RPCHandler
{
NetworkOPs* mNetOps;
InfoSub::pointer mInfoSub;
int mRole;
NetworkOPs* mNetOps;
InfoSub::pointer mInfoSub;
int mRole;
typedef Json::Value (RPCHandler::*doFuncPtr)(Json::Value params, int& cost, ScopedLock& MasterLockHolder);
enum {
optNone = 0,
optNetwork = 1, // Need network
optCurrent = 2+optNetwork, // Need current ledger
optClosed = 4+optNetwork, // Need closed ledger
};
typedef Json::Value (RPCHandler::*doFuncPtr) (Json::Value params, int& cost, ScopedLock& MasterLockHolder);
enum
{
optNone = 0,
optNetwork = 1, // Need network
optCurrent = 2 + optNetwork, // Need current ledger
optClosed = 4 + optNetwork, // Need closed ledger
};
// Utilities
void addSubmitPath(Json::Value& txJSON);
boost::unordered_set<RippleAddress> parseAccountIds(const Json::Value& jvArray);
Json::Value transactionSign(Json::Value jvRequest, bool bSubmit, ScopedLock& mlh);
// Utilities
void addSubmitPath (Json::Value& txJSON);
boost::unordered_set<RippleAddress> parseAccountIds (const Json::Value& jvArray);
Json::Value transactionSign (Json::Value jvRequest, bool bSubmit, ScopedLock& mlh);
Json::Value lookupLedger(Json::Value jvRequest, Ledger::pointer& lpLedger);
Json::Value lookupLedger (Json::Value jvRequest, Ledger::pointer& lpLedger);
Json::Value getMasterGenerator(Ledger::ref lrLedger, const RippleAddress& naRegularSeed, RippleAddress& naMasterGenerator);
Json::Value authorize(Ledger::ref lrLedger, const RippleAddress& naRegularSeed, const RippleAddress& naSrcAccountID,
RippleAddress& naAccountPublic, RippleAddress& naAccountPrivate,
STAmount& saSrcBalance, const STAmount& saFee, AccountState::pointer& asSrc,
const RippleAddress& naVerifyGenerator);
Json::Value accounts(Ledger::ref lrLedger, const RippleAddress& naMasterGenerator);
Json::Value getMasterGenerator (Ledger::ref lrLedger, const RippleAddress& naRegularSeed, RippleAddress& naMasterGenerator);
Json::Value authorize (Ledger::ref lrLedger, const RippleAddress& naRegularSeed, const RippleAddress& naSrcAccountID,
RippleAddress& naAccountPublic, RippleAddress& naAccountPrivate,
STAmount& saSrcBalance, const STAmount& saFee, AccountState::pointer& asSrc,
const RippleAddress& naVerifyGenerator);
Json::Value accounts (Ledger::ref lrLedger, const RippleAddress& naMasterGenerator);
Json::Value accountFromString(Ledger::ref lrLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex, const bool bStrict);
Json::Value accountFromString (Ledger::ref lrLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex, const bool bStrict);
Json::Value doAccountInfo(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountLines(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountOffers(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountTransactions(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doBookOffers(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doConnect(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doConsensusInfo(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountInfo (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountLines (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountOffers (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountTransactions (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doBookOffers (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doConnect (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doConsensusInfo (Json::Value params, int& cost, ScopedLock& mlh);
#if ENABLE_INSECURE
Json::Value doDataDelete(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataFetch(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataStore(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataDelete (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataFetch (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataStore (Json::Value params, int& cost, ScopedLock& mlh);
#endif
Json::Value doFeature(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doGetCounts(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doInternal(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedger(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLogLevel(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLogRotate(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doNicknameInfo(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doOwnerInfo(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPeers(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPathFind(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPing(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProfile(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofCreate(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofSolve(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofVerify(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doRandom(Json::Value jvRequest, int& cost, ScopedLock& mlh);
Json::Value doRipplePathFind(Json::Value jvRequest, int& cost, ScopedLock& mlh);
Json::Value doServerInfo(Json::Value params, int& cost, ScopedLock& mlh); // for humans
Json::Value doServerState(Json::Value params, int& cost, ScopedLock& mlh); // for machines
Json::Value doSessionClose(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSessionOpen(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSMS(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doStop(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSign(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSubmit(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTx(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTxHistory(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlAdd(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlDelete(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlFetch(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlList(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlLoad(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlNetwork(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlReset(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlScore(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doFeature (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doGetCounts (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doInternal (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedger (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLogLevel (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLogRotate (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doNicknameInfo (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doOwnerInfo (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPeers (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPathFind (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPing (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProfile (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofCreate (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofSolve (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofVerify (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doRandom (Json::Value jvRequest, int& cost, ScopedLock& mlh);
Json::Value doRipplePathFind (Json::Value jvRequest, int& cost, ScopedLock& mlh);
Json::Value doServerInfo (Json::Value params, int& cost, ScopedLock& mlh); // for humans
Json::Value doServerState (Json::Value params, int& cost, ScopedLock& mlh); // for machines
Json::Value doSessionClose (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSessionOpen (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSMS (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doStop (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSign (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSubmit (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTx (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTxHistory (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlAdd (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlDelete (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlFetch (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlList (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlLoad (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlNetwork (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlReset (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlScore (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doValidationCreate(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doValidationSeed(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doValidationCreate (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doValidationSeed (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletAccounts(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletLock(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletPropose(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletSeed(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletUnlock(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletVerify(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletAccounts (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletLock (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletPropose (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletSeed (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletUnlock (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletVerify (Json::Value params, int& cost, ScopedLock& mlh);
#if ENABLE_INSECURE
Json::Value doLogin(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLogin (Json::Value params, int& cost, ScopedLock& mlh);
#endif
Json::Value doLedgerAccept(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerClosed(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerCurrent(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerEntry(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerHeader(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTransactionEntry(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerAccept (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerClosed (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerCurrent (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerEntry (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerHeader (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTransactionEntry (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSubscribe(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnsubscribe(Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSubscribe (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnsubscribe (Json::Value params, int& cost, ScopedLock& mlh);
public:
enum { GUEST, USER, ADMIN, FORBID };
enum { GUEST, USER, ADMIN, FORBID };
RPCHandler(NetworkOPs* netOps);
RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub);
RPCHandler (NetworkOPs* netOps);
RPCHandler (NetworkOPs* netOps, InfoSub::pointer infoSub);
Json::Value doCommand(const Json::Value& jvRequest, int role, int& cost);
Json::Value doRpcCommand(const std::string& strCommand, Json::Value& jvParams, int iRole, int& cost);
Json::Value doCommand (const Json::Value& jvRequest, int role, int& cost);
Json::Value doRpcCommand (const std::string& strCommand, Json::Value& jvParams, int iRole, int& cost);
};
class RPCInternalHandler
{
public:
typedef Json::Value (*handler_t)(const Json::Value&);
typedef Json::Value (*handler_t) (const Json::Value&);
public:
RPCInternalHandler(const std::string& name, handler_t handler);
static Json::Value runHandler(const std::string& name, const Json::Value& params);
RPCInternalHandler (const std::string& name, handler_t handler);
static Json::Value runHandler (const std::string& name, const Json::Value& params);
private:
static RPCInternalHandler* sHeadHandler;
static RPCInternalHandler* sHeadHandler;
RPCInternalHandler* mNextHandler;
std::string mName;
handler_t mHandler;
RPCInternalHandler* mNextHandler;
std::string mName;
handler_t mHandler;
};
// VFALCO TODO tidy up this loose function

View File

@@ -13,192 +13,200 @@
#include <boost/asio/read_until.hpp>
#ifndef RPC_MAXIMUM_QUERY
#define RPC_MAXIMUM_QUERY (1024*1024)
#define RPC_MAXIMUM_QUERY (1024*1024)
#endif
SETUP_LOG (RPCServer)
RPCServer::RPCServer(boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* nopNetwork)
: mNetOps(nopNetwork), mSocket(io_service, context)
RPCServer::RPCServer (boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* nopNetwork)
: mNetOps (nopNetwork), mSocket (io_service, context)
{
mRole = RPCHandler::GUEST;
mRole = RPCHandler::GUEST;
}
void RPCServer::connected()
void RPCServer::connected ()
{
//std::cerr << "RPC request" << std::endl;
boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n",
boost::bind(&RPCServer::handle_read_line, shared_from_this(), boost::asio::placeholders::error));
//std::cerr << "RPC request" << std::endl;
boost::asio::async_read_until (mSocket, mLineBuffer, "\r\n",
boost::bind (&RPCServer::handle_read_line, shared_from_this (), boost::asio::placeholders::error));
}
void RPCServer::handle_read_req(const boost::system::error_code& e)
void RPCServer::handle_read_req (const boost::system::error_code& e)
{
std::string req;
std::string req;
if (mLineBuffer.size())
{
req.assign(boost::asio::buffer_cast<const char*>(mLineBuffer.data()), mLineBuffer.size());
mLineBuffer.consume(mLineBuffer.size());
}
if (mLineBuffer.size ())
{
req.assign (boost::asio::buffer_cast<const char*> (mLineBuffer.data ()), mLineBuffer.size ());
mLineBuffer.consume (mLineBuffer.size ());
}
req += strCopy(mQueryVec);
req += strCopy (mQueryVec);
if (!HTTPAuthorized(mHTTPRequest.peekHeaders()))
mReplyStr = HTTPReply(403, "Forbidden");
else
mReplyStr = handleRequest(req);
if (!HTTPAuthorized (mHTTPRequest.peekHeaders ()))
mReplyStr = HTTPReply (403, "Forbidden");
else
mReplyStr = handleRequest (req);
boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr),
boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error));
boost::asio::async_write (mSocket, boost::asio::buffer (mReplyStr),
boost::bind (&RPCServer::handle_write, shared_from_this (), boost::asio::placeholders::error));
}
static void dummy_handler()
static void dummy_handler ()
{
;
;
}
void RPCServer::handle_read_line(const boost::system::error_code& e)
void RPCServer::handle_read_line (const boost::system::error_code& e)
{
if (e)
return;
if (e)
return;
HTTPRequestAction action = mHTTPRequest.consume(mLineBuffer);
HTTPRequestAction action = mHTTPRequest.consume (mLineBuffer);
if (action == haDO_REQUEST)
{ // request with no body
WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body";
mSocket.async_shutdown(boost::bind(&dummy_handler));
return;
}
else if (action == haREAD_LINE)
{
boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n",
boost::bind(&RPCServer::handle_read_line, shared_from_this(),
boost::asio::placeholders::error));
}
else if (action == haREAD_RAW)
{
int rLen = mHTTPRequest.getDataSize();
if ((rLen < 0) || (rLen > RPC_MAXIMUM_QUERY))
{
WriteLog (lsWARNING, RPCServer) << "Illegal RPC request length " << rLen;
mSocket.async_shutdown(boost::bind(&dummy_handler));
return;
}
if (action == haDO_REQUEST)
{
// request with no body
WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body";
mSocket.async_shutdown (boost::bind (&dummy_handler));
return;
}
else if (action == haREAD_LINE)
{
boost::asio::async_read_until (mSocket, mLineBuffer, "\r\n",
boost::bind (&RPCServer::handle_read_line, shared_from_this (),
boost::asio::placeholders::error));
}
else if (action == haREAD_RAW)
{
int rLen = mHTTPRequest.getDataSize ();
int alreadyHave = mLineBuffer.size();
if ((rLen < 0) || (rLen > RPC_MAXIMUM_QUERY))
{
WriteLog (lsWARNING, RPCServer) << "Illegal RPC request length " << rLen;
mSocket.async_shutdown (boost::bind (&dummy_handler));
return;
}
if (alreadyHave < rLen)
{
mQueryVec.resize(rLen - alreadyHave);
boost::asio::async_read(mSocket, boost::asio::buffer(mQueryVec),
boost::bind(&RPCServer::handle_read_req, shared_from_this(), boost::asio::placeholders::error));
WriteLog (lsTRACE, RPCServer) << "Waiting for completed request: " << rLen;
}
else
{ // we have the whole thing
mQueryVec.resize(0);
handle_read_req(e);
}
}
else
mSocket.async_shutdown(boost::bind(&dummy_handler));
int alreadyHave = mLineBuffer.size ();
if (alreadyHave < rLen)
{
mQueryVec.resize (rLen - alreadyHave);
boost::asio::async_read (mSocket, boost::asio::buffer (mQueryVec),
boost::bind (&RPCServer::handle_read_req, shared_from_this (), boost::asio::placeholders::error));
WriteLog (lsTRACE, RPCServer) << "Waiting for completed request: " << rLen;
}
else
{
// we have the whole thing
mQueryVec.resize (0);
handle_read_req (e);
}
}
else
mSocket.async_shutdown (boost::bind (&dummy_handler));
}
std::string RPCServer::handleRequest(const std::string& requestStr)
std::string RPCServer::handleRequest (const std::string& requestStr)
{
WriteLog (lsTRACE, RPCServer) << "handleRequest " << requestStr;
WriteLog (lsTRACE, RPCServer) << "handleRequest " << requestStr;
Json::Value id;
Json::Value id;
// Parse request
Json::Value jvRequest;
Json::Reader reader;
// Parse request
Json::Value jvRequest;
Json::Reader reader;
if (!reader.parse(requestStr, jvRequest) || jvRequest.isNull() || !jvRequest.isObject())
return(HTTPReply(400, "unable to parse request"));
if (!reader.parse (requestStr, jvRequest) || jvRequest.isNull () || !jvRequest.isObject ())
return (HTTPReply (400, "unable to parse request"));
// Parse id now so errors from here on will have the id
id = jvRequest["id"];
// Parse id now so errors from here on will have the id
id = jvRequest["id"];
// Parse method
Json::Value valMethod = jvRequest["method"];
if (valMethod.isNull())
return(HTTPReply(400, "null method"));
if (!valMethod.isString())
return(HTTPReply(400, "method is not string"));
std::string strMethod = valMethod.asString();
// Parse method
Json::Value valMethod = jvRequest["method"];
// Parse params
Json::Value valParams = jvRequest["params"];
if (valMethod.isNull ())
return (HTTPReply (400, "null method"));
if (valParams.isNull())
{
valParams = Json::Value(Json::arrayValue);
}
else if (!valParams.isArray())
{
return HTTPReply(400, "params unparseable");
}
if (!valMethod.isString ())
return (HTTPReply (400, "method is not string"));
try
{
mRole = iAdminGet(jvRequest, mSocket.PlainSocket().remote_endpoint().address().to_string());
}
catch (...)
{ // endpoint already disconnected
return "";
}
std::string strMethod = valMethod.asString ();
if (RPCHandler::FORBID == mRole)
{
// XXX This needs rate limiting to prevent brute forcing password.
return HTTPReply(403, "Forbidden");
}
// Parse params
Json::Value valParams = jvRequest["params"];
RPCHandler mRPCHandler(mNetOps);
if (valParams.isNull ())
{
valParams = Json::Value (Json::arrayValue);
}
else if (!valParams.isArray ())
{
return HTTPReply (400, "params unparseable");
}
WriteLog (lsTRACE, RPCServer) << valParams;
int cost = 10;
Json::Value result = mRPCHandler.doRpcCommand(strMethod, valParams, mRole, cost);
WriteLog (lsTRACE, RPCServer) << result;
try
{
mRole = iAdminGet (jvRequest, mSocket.PlainSocket ().remote_endpoint ().address ().to_string ());
}
catch (...)
{
// endpoint already disconnected
return "";
}
std::string strReply = JSONRPCReply(result, Json::Value(), id);
return HTTPReply(200, strReply);
if (RPCHandler::FORBID == mRole)
{
// XXX This needs rate limiting to prevent brute forcing password.
return HTTPReply (403, "Forbidden");
}
RPCHandler mRPCHandler (mNetOps);
WriteLog (lsTRACE, RPCServer) << valParams;
int cost = 10;
Json::Value result = mRPCHandler.doRpcCommand (strMethod, valParams, mRole, cost);
WriteLog (lsTRACE, RPCServer) << result;
std::string strReply = JSONRPCReply (result, Json::Value (), id);
return HTTPReply (200, strReply);
}
#if 0
// now, expire, n
bool RPCServer::parseAcceptRate(const std::string& sAcceptRate)
bool RPCServer::parseAcceptRate (const std::string& sAcceptRate)
{
if (!sAcceptRate.compare("expire"))
0;
if (!sAcceptRate.compare ("expire"))
0;
return true;
return true;
}
#endif
void RPCServer::handle_write(const boost::system::error_code& e)
void RPCServer::handle_write (const boost::system::error_code& e)
{
//std::cerr << "async_write complete " << e << std::endl;
//std::cerr << "async_write complete " << e << std::endl;
if (!e)
{
HTTPRequestAction action = mHTTPRequest.requestDone(false);
if (action == haCLOSE_CONN)
mSocket.async_shutdown(boost::bind(&dummy_handler));
else
{
boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n",
boost::bind(&RPCServer::handle_read_line, shared_from_this(), boost::asio::placeholders::error));
}
}
if (!e)
{
HTTPRequestAction action = mHTTPRequest.requestDone (false);
if (e != boost::asio::error::operation_aborted)
{
//connection_manager_.stop(shared_from_this());
}
if (action == haCLOSE_CONN)
mSocket.async_shutdown (boost::bind (&dummy_handler));
else
{
boost::asio::async_read_until (mSocket, mLineBuffer, "\r\n",
boost::bind (&RPCServer::handle_read_line, shared_from_this (), boost::asio::placeholders::error));
}
}
if (e != boost::asio::error::operation_aborted)
{
//connection_manager_.stop(shared_from_this());
}
}
// vim:ts=4

View File

@@ -8,52 +8,52 @@
class RPCServer : public boost::enable_shared_from_this<RPCServer>
{
public:
typedef boost::shared_ptr<RPCServer> pointer;
typedef boost::shared_ptr<RPCServer> pointer;
private:
NetworkOPs* mNetOps;
AutoSocket mSocket;
NetworkOPs* mNetOps;
boost::asio::streambuf mLineBuffer;
Blob mQueryVec;
std::string mReplyStr;
AutoSocket mSocket;
HTTPRequest mHTTPRequest;
boost::asio::streambuf mLineBuffer;
Blob mQueryVec;
std::string mReplyStr;
int mRole;
HTTPRequest mHTTPRequest;
RPCServer(boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context, NetworkOPs* nopNetwork);
RPCServer(const RPCServer&); // no implementation
RPCServer& operator=(const RPCServer&); // no implementation
int mRole;
void handle_write(const boost::system::error_code& ec);
void handle_read_line(const boost::system::error_code& ec);
void handle_read_req(const boost::system::error_code& ec);
RPCServer (boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context, NetworkOPs* nopNetwork);
std::string handleRequest(const std::string& requestStr);
RPCServer (const RPCServer&); // no implementation
RPCServer& operator= (const RPCServer&); // no implementation
void handle_write (const boost::system::error_code& ec);
void handle_read_line (const boost::system::error_code& ec);
void handle_read_req (const boost::system::error_code& ec);
std::string handleRequest (const std::string& requestStr);
public:
static pointer create(boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* mNetOps)
{
return pointer(new RPCServer(io_service, context, mNetOps));
}
static pointer create (boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* mNetOps)
{
return pointer (new RPCServer (io_service, context, mNetOps));
}
AutoSocket& getSocket()
{
return mSocket;
}
AutoSocket& getSocket ()
{
return mSocket;
}
boost::asio::ip::tcp::socket& getRawSocket()
{
return mSocket.PlainSocket();
}
boost::asio::ip::tcp::socket& getRawSocket ()
{
return mSocket.PlainSocket ();
}
void connected();
void connected ();
};
#endif

View File

@@ -6,112 +6,113 @@
SETUP_LOG (RPCSub)
RPCSub::RPCSub(const std::string& strUrl, const std::string& strUsername, const std::string& strPassword)
: mUrl(strUrl), mSSL(false), mUsername(strUsername), mPassword(strPassword), mSending(false)
RPCSub::RPCSub (const std::string& strUrl, const std::string& strUsername, const std::string& strPassword)
: mUrl (strUrl), mSSL (false), mUsername (strUsername), mPassword (strPassword), mSending (false)
{
std::string strScheme;
std::string strScheme;
if (!parseUrl(strUrl, strScheme, mIp, mPort, mPath))
if (!parseUrl (strUrl, strScheme, mIp, mPort, mPath))
{
throw std::runtime_error("Failed to parse url.");
throw std::runtime_error ("Failed to parse url.");
}
else if (strScheme == "https")
{
mSSL = true;
mSSL = true;
}
else if (strScheme != "http")
{
throw std::runtime_error("Only http and https is supported.");
throw std::runtime_error ("Only http and https is supported.");
}
mSeq = 1;
mSeq = 1;
if (mPort < 0)
mPort = mSSL ? 443 : 80;
mPort = mSSL ? 443 : 80;
WriteLog (lsINFO, RPCSub) << boost::str(boost::format("callRPC sub: ip='%s' port=%d ssl=%d path='%s'")
% mIp
% mPort
% mSSL
% mPath);
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC sub: ip='%s' port=%d ssl=%d path='%s'")
% mIp
% mPort
% mSSL
% mPath);
}
// XXX Could probably create a bunch of send jobs in a single get of the lock.
void RPCSub::sendThread()
void RPCSub::sendThread ()
{
Json::Value jvEvent;
bool bSend;
Json::Value jvEvent;
bool bSend;
do
{
{
// Obtain the lock to manipulate the queue and change sending.
boost::mutex::scoped_lock sl(mLockInfo);
{
// Obtain the lock to manipulate the queue and change sending.
boost::mutex::scoped_lock sl (mLockInfo);
if (mDeque.empty())
{
mSending = false;
bSend = false;
}
else
{
std::pair<int, Json::Value> pEvent = mDeque.front();
if (mDeque.empty ())
{
mSending = false;
bSend = false;
}
else
{
std::pair<int, Json::Value> pEvent = mDeque.front ();
mDeque.pop_front();
mDeque.pop_front ();
jvEvent = pEvent.second;
jvEvent["seq"] = pEvent.first;
jvEvent = pEvent.second;
jvEvent["seq"] = pEvent.first;
bSend = true;
}
}
bSend = true;
}
}
// Send outside of the lock.
if (bSend)
{
// XXX Might not need this in a try.
try
{
WriteLog (lsINFO, RPCSub) << boost::str(boost::format("callRPC calling: %s") % mIp);
// Send outside of the lock.
if (bSend)
{
// XXX Might not need this in a try.
try
{
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC calling: %s") % mIp);
callRPC(
theApp->getIOService(),
mIp, mPort,
mUsername, mPassword,
mPath, "event",
jvEvent,
mSSL);
}
catch (const std::exception& e)
{
WriteLog (lsINFO, RPCSub) << boost::str(boost::format("callRPC exception: %s") % e.what());
}
}
} while (bSend);
callRPC (
theApp->getIOService (),
mIp, mPort,
mUsername, mPassword,
mPath, "event",
jvEvent,
mSSL);
}
catch (const std::exception& e)
{
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC exception: %s") % e.what ());
}
}
}
while (bSend);
}
void RPCSub::send(const Json::Value& jvObj, bool broadcast)
void RPCSub::send (const Json::Value& jvObj, bool broadcast)
{
boost::mutex::scoped_lock sl(mLockInfo);
boost::mutex::scoped_lock sl (mLockInfo);
if (RPC_EVENT_QUEUE_MAX == mDeque.size())
if (RPC_EVENT_QUEUE_MAX == mDeque.size ())
{
// Drop the previous event.
WriteLog (lsWARNING, RPCSub) << boost::str(boost::format("callRPC drop"));
mDeque.pop_back();
// Drop the previous event.
WriteLog (lsWARNING, RPCSub) << boost::str (boost::format ("callRPC drop"));
mDeque.pop_back ();
}
WriteLog (broadcast ? lsDEBUG : lsINFO, RPCSub) << boost::str(boost::format("callRPC push: %s") % jvObj);
WriteLog (broadcast ? lsDEBUG : lsINFO, RPCSub) << boost::str (boost::format ("callRPC push: %s") % jvObj);
mDeque.push_back(std::make_pair(mSeq++, jvObj));
mDeque.push_back (std::make_pair (mSeq++, jvObj));
if (!mSending)
{
// Start a sending thread.
mSending = true;
// Start a sending thread.
mSending = true;
WriteLog (lsINFO, RPCSub) << boost::str(boost::format("callRPC start"));
boost::thread(boost::bind(&RPCSub::sendThread, this)).detach();
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC start"));
boost::thread (boost::bind (&RPCSub::sendThread, this)).detach ();
}
}

View File

@@ -1,53 +1,56 @@
#ifndef __RPCSUB__
#define __RPCSUB__
#define RPC_EVENT_QUEUE_MAX 32
#define RPC_EVENT_QUEUE_MAX 32
// Subscription object for JSON-RPC
class RPCSub : public InfoSub
{
public:
typedef boost::shared_ptr<RPCSub> pointer;
typedef const pointer& ref;
typedef boost::shared_ptr<RPCSub> pointer;
typedef const pointer& ref;
RPCSub(const std::string& strUrl, const std::string& strUsername, const std::string& strPassword);
RPCSub (const std::string& strUrl, const std::string& strUsername, const std::string& strPassword);
virtual ~RPCSub() { ; }
virtual ~RPCSub ()
{
;
}
// Implement overridden functions from base class:
void send(const Json::Value& jvObj, bool broadcast);
// Implement overridden functions from base class:
void send (const Json::Value& jvObj, bool broadcast);
void setUsername(const std::string& strUsername)
{
boost::mutex::scoped_lock sl(mLockInfo);
void setUsername (const std::string& strUsername)
{
boost::mutex::scoped_lock sl (mLockInfo);
mUsername = strUsername;
}
mUsername = strUsername;
}
void setPassword(const std::string& strPassword)
{
boost::mutex::scoped_lock sl(mLockInfo);
void setPassword (const std::string& strPassword)
{
boost::mutex::scoped_lock sl (mLockInfo);
mPassword = strPassword;
}
mPassword = strPassword;
}
protected:
void sendThread();
void sendThread ();
private:
std::string mUrl;
std::string mIp;
int mPort;
bool mSSL;
std::string mUsername;
std::string mPassword;
std::string mPath;
std::string mUrl;
std::string mIp;
int mPort;
bool mSSL;
std::string mUsername;
std::string mPassword;
std::string mPath;
int mSeq; // Next id to allocate.
int mSeq; // Next id to allocate.
bool mSending; // Sending threead is active.
bool mSending; // Sending threead is active.
std::deque<std::pair<int, Json::Value> > mDeque;
std::deque<std::pair<int, Json::Value> > mDeque;
};
#endif

View File

@@ -1,41 +1,43 @@
SETUP_LOG (RegularKeySetTransactor)
uint64 RegularKeySetTransactor::calculateBaseFee()
uint64 RegularKeySetTransactor::calculateBaseFee ()
{
if ( !(mTxnAccount->getFlags() & lsfPasswordSpent)
&& (mSigningPubKey.getAccountID() == mTxnAccountID))
{ // flag is armed and they signed with the right account
return 0;
}
return Transactor::calculateBaseFee();
if ( ! (mTxnAccount->getFlags () & lsfPasswordSpent)
&& (mSigningPubKey.getAccountID () == mTxnAccountID))
{
// flag is armed and they signed with the right account
return 0;
}
return Transactor::calculateBaseFee ();
}
TER RegularKeySetTransactor::doApply()
TER RegularKeySetTransactor::doApply ()
{
std::cerr << "RegularKeySet>" << std::endl;
std::cerr << "RegularKeySet>" << std::endl;
const uint32 uTxFlags = mTxn.getFlags();
const uint32 uTxFlags = mTxn.getFlags ();
if (uTxFlags)
{
WriteLog (lsINFO, RegularKeySetTransactor) << "RegularKeySet: Malformed transaction: Invalid flags set.";
if (uTxFlags)
{
WriteLog (lsINFO, RegularKeySetTransactor) << "RegularKeySet: Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
return temINVALID_FLAG;
}
if (mFeeDue.isZero())
{
mTxnAccount->setFlag(lsfPasswordSpent);
}
if (mFeeDue.isZero ())
{
mTxnAccount->setFlag (lsfPasswordSpent);
}
uint160 uAuthKeyID=mTxn.getFieldAccount160(sfRegularKey);
mTxnAccount->setFieldAccount(sfRegularKey, uAuthKeyID);
uint160 uAuthKeyID = mTxn.getFieldAccount160 (sfRegularKey);
mTxnAccount->setFieldAccount (sfRegularKey, uAuthKeyID);
std::cerr << "RegularKeySet<" << std::endl;
std::cerr << "RegularKeySet<" << std::endl;
return tesSUCCESS;
return tesSUCCESS;
}
// vim:ts=4

View File

@@ -5,11 +5,11 @@
class RegularKeySetTransactor : public Transactor
{
uint64 calculateBaseFee();
uint64 calculateBaseFee ();
public:
RegularKeySetTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {}
TER checkFee();
TER doApply();
RegularKeySetTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : Transactor (txn, params, engine) {}
TER checkFee ();
TER doApply ();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -10,213 +10,226 @@
class PaymentNode
{
public:
bool operator==(const PaymentNode& pnOther) const;
bool operator== (const PaymentNode& pnOther) const;
Json::Value getJson() const;
Json::Value getJson () const;
private:
// VFALCO TODO remove the need for friend declaration
friend class RippleCalc;
friend class PathState;
friend class RippleCalc;
friend class PathState;
uint16 uFlags; // --> From path.
uint16 uFlags; // --> From path.
uint160 uAccountID; // --> Accounts: Recieving/sending account.
uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send.
// --- For offer's next has currency out.
uint160 uIssuerID; // --> Currency's issuer
uint160 uAccountID; // --> Accounts: Recieving/sending account.
uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send.
// --- For offer's next has currency out.
uint160 uIssuerID; // --> Currency's issuer
STAmount saTransferRate; // Transfer rate for uIssuerID.
STAmount saTransferRate; // Transfer rate for uIssuerID.
// Computed by Reverse.
STAmount saRevRedeem; // <-- Amount to redeem to next.
STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs.
// Issue isn't used by offers.
STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee.
// Computed by Reverse.
STAmount saRevRedeem; // <-- Amount to redeem to next.
STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs.
// Issue isn't used by offers.
STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee.
// Computed by forward.
STAmount saFwdRedeem; // <-- Amount node will redeem to next.
STAmount saFwdIssue; // <-- Amount node will issue to next.
// Issue isn't used by offers.
STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee.
// Computed by forward.
STAmount saFwdRedeem; // <-- Amount node will redeem to next.
STAmount saFwdIssue; // <-- Amount node will issue to next.
// Issue isn't used by offers.
STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee.
// For offers:
// For offers:
STAmount saRateMax;
STAmount saRateMax;
// Directory
uint256 uDirectTip; // Current directory.
uint256 uDirectEnd; // Next order book.
bool bDirectAdvance; // Need to advance directory.
SLE::pointer sleDirectDir;
STAmount saOfrRate; // For correct ratio.
// Directory
uint256 uDirectTip; // Current directory.
uint256 uDirectEnd; // Next order book.
bool bDirectAdvance; // Need to advance directory.
SLE::pointer sleDirectDir;
STAmount saOfrRate; // For correct ratio.
// Node
bool bEntryAdvance; // Need to advance entry.
unsigned int uEntry;
uint256 uOfferIndex;
SLE::pointer sleOffer;
uint160 uOfrOwnerID;
bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets.
STAmount saOfferFunds;
STAmount saTakerPays;
STAmount saTakerGets;
// Node
bool bEntryAdvance; // Need to advance entry.
unsigned int uEntry;
uint256 uOfferIndex;
SLE::pointer sleOffer;
uint160 uOfrOwnerID;
bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets.
STAmount saOfferFunds;
STAmount saTakerPays;
STAmount saTakerGets;
};
// account id, currency id, issuer id :: node
typedef boost::tuple<uint160, uint160, uint160> aciSource;
typedef boost::unordered_map<aciSource, unsigned int> curIssuerNode; // Map of currency, issuer to node index.
typedef boost::unordered_map<aciSource, unsigned int>::const_iterator curIssuerNodeConstIterator;
typedef boost::unordered_map<aciSource, unsigned int> curIssuerNode; // Map of currency, issuer to node index.
typedef boost::unordered_map<aciSource, unsigned int>::const_iterator curIssuerNodeConstIterator;
extern std::size_t hash_value(const aciSource& asValue);
extern std::size_t hash_value (const aciSource& asValue);
// Holds a path state under incremental application.
class PathState
{
public:
typedef boost::shared_ptr<PathState> pointer;
typedef const boost::shared_ptr<PathState>& ref;
typedef boost::shared_ptr<PathState> pointer;
typedef const boost::shared_ptr<PathState>& ref;
TER terStatus;
std::vector<PaymentNode> vpnNodes;
TER terStatus;
std::vector<PaymentNode> vpnNodes;
// When processing, don't want to complicate directory walking with deletion.
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded or were completely consumed.
// When processing, don't want to complicate directory walking with deletion.
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded or were completely consumed.
// First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be
// used there.
curIssuerNode umForward; // Map of currency, issuer to node index.
// First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be
// used there.
curIssuerNode umForward; // Map of currency, issuer to node index.
// First time working in reverse a funding source was used.
// Source may only be used there if not mentioned by an account.
curIssuerNode umReverse; // Map of currency, issuer to node index.
// First time working in reverse a funding source was used.
// Source may only be used there if not mentioned by an account.
curIssuerNode umReverse; // Map of currency, issuer to node index.
LedgerEntrySet lesEntries;
LedgerEntrySet lesEntries;
int mIndex; // Index/rank amoung siblings.
uint64 uQuality; // 0 = no quality/liquity left.
const STAmount& saInReq; // --> Max amount to spend by sender.
STAmount saInAct; // --> Amount spent by sender so far.
STAmount saInPass; // <-- Amount spent by sender.
const STAmount& saOutReq; // --> Amount to send.
STAmount saOutAct; // --> Amount actually sent so far.
STAmount saOutPass; // <-- Amount actually sent.
bool bConsumed; // If true, use consumes full liquidity. False, may or may not.
int mIndex; // Index/rank amoung siblings.
uint64 uQuality; // 0 = no quality/liquity left.
const STAmount& saInReq; // --> Max amount to spend by sender.
STAmount saInAct; // --> Amount spent by sender so far.
STAmount saInPass; // <-- Amount spent by sender.
const STAmount& saOutReq; // --> Amount to send.
STAmount saOutAct; // --> Amount actually sent so far.
STAmount saOutPass; // <-- Amount actually sent.
bool bConsumed; // If true, use consumes full liquidity. False, may or may not.
PathState* setIndex(const int iIndex) {
mIndex = iIndex;
PathState* setIndex (const int iIndex)
{
mIndex = iIndex;
return this;
}
return this;
}
int getIndex() { return mIndex; };
int getIndex ()
{
return mIndex;
};
PathState(
const STAmount& saSend,
const STAmount& saSendMax
) : saInReq(saSendMax), saOutReq(saSend) { ; }
PathState (
const STAmount& saSend,
const STAmount& saSendMax
) : saInReq (saSendMax), saOutReq (saSend)
{
;
}
PathState(const PathState& psSrc, bool bUnused)
: saInReq(psSrc.saInReq), saOutReq(psSrc.saOutReq) { ; }
PathState (const PathState& psSrc, bool bUnused)
: saInReq (psSrc.saInReq), saOutReq (psSrc.saOutReq)
{
;
}
void setExpanded(
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID
);
void setExpanded (
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID
);
void setCanonical(
const PathState& psExpanded
);
void setCanonical (
const PathState& psExpanded
);
Json::Value getJson() const;
Json::Value getJson () const;
#if 0
static PathState::pointer createCanonical(
PathState&ref pspExpanded
)
{
PathState::pointer pspNew = boost::make_shared<PathState>(pspExpanded->saOutAct, pspExpanded->saInAct);
static PathState::pointer createCanonical (
PathState& ref pspExpanded
)
{
PathState::pointer pspNew = boost::make_shared<PathState> (pspExpanded->saOutAct, pspExpanded->saInAct);
pspNew->setCanonical(pspExpanded);
pspNew->setCanonical (pspExpanded);
return pspNew;
}
return pspNew;
}
#endif
static bool lessPriority(PathState& lhs, PathState& rhs);
static bool lessPriority (PathState& lhs, PathState& rhs);
private:
TER pushNode(const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
TER pushImply(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
TER pushNode (const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
TER pushImply (const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
};
class RippleCalc
{
public:
// First time working in reverse a funding source was mentioned. Source may only be used there.
curIssuerNode mumSource; // Map of currency, issuer to node index.
// First time working in reverse a funding source was mentioned. Source may only be used there.
curIssuerNode mumSource; // Map of currency, issuer to node index.
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
void pathNext(PathState::ref psrCur, const bool bMultiQuality, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
TER calcNode(const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeFwd(const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferFwd(const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountFwd(const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAdvance(const unsigned int uNode, PathState& psCur, const bool bMultiQuality, const bool bReverse);
TER calcNodeDeliverRev(
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uOutAccountID,
const STAmount& saOutReq,
STAmount& saOutAct);
void pathNext (PathState::ref psrCur, const bool bMultiQuality, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
TER calcNode (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAdvance (const unsigned int uNode, PathState& psCur, const bool bMultiQuality, const bool bReverse);
TER calcNodeDeliverRev (
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uOutAccountID,
const STAmount& saOutReq,
STAmount& saOutAct);
TER calcNodeDeliverFwd(
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uInAccountID,
const STAmount& saInReq,
STAmount& saInAct,
STAmount& saInFees);
TER calcNodeDeliverFwd (
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uInAccountID,
const STAmount& saInReq,
STAmount& saInAct,
STAmount& saInFees);
void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut,
const STAmount& saPrvReq, const STAmount& saCurReq,
STAmount& saPrvAct, STAmount& saCurAct,
uint64& uRateMax);
void calcNodeRipple (const uint32 uQualityIn, const uint32 uQualityOut,
const STAmount& saPrvReq, const STAmount& saCurReq,
STAmount& saPrvAct, STAmount& saCurAct,
uint64& uRateMax);
RippleCalc(LedgerEntrySet& lesNodes, const bool bOpenLedger)
: lesActive(lesNodes), mOpenLedger(bOpenLedger) { ; }
RippleCalc (LedgerEntrySet& lesNodes, const bool bOpenLedger)
: lesActive (lesNodes), mOpenLedger (bOpenLedger)
{
;
}
static TER rippleCalc(
LedgerEntrySet& lesActive,
STAmount& saMaxAmountAct,
STAmount& saDstAmountAct,
std::vector<PathState::pointer>& vpsExpanded,
const STAmount& saDstAmountReq,
const STAmount& saMaxAmountReq,
const uint160& uDstAccountID,
const uint160& uSrcAccountID,
const STPathSet& spsPaths,
const bool bPartialPayment,
const bool bLimitQuality,
const bool bNoRippleDirect,
const bool bStandAlone, // --> True, not to affect accounts.
const bool bOpenLedger = true // --> What kind of errors to return.
);
static TER rippleCalc (
LedgerEntrySet& lesActive,
STAmount& saMaxAmountAct,
STAmount& saDstAmountAct,
std::vector<PathState::pointer>& vpsExpanded,
const STAmount& saDstAmountReq,
const STAmount& saMaxAmountReq,
const uint160& uDstAccountID,
const uint160& uSrcAccountID,
const STPathSet& spsPaths,
const bool bPartialPayment,
const bool bLimitQuality,
const bool bNoRippleDirect,
const bool bStandAlone, // --> True, not to affect accounts.
const bool bOpenLedger = true // --> What kind of errors to return.
);
static void setCanonical(STPathSet& spsDst, const std::vector<PathState::pointer>& vpsExpanded, bool bKeepDefault);
static void setCanonical (STPathSet& spsDst, const std::vector<PathState::pointer>& vpsExpanded, bool bKeepDefault);
protected:
LedgerEntrySet& lesActive;
bool mOpenLedger;
LedgerEntrySet& lesActive;
bool mOpenLedger;
};
#endif

View File

@@ -1,55 +1,56 @@
AccountItem::pointer RippleState::makeItem(const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry)
AccountItem::pointer RippleState::makeItem (const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry)
{
if (!ledgerEntry || ledgerEntry->getType() != ltRIPPLE_STATE)
return AccountItem::pointer();
RippleState* rs = new RippleState(ledgerEntry);
rs->setViewAccount(accountID);
if (!ledgerEntry || ledgerEntry->getType () != ltRIPPLE_STATE)
return AccountItem::pointer ();
return AccountItem::pointer(rs);
RippleState* rs = new RippleState (ledgerEntry);
rs->setViewAccount (accountID);
return AccountItem::pointer (rs);
}
RippleState::RippleState(SerializedLedgerEntry::ref ledgerEntry) : AccountItem(ledgerEntry),
mValid(false),
mViewLowest(true),
RippleState::RippleState (SerializedLedgerEntry::ref ledgerEntry) : AccountItem (ledgerEntry),
mValid (false),
mViewLowest (true),
mLowLimit(ledgerEntry->getFieldAmount(sfLowLimit)),
mHighLimit(ledgerEntry->getFieldAmount(sfHighLimit)),
mLowLimit (ledgerEntry->getFieldAmount (sfLowLimit)),
mHighLimit (ledgerEntry->getFieldAmount (sfHighLimit)),
mLowID(mLowLimit.getIssuer()),
mHighID(mHighLimit.getIssuer()),
mLowID (mLowLimit.getIssuer ()),
mHighID (mHighLimit.getIssuer ()),
mBalance(ledgerEntry->getFieldAmount(sfBalance))
mBalance (ledgerEntry->getFieldAmount (sfBalance))
{
mFlags = mLedgerEntry->getFieldU32(sfFlags);
mFlags = mLedgerEntry->getFieldU32 (sfFlags);
mLowQualityIn = mLedgerEntry->getFieldU32(sfLowQualityIn);
mLowQualityOut = mLedgerEntry->getFieldU32(sfLowQualityOut);
mLowQualityIn = mLedgerEntry->getFieldU32 (sfLowQualityIn);
mLowQualityOut = mLedgerEntry->getFieldU32 (sfLowQualityOut);
mHighQualityIn = mLedgerEntry->getFieldU32(sfHighQualityIn);
mHighQualityOut = mLedgerEntry->getFieldU32(sfHighQualityOut);
mHighQualityIn = mLedgerEntry->getFieldU32 (sfHighQualityIn);
mHighQualityOut = mLedgerEntry->getFieldU32 (sfHighQualityOut);
mValid = true;
mValid = true;
}
void RippleState::setViewAccount(const uint160& accountID)
void RippleState::setViewAccount (const uint160& accountID)
{
bool bViewLowestNew = mLowID == accountID;
bool bViewLowestNew = mLowID == accountID;
if (bViewLowestNew != mViewLowest)
{
mViewLowest = bViewLowestNew;
mBalance.negate();
}
if (bViewLowestNew != mViewLowest)
{
mViewLowest = bViewLowestNew;
mBalance.negate ();
}
}
Json::Value RippleState::getJson(int)
Json::Value RippleState::getJson (int)
{
Json::Value ret(Json::objectValue);
ret["low_id"] = mLowID.GetHex();
ret["high_id"] = mHighID.GetHex();
return ret;
Json::Value ret (Json::objectValue);
ret["low_id"] = mLowID.GetHex ();
ret["high_id"] = mHighID.GetHex ();
return ret;
}
// vim:ts=4

View File

@@ -9,57 +9,96 @@
class RippleState : public AccountItem
{
public:
typedef boost::shared_ptr<RippleState> pointer;
typedef boost::shared_ptr<RippleState> pointer;
private:
bool mValid;
bool mViewLowest;
bool mValid;
bool mViewLowest;
uint32 mFlags;
uint32 mFlags;
STAmount mLowLimit;
STAmount mHighLimit;
STAmount mLowLimit;
STAmount mHighLimit;
uint160 mLowID;
uint160 mHighID;
uint160 mLowID;
uint160 mHighID;
uint64 mLowQualityIn;
uint64 mLowQualityOut;
uint64 mHighQualityIn;
uint64 mHighQualityOut;
uint64 mLowQualityIn;
uint64 mLowQualityOut;
uint64 mHighQualityIn;
uint64 mHighQualityOut;
STAmount mBalance;
STAmount mBalance;
RippleState(SerializedLedgerEntry::ref ledgerEntry); // For accounts in a ledger
RippleState (SerializedLedgerEntry::ref ledgerEntry); // For accounts in a ledger
public:
RippleState(){ }
virtual ~RippleState(){}
AccountItem::pointer makeItem(const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry);
LedgerEntryType getType(){ return(ltRIPPLE_STATE); }
RippleState () { }
virtual ~RippleState () {}
AccountItem::pointer makeItem (const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry);
LedgerEntryType getType ()
{
return (ltRIPPLE_STATE);
}
void setViewAccount(const uint160& accountID);
void setViewAccount (const uint160& accountID);
const uint160& getAccountID() const { return mViewLowest ? mLowID : mHighID; }
const uint160& getAccountIDPeer() const { return !mViewLowest ? mLowID : mHighID; }
const uint160& getAccountID () const
{
return mViewLowest ? mLowID : mHighID;
}
const uint160& getAccountIDPeer () const
{
return !mViewLowest ? mLowID : mHighID;
}
// True, Provided auth to peer.
bool getAuth() const { return isSetBit(mFlags, mViewLowest ? lsfLowAuth : lsfHighAuth); }
bool getAuthPeer() const { return isSetBit(mFlags, !mViewLowest ? lsfLowAuth : lsfHighAuth); }
// True, Provided auth to peer.
bool getAuth () const
{
return isSetBit (mFlags, mViewLowest ? lsfLowAuth : lsfHighAuth);
}
bool getAuthPeer () const
{
return isSetBit (mFlags, !mViewLowest ? lsfLowAuth : lsfHighAuth);
}
const STAmount& getBalance() const { return mBalance; }
const STAmount& getLimit() const { return mViewLowest ? mLowLimit : mHighLimit; }
const STAmount& getLimitPeer() const { return !mViewLowest ? mLowLimit : mHighLimit; }
const STAmount& getBalance () const
{
return mBalance;
}
const STAmount& getLimit () const
{
return mViewLowest ? mLowLimit : mHighLimit;
}
const STAmount& getLimitPeer () const
{
return !mViewLowest ? mLowLimit : mHighLimit;
}
uint32 getQualityIn() const { return((uint32) (mViewLowest ? mLowQualityIn : mHighQualityIn)); }
uint32 getQualityOut() const { return((uint32) (mViewLowest ? mLowQualityOut : mHighQualityOut)); }
uint32 getQualityIn () const
{
return ((uint32) (mViewLowest ? mLowQualityIn : mHighQualityIn));
}
uint32 getQualityOut () const
{
return ((uint32) (mViewLowest ? mLowQualityOut : mHighQualityOut));
}
SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; }
const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; }
SerializedLedgerEntry& peekSLE() { return *mLedgerEntry; }
Json::Value getJson(int);
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
const SerializedLedgerEntry& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Json::Value getJson (int);
Blob getRaw() const;
Blob getRaw () const;
};
#endif
// vim:ts=4

View File

@@ -11,238 +11,260 @@ SETUP_LOG (SNTPClient)
// #define SNTP_DEBUG
static uint8_t SNTPQueryData[48] =
{ 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
{ 0x1B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// NTP query frequency - 4 minutes
#define NTP_QUERY_FREQUENCY (4 * 60)
#define NTP_QUERY_FREQUENCY (4 * 60)
// NTP minimum interval to query same servers - 3 minutes
#define NTP_MIN_QUERY (3 * 60)
#define NTP_MIN_QUERY (3 * 60)
// NTP sample window (should be odd)
#define NTP_SAMPLE_WINDOW 9
#define NTP_SAMPLE_WINDOW 9
// NTP timestamp constant
#define NTP_UNIX_OFFSET 0x83AA7E80
#define NTP_UNIX_OFFSET 0x83AA7E80
// NTP timestamp validity
#define NTP_TIMESTAMP_VALID ((NTP_QUERY_FREQUENCY + NTP_MIN_QUERY) * 2)
#define NTP_TIMESTAMP_VALID ((NTP_QUERY_FREQUENCY + NTP_MIN_QUERY) * 2)
// SNTP packet offsets
#define NTP_OFF_INFO 0
#define NTP_OFF_ROOTDELAY 1
#define NTP_OFF_ROOTDISP 2
#define NTP_OFF_REFERENCEID 3
#define NTP_OFF_REFTS_INT 4
#define NTP_OFF_REFTS_FRAC 5
#define NTP_OFF_ORGTS_INT 6
#define NTP_OFF_ORGTS_FRAC 7
#define NTP_OFF_RECVTS_INT 8
#define NTP_OFF_RECVTS_FRAC 9
#define NTP_OFF_XMITTS_INT 10
#define NTP_OFF_XMITTS_FRAC 11
#define NTP_OFF_INFO 0
#define NTP_OFF_ROOTDELAY 1
#define NTP_OFF_ROOTDISP 2
#define NTP_OFF_REFERENCEID 3
#define NTP_OFF_REFTS_INT 4
#define NTP_OFF_REFTS_FRAC 5
#define NTP_OFF_ORGTS_INT 6
#define NTP_OFF_ORGTS_FRAC 7
#define NTP_OFF_RECVTS_INT 8
#define NTP_OFF_RECVTS_FRAC 9
#define NTP_OFF_XMITTS_INT 10
#define NTP_OFF_XMITTS_FRAC 11
SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service),
mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256)
SNTPClient::SNTPClient (boost::asio::io_service& service) : mSocket (service), mTimer (service), mResolver (service),
mOffset (0), mLastOffsetUpdate ((time_t) - 1), mReceiveBuffer (256)
{
mSocket.open(boost::asio::ip::udp::v4());
mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint,
boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
mSocket.open (boost::asio::ip::udp::v4 ());
mSocket.async_receive_from (boost::asio::buffer (mReceiveBuffer, 256), mReceiveEndpoint,
boost::bind (&SNTPClient::receivePacket, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY));
mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
mTimer.expires_from_now (boost::posix_time::seconds (NTP_QUERY_FREQUENCY));
mTimer.async_wait (boost::bind (&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
}
void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it)
void SNTPClient::resolveComplete (const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it)
{
if (!error)
{
boost::asio::ip::udp::resolver::iterator sel = it;
int i = 1;
while (++it != boost::asio::ip::udp::resolver::iterator())
if ((rand() % ++i) == 0)
sel = it;
if (sel != boost::asio::ip::udp::resolver::iterator())
{
boost::mutex::scoped_lock sl(mLock);
SNTPQuery& query = mQueries[*sel];
time_t now = time(NULL);
if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now))
{ // This can happen if the same IP address is reached through multiple names
WriteLog (lsTRACE, SNTPClient) << "SNTP: Redundant query suppressed";
return;
}
query.mReceivedReply = false;
query.mLocalTimeSent = now;
RandomNumbers::getInstance ().fill (&query.mQueryNonce);
reinterpret_cast<uint32*>(SNTPQueryData)[NTP_OFF_XMITTS_INT] = static_cast<uint32>(time(NULL)) + NTP_UNIX_OFFSET;
reinterpret_cast<uint32*>(SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.mQueryNonce;
mSocket.async_send_to(boost::asio::buffer(SNTPQueryData, 48), *sel,
boost::bind(&SNTPClient::sendComplete, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
}
if (!error)
{
boost::asio::ip::udp::resolver::iterator sel = it;
int i = 1;
while (++it != boost::asio::ip::udp::resolver::iterator ())
if ((rand () % ++i) == 0)
sel = it;
if (sel != boost::asio::ip::udp::resolver::iterator ())
{
boost::mutex::scoped_lock sl (mLock);
SNTPQuery& query = mQueries[*sel];
time_t now = time (NULL);
if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now))
{
// This can happen if the same IP address is reached through multiple names
WriteLog (lsTRACE, SNTPClient) << "SNTP: Redundant query suppressed";
return;
}
query.mReceivedReply = false;
query.mLocalTimeSent = now;
RandomNumbers::getInstance ().fill (&query.mQueryNonce);
reinterpret_cast<uint32*> (SNTPQueryData)[NTP_OFF_XMITTS_INT] = static_cast<uint32> (time (NULL)) + NTP_UNIX_OFFSET;
reinterpret_cast<uint32*> (SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.mQueryNonce;
mSocket.async_send_to (boost::asio::buffer (SNTPQueryData, 48), *sel,
boost::bind (&SNTPClient::sendComplete, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
}
}
void SNTPClient::receivePacket(const boost::system::error_code& error, std::size_t bytes_xferd)
void SNTPClient::receivePacket (const boost::system::error_code& error, std::size_t bytes_xferd)
{
if (!error)
{
boost::mutex::scoped_lock sl(mLock);
if (!error)
{
boost::mutex::scoped_lock sl (mLock);
#ifdef SNTP_DEBUG
WriteLog (lsTRACE, SNTPClient) << "SNTP: Packet from " << mReceiveEndpoint;
WriteLog (lsTRACE, SNTPClient) << "SNTP: Packet from " << mReceiveEndpoint;
#endif
std::map<boost::asio::ip::udp::endpoint, SNTPQuery>::iterator query = mQueries.find(mReceiveEndpoint);
if (query == mQueries.end())
WriteLog (lsDEBUG, SNTPClient) << "SNTP: Reply from " << mReceiveEndpoint << " found without matching query";
else if (query->second.mReceivedReply)
WriteLog (lsDEBUG, SNTPClient) << "SNTP: Duplicate response from " << mReceiveEndpoint;
else
{
query->second.mReceivedReply = true;
if (time(NULL) > (query->second.mLocalTimeSent + 1))
WriteLog (lsWARNING, SNTPClient) << "SNTP: Late response from " << mReceiveEndpoint;
else if (bytes_xferd < 48)
WriteLog (lsWARNING, SNTPClient) << "SNTP: Short reply from " << mReceiveEndpoint
<< " (" << bytes_xferd << ") " << mReceiveBuffer.size();
else if (reinterpret_cast<uint32*>(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryNonce)
WriteLog (lsWARNING, SNTPClient) << "SNTP: Reply from " << mReceiveEndpoint << "had wrong nonce";
else
processReply();
}
}
std::map<boost::asio::ip::udp::endpoint, SNTPQuery>::iterator query = mQueries.find (mReceiveEndpoint);
mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint,
boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
if (query == mQueries.end ())
WriteLog (lsDEBUG, SNTPClient) << "SNTP: Reply from " << mReceiveEndpoint << " found without matching query";
else if (query->second.mReceivedReply)
WriteLog (lsDEBUG, SNTPClient) << "SNTP: Duplicate response from " << mReceiveEndpoint;
else
{
query->second.mReceivedReply = true;
if (time (NULL) > (query->second.mLocalTimeSent + 1))
WriteLog (lsWARNING, SNTPClient) << "SNTP: Late response from " << mReceiveEndpoint;
else if (bytes_xferd < 48)
WriteLog (lsWARNING, SNTPClient) << "SNTP: Short reply from " << mReceiveEndpoint
<< " (" << bytes_xferd << ") " << mReceiveBuffer.size ();
else if (reinterpret_cast<uint32*> (&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryNonce)
WriteLog (lsWARNING, SNTPClient) << "SNTP: Reply from " << mReceiveEndpoint << "had wrong nonce";
else
processReply ();
}
}
mSocket.async_receive_from (boost::asio::buffer (mReceiveBuffer, 256), mReceiveEndpoint,
boost::bind (&SNTPClient::receivePacket, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void SNTPClient::sendComplete(const boost::system::error_code& error, std::size_t)
void SNTPClient::sendComplete (const boost::system::error_code& error, std::size_t)
{
CondLog (error, lsWARNING, SNTPClient) << "SNTP: Send error";
CondLog (error, lsWARNING, SNTPClient) << "SNTP: Send error";
}
void SNTPClient::processReply()
void SNTPClient::processReply ()
{
assert(mReceiveBuffer.size() >= 48);
uint32 *recvBuffer = reinterpret_cast<uint32*>(&mReceiveBuffer.front());
assert (mReceiveBuffer.size () >= 48);
uint32* recvBuffer = reinterpret_cast<uint32*> (&mReceiveBuffer.front ());
unsigned info = ntohl(recvBuffer[NTP_OFF_INFO]);
int64_t timev = ntohl(recvBuffer[NTP_OFF_RECVTS_INT]);
unsigned stratum = (info >> 16) & 0xff;
unsigned info = ntohl (recvBuffer[NTP_OFF_INFO]);
int64_t timev = ntohl (recvBuffer[NTP_OFF_RECVTS_INT]);
unsigned stratum = (info >> 16) & 0xff;
if ((info >> 30) == 3)
{
WriteLog (lsINFO, SNTPClient) << "SNTP: Alarm condition " << mReceiveEndpoint;
return;
}
if ((stratum == 0) || (stratum > 14))
{
WriteLog (lsINFO, SNTPClient) << "SNTP: Unreasonable stratum (" << stratum << ") from " << mReceiveEndpoint;
return;
}
if ((info >> 30) == 3)
{
WriteLog (lsINFO, SNTPClient) << "SNTP: Alarm condition " << mReceiveEndpoint;
return;
}
int64 now = static_cast<int>(time(NULL));
timev -= now;
timev -= NTP_UNIX_OFFSET;
if ((stratum == 0) || (stratum > 14))
{
WriteLog (lsINFO, SNTPClient) << "SNTP: Unreasonable stratum (" << stratum << ") from " << mReceiveEndpoint;
return;
}
// add offset to list, replacing oldest one if appropriate
mOffsetList.push_back(timev);
if (mOffsetList.size() >= NTP_SAMPLE_WINDOW)
mOffsetList.pop_front();
mLastOffsetUpdate = now;
int64 now = static_cast<int> (time (NULL));
timev -= now;
timev -= NTP_UNIX_OFFSET;
// select median time
std::list<int> offsetList = mOffsetList;
offsetList.sort();
int j = offsetList.size();
std::list<int>::iterator it = offsetList.begin();
for (int i = 0; i < (j / 2); ++i)
++it;
mOffset = *it;
if ((j % 2) == 0)
mOffset = (mOffset + (*--it)) / 2;
// add offset to list, replacing oldest one if appropriate
mOffsetList.push_back (timev);
if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good
mOffset = 0;
if (mOffsetList.size () >= NTP_SAMPLE_WINDOW)
mOffsetList.pop_front ();
CondLog (timev || mOffset, lsTRACE, SNTPClient) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset;
mLastOffsetUpdate = now;
// select median time
std::list<int> offsetList = mOffsetList;
offsetList.sort ();
int j = offsetList.size ();
std::list<int>::iterator it = offsetList.begin ();
for (int i = 0; i < (j / 2); ++i)
++it;
mOffset = *it;
if ((j % 2) == 0)
mOffset = (mOffset + (*--it)) / 2;
if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good
mOffset = 0;
CondLog (timev || mOffset, lsTRACE, SNTPClient) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset;
}
void SNTPClient::timerEntry(const boost::system::error_code& error)
void SNTPClient::timerEntry (const boost::system::error_code& error)
{
if (!error)
{
doQuery();
mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY));
mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
}
if (!error)
{
doQuery ();
mTimer.expires_from_now (boost::posix_time::seconds (NTP_QUERY_FREQUENCY));
mTimer.async_wait (boost::bind (&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
}
}
void SNTPClient::addServer(const std::string& server)
void SNTPClient::addServer (const std::string& server)
{
boost::mutex::scoped_lock sl(mLock);
mServers.push_back(std::make_pair(server, (time_t) -1));
boost::mutex::scoped_lock sl (mLock);
mServers.push_back (std::make_pair (server, (time_t) - 1));
}
void SNTPClient::init(const std::vector<std::string>& servers)
void SNTPClient::init (const std::vector<std::string>& servers)
{
std::vector<std::string>::const_iterator it = servers.begin();
if (it == servers.end())
{
WriteLog (lsINFO, SNTPClient) << "SNTP: no server specified";
return;
}
BOOST_FOREACH(const std::string& it, servers)
addServer(it);
queryAll();
std::vector<std::string>::const_iterator it = servers.begin ();
if (it == servers.end ())
{
WriteLog (lsINFO, SNTPClient) << "SNTP: no server specified";
return;
}
BOOST_FOREACH (const std::string & it, servers)
addServer (it);
queryAll ();
}
void SNTPClient::queryAll()
void SNTPClient::queryAll ()
{
while (doQuery())
nothing();
while (doQuery ())
nothing ();
}
bool SNTPClient::getOffset(int& offset)
bool SNTPClient::getOffset (int& offset)
{
boost::mutex::scoped_lock sl(mLock);
if ((mLastOffsetUpdate == (time_t) -1) || ((mLastOffsetUpdate + NTP_TIMESTAMP_VALID) < time(NULL)))
return false;
offset = mOffset;
return true;
boost::mutex::scoped_lock sl (mLock);
if ((mLastOffsetUpdate == (time_t) - 1) || ((mLastOffsetUpdate + NTP_TIMESTAMP_VALID) < time (NULL)))
return false;
offset = mOffset;
return true;
}
bool SNTPClient::doQuery()
bool SNTPClient::doQuery ()
{
boost::mutex::scoped_lock sl(mLock);
std::vector< std::pair<std::string, time_t> >::iterator best = mServers.end();
for (std::vector< std::pair<std::string, time_t> >::iterator it = mServers.begin(), end = best;
it != end; ++it)
if ((best == end) || (it->second == (time_t) -1) || (it->second < best->second))
best = it;
if (best == mServers.end())
{
WriteLog (lsINFO, SNTPClient) << "SNTP: No server to query";
return false;
}
time_t now = time(NULL);
if ((best->second != (time_t) -1) && ((best->second + NTP_MIN_QUERY) >= now))
{
WriteLog (lsTRACE, SNTPClient) << "SNTP: All servers recently queried";
return false;
}
best->second = now;
boost::mutex::scoped_lock sl (mLock);
std::vector< std::pair<std::string, time_t> >::iterator best = mServers.end ();
boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), best->first, "ntp");
mResolver.async_resolve(query,
boost::bind(&SNTPClient::resolveComplete, this,
boost::asio::placeholders::error, boost::asio::placeholders::iterator));
for (std::vector< std::pair<std::string, time_t> >::iterator it = mServers.begin (), end = best;
it != end; ++it)
if ((best == end) || (it->second == (time_t) - 1) || (it->second < best->second))
best = it;
if (best == mServers.end ())
{
WriteLog (lsINFO, SNTPClient) << "SNTP: No server to query";
return false;
}
time_t now = time (NULL);
if ((best->second != (time_t) - 1) && ((best->second + NTP_MIN_QUERY) >= now))
{
WriteLog (lsTRACE, SNTPClient) << "SNTP: All servers recently queried";
return false;
}
best->second = now;
boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), best->first, "ntp");
mResolver.async_resolve (query,
boost::bind (&SNTPClient::resolveComplete, this,
boost::asio::placeholders::error, boost::asio::placeholders::iterator));
#ifdef SNTP_DEBUG
WriteLog (lsTRACE, SNTPClient) << "SNTP: Resolve pending for " << best->first;
WriteLog (lsTRACE, SNTPClient) << "SNTP: Resolve pending for " << best->first;
#endif
return true;
return true;
}
// vim:ts=4

View File

@@ -12,47 +12,50 @@
class SNTPQuery
{
public:
bool mReceivedReply;
time_t mLocalTimeSent;
uint32 mQueryNonce;
bool mReceivedReply;
time_t mLocalTimeSent;
uint32 mQueryNonce;
SNTPQuery(time_t j = (time_t) -1) : mReceivedReply(false), mLocalTimeSent(j) { ; }
SNTPQuery (time_t j = (time_t) - 1) : mReceivedReply (false), mLocalTimeSent (j)
{
;
}
};
class SNTPClient
{
public:
SNTPClient(boost::asio::io_service& service);
void init(const std::vector<std::string>& servers);
void addServer(const std::string& mServer);
SNTPClient (boost::asio::io_service& service);
void init (const std::vector<std::string>& servers);
void addServer (const std::string& mServer);
void queryAll();
bool doQuery();
bool getOffset(int& offset);
void queryAll ();
bool doQuery ();
bool getOffset (int& offset);
private:
std::map<boost::asio::ip::udp::endpoint, SNTPQuery> mQueries;
boost::mutex mLock;
std::map<boost::asio::ip::udp::endpoint, SNTPQuery> mQueries;
boost::mutex mLock;
boost::asio::ip::udp::socket mSocket;
boost::asio::deadline_timer mTimer;
boost::asio::ip::udp::resolver mResolver;
boost::asio::ip::udp::socket mSocket;
boost::asio::deadline_timer mTimer;
boost::asio::ip::udp::resolver mResolver;
std::vector< std::pair<std::string, time_t> > mServers;
std::vector< std::pair<std::string, time_t> > mServers;
int mOffset;
time_t mLastOffsetUpdate;
std::list<int> mOffsetList;
int mOffset;
time_t mLastOffsetUpdate;
std::list<int> mOffsetList;
std::vector<uint8_t> mReceiveBuffer;
boost::asio::ip::udp::endpoint mReceiveEndpoint;
std::vector<uint8_t> mReceiveBuffer;
boost::asio::ip::udp::endpoint mReceiveEndpoint;
void receivePacket(const boost::system::error_code& error, std::size_t bytes);
void resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator iterator);
void sentPacket(boost::shared_ptr<std::string>, const boost::system::error_code&, std::size_t);
void timerEntry(const boost::system::error_code&);
void sendComplete(const boost::system::error_code& error, std::size_t bytesTransferred);
void processReply();
void receivePacket (const boost::system::error_code& error, std::size_t bytes);
void resolveComplete (const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator iterator);
void sentPacket (boost::shared_ptr<std::string>, const boost::system::error_code&, std::size_t);
void timerEntry (const boost::system::error_code&);
void sendComplete (const boost::system::error_code& error, std::size_t bytesTransferred);
void processReply ();
};
#endif

View File

@@ -1,87 +1,160 @@
#ifndef SCRIPT_DATA_H
#define SCRIPT_DATA_H
namespace Script {
namespace Script
{
class Data
{
public:
typedef boost::shared_ptr<Data> pointer;
typedef boost::shared_ptr<Data> pointer;
virtual ~Data(){ ; }
virtual ~Data ()
{
;
}
virtual bool isInt32(){ return(false); }
virtual bool isFloat(){ return(false); }
virtual bool isUint160(){ return(false); }
virtual bool isError(){ return(false); }
virtual bool isTrue(){ return(false); }
virtual bool isBool(){ return(false); }
//virtual bool isBlockEnd(){ return(false); }
virtual bool isInt32 ()
{
return (false);
}
virtual bool isFloat ()
{
return (false);
}
virtual bool isUint160 ()
{
return (false);
}
virtual bool isError ()
{
return (false);
}
virtual bool isTrue ()
{
return (false);
}
virtual bool isBool ()
{
return (false);
}
//virtual bool isBlockEnd(){ return(false); }
virtual int getInt(){ return(0); }
virtual float getFloat(){ return(0); }
virtual uint160 getUint160(){ return(0); }
virtual int getInt ()
{
return (0);
}
virtual float getFloat ()
{
return (0);
}
virtual uint160 getUint160 ()
{
return (0);
}
//virtual bool isCurrency(){ return(false); }
//virtual bool isCurrency(){ return(false); }
};
class IntData : public Data
{
int mValue;
int mValue;
public:
IntData(int value)
{
mValue=value;
}
bool isInt32(){ return(true); }
int getInt(){ return(mValue); }
float getFloat(){ return((float)mValue); }
bool isTrue(){ return(mValue!=0); }
IntData (int value)
{
mValue = value;
}
bool isInt32 ()
{
return (true);
}
int getInt ()
{
return (mValue);
}
float getFloat ()
{
return ((float)mValue);
}
bool isTrue ()
{
return (mValue != 0);
}
};
class FloatData : public Data
{
float mValue;
float mValue;
public:
FloatData(float value)
{
mValue=value;
}
bool isFloat(){ return(true); }
float getFloat(){ return(mValue); }
bool isTrue(){ return(mValue!=0); }
FloatData (float value)
{
mValue = value;
}
bool isFloat ()
{
return (true);
}
float getFloat ()
{
return (mValue);
}
bool isTrue ()
{
return (mValue != 0);
}
};
class Uint160Data : public Data
{
uint160 mValue;
uint160 mValue;
public:
Uint160Data(uint160 value) : mValue(value) { ; }
bool isUint160(){ return(true); }
uint160 getUint160(){ return(mValue); }
Uint160Data (uint160 value) : mValue (value)
{
;
}
bool isUint160 ()
{
return (true);
}
uint160 getUint160 ()
{
return (mValue);
}
};
class BoolData : public Data
{
bool mValue;
bool mValue;
public:
BoolData(bool value)
{
mValue=value;
}
bool isBool(){ return(true); }
bool isTrue(){ return(mValue); }
BoolData (bool value)
{
mValue = value;
}
bool isBool ()
{
return (true);
}
bool isTrue ()
{
return (mValue);
}
};
class ErrorData : public Data
{
public:
bool isError(){ return(true); }
bool isError ()
{
return (true);
}
};
class BlockEndData : public Data
{
public:
bool isBlockEnd(){ return(true); }
bool isBlockEnd ()
{
return (true);
}
};

View File

@@ -1,16 +1,17 @@
DECLARE_INSTANCE(SerializedValidation);
DECLARE_INSTANCE (SerializedValidation);
SerializedValidation::SerializedValidation (SerializerIterator& sit, bool checkSignature)
: STObject (getFormat (), sit, sfValidation)
, mTrusted (false)
{
mNodeID = RippleAddress::createNodePublic(getFieldVL(sfSigningPubKey)).getNodeID();
assert(mNodeID.isNonZero());
if (checkSignature && !isValid())
mNodeID = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey)).getNodeID ();
assert (mNodeID.isNonZero ());
if (checkSignature && !isValid ())
{
Log(lsTRACE) << "Invalid validation " << getJson(0);
throw std::runtime_error("Invalid validation");
Log (lsTRACE) << "Invalid validation " << getJson (0);
throw std::runtime_error ("Invalid validation");
}
}
@@ -19,93 +20,94 @@ SerializedValidation::SerializedValidation (
const RippleAddress& raPub, bool isFull)
: STObject (getFormat (), sfValidation)
, mTrusted (false)
{ // Does not sign
setFieldH256(sfLedgerHash, ledgerHash);
setFieldU32(sfSigningTime, signTime);
{
// Does not sign
setFieldH256 (sfLedgerHash, ledgerHash);
setFieldU32 (sfSigningTime, signTime);
setFieldVL(sfSigningPubKey, raPub.getNodePublic());
mNodeID = raPub.getNodeID();
assert(mNodeID.isNonZero());
setFieldVL (sfSigningPubKey, raPub.getNodePublic ());
mNodeID = raPub.getNodeID ();
assert (mNodeID.isNonZero ());
if (!isFull)
setFlag(sFullFlag);
setFlag (sFullFlag);
}
void SerializedValidation::sign(const RippleAddress& raPriv)
void SerializedValidation::sign (const RippleAddress& raPriv)
{
uint256 signingHash;
sign(signingHash, raPriv);
sign (signingHash, raPriv);
}
void SerializedValidation::sign(uint256& signingHash, const RippleAddress& raPriv)
void SerializedValidation::sign (uint256& signingHash, const RippleAddress& raPriv)
{
signingHash = getSigningHash();
signingHash = getSigningHash ();
Blob signature;
raPriv.signNodePrivate(signingHash, signature);
setFieldVL(sfSignature, signature);
raPriv.signNodePrivate (signingHash, signature);
setFieldVL (sfSignature, signature);
}
uint256 SerializedValidation::getSigningHash() const
uint256 SerializedValidation::getSigningHash () const
{
return STObject::getSigningHash(theConfig.SIGN_VALIDATION);
return STObject::getSigningHash (theConfig.SIGN_VALIDATION);
}
uint256 SerializedValidation::getLedgerHash() const
uint256 SerializedValidation::getLedgerHash () const
{
return getFieldH256(sfLedgerHash);
return getFieldH256 (sfLedgerHash);
}
uint32 SerializedValidation::getSignTime() const
uint32 SerializedValidation::getSignTime () const
{
return getFieldU32(sfSigningTime);
return getFieldU32 (sfSigningTime);
}
uint32 SerializedValidation::getFlags() const
uint32 SerializedValidation::getFlags () const
{
return getFieldU32(sfFlags);
return getFieldU32 (sfFlags);
}
bool SerializedValidation::isValid() const
bool SerializedValidation::isValid () const
{
return isValid(getSigningHash());
return isValid (getSigningHash ());
}
bool SerializedValidation::isValid(uint256 const& signingHash) const
bool SerializedValidation::isValid (uint256 const& signingHash) const
{
try
{
RippleAddress raPublicKey = RippleAddress::createNodePublic(getFieldVL(sfSigningPubKey));
return raPublicKey.isValid() && raPublicKey.verifyNodePublic(signingHash, getFieldVL(sfSignature));
RippleAddress raPublicKey = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey));
return raPublicKey.isValid () && raPublicKey.verifyNodePublic (signingHash, getFieldVL (sfSignature));
}
catch (...)
{
Log(lsINFO) << "exception validating validation";
Log (lsINFO) << "exception validating validation";
return false;
}
}
RippleAddress SerializedValidation::getSignerPublic() const
RippleAddress SerializedValidation::getSignerPublic () const
{
RippleAddress a;
a.setNodePublic(getFieldVL(sfSigningPubKey));
a.setNodePublic (getFieldVL (sfSigningPubKey));
return a;
}
bool SerializedValidation::isFull() const
bool SerializedValidation::isFull () const
{
return (getFlags() & sFullFlag) != 0;
return (getFlags () & sFullFlag) != 0;
}
Blob SerializedValidation::getSignature() const
Blob SerializedValidation::getSignature () const
{
return getFieldVL(sfSignature);
return getFieldVL (sfSignature);
}
Blob SerializedValidation::getSigned() const
Blob SerializedValidation::getSigned () const
{
Serializer s;
add(s);
return s.peekData();
add (s);
return s.peekData ();
}
SOTemplate const& SerializedValidation::getFormat ()
@@ -124,7 +126,7 @@ SOTemplate const& SerializedValidation::getFormat ()
format.push_back (SOElement (sfFeatures, SOE_OPTIONAL));
format.push_back (SOElement (sfBaseFee, SOE_OPTIONAL));
format.push_back (SOElement (sfReserveBase, SOE_OPTIONAL));
format.push_back (SOElement (sfReserveIncrement,SOE_OPTIONAL));
format.push_back (SOElement (sfReserveIncrement, SOE_OPTIONAL));
format.push_back (SOElement (sfSigningTime, SOE_REQUIRED));
format.push_back (SOElement (sfSigningPubKey, SOE_REQUIRED));
format.push_back (SOElement (sfSignature, SOE_OPTIONAL));

View File

@@ -8,47 +8,65 @@ class SerializedValidation
, private IS_INSTANCE (SerializedValidation)
{
public:
typedef boost::shared_ptr<SerializedValidation> pointer;
typedef const boost::shared_ptr<SerializedValidation>& ref;
typedef boost::shared_ptr<SerializedValidation> pointer;
typedef const boost::shared_ptr<SerializedValidation>& ref;
static const uint32 sFullFlag = 0x1;
static const uint32 sFullFlag = 0x1;
// These throw if the object is not valid
SerializedValidation (SerializerIterator& sit, bool checkSignature = true);
SerializedValidation (SerializerIterator & sit, bool checkSignature = true);
// Does not sign the validation
SerializedValidation (uint256 const& ledgerHash, uint32 signTime, const RippleAddress& raPub, bool isFull);
// Does not sign the validation
SerializedValidation (uint256 const & ledgerHash, uint32 signTime, const RippleAddress & raPub, bool isFull);
uint256 getLedgerHash() const;
uint32 getSignTime() const;
uint32 getFlags() const;
RippleAddress getSignerPublic() const;
uint160 getNodeID() const { return mNodeID; }
bool isValid() const;
bool isFull() const;
bool isTrusted() const { return mTrusted; }
uint256 getSigningHash() const;
bool isValid(uint256 const& ) const;
uint256 getLedgerHash () const;
uint32 getSignTime () const;
uint32 getFlags () const;
RippleAddress getSignerPublic () const;
uint160 getNodeID () const
{
return mNodeID;
}
bool isValid () const;
bool isFull () const;
bool isTrusted () const
{
return mTrusted;
}
uint256 getSigningHash () const;
bool isValid (uint256 const& ) const;
void setTrusted() { mTrusted = true; }
Blob getSigned() const;
Blob getSignature() const;
void sign(uint256& signingHash, const RippleAddress& raPrivate);
void sign(const RippleAddress& raPrivate);
void setTrusted ()
{
mTrusted = true;
}
Blob getSigned () const;
Blob getSignature () const;
void sign (uint256 & signingHash, const RippleAddress & raPrivate);
void sign (const RippleAddress & raPrivate);
// The validation this replaced
uint256 const& getPreviousHash() { return mPreviousHash; }
bool isPreviousHash(uint256 const& h) const { return mPreviousHash == h; }
void setPreviousHash(uint256 const& h) { mPreviousHash = h; }
// The validation this replaced
uint256 const& getPreviousHash ()
{
return mPreviousHash;
}
bool isPreviousHash (uint256 const & h) const
{
return mPreviousHash == h;
}
void setPreviousHash (uint256 const & h)
{
mPreviousHash = h;
}
private:
static SOTemplate const& getFormat ();
void setNode ();
void setNode ();
uint256 mPreviousHash;
uint160 mNodeID;
bool mTrusted;
uint256 mPreviousHash;
uint160 mNodeID;
bool mTrusted;
};
#endif

View File

@@ -1,95 +1,96 @@
DECLARE_INSTANCE(Transaction);
DECLARE_INSTANCE (Transaction);
Transaction::Transaction(SerializedTransaction::ref sit, bool bValidate)
: mInLedger(0), mStatus(INVALID), mResult(temUNCERTAIN), mTransaction(sit)
Transaction::Transaction (SerializedTransaction::ref sit, bool bValidate)
: mInLedger (0), mStatus (INVALID), mResult (temUNCERTAIN), mTransaction (sit)
{
try
{
mFromPubKey.setAccountPublic(mTransaction->getSigningPubKey());
mTransactionID = mTransaction->getTransactionID();
mAccountFrom = mTransaction->getSourceAccount();
}
catch(...)
{
return;
}
try
{
mFromPubKey.setAccountPublic (mTransaction->getSigningPubKey ());
mTransactionID = mTransaction->getTransactionID ();
mAccountFrom = mTransaction->getSourceAccount ();
}
catch (...)
{
return;
}
if (!bValidate || checkSign())
mStatus = NEW;
if (!bValidate || checkSign ())
mStatus = NEW;
}
Transaction::pointer Transaction::sharedTransaction(Blob const& vucTransaction, bool bValidate)
Transaction::pointer Transaction::sharedTransaction (Blob const& vucTransaction, bool bValidate)
{
try
{
Serializer s(vucTransaction);
SerializerIterator sit(s);
try
{
Serializer s (vucTransaction);
SerializerIterator sit (s);
SerializedTransaction::pointer st = boost::make_shared<SerializedTransaction>(boost::ref(sit));
SerializedTransaction::pointer st = boost::make_shared<SerializedTransaction> (boost::ref (sit));
return boost::make_shared<Transaction>(st, bValidate);
}
catch (...)
{
Log(lsWARNING) << "Exception constructing transaction";
return boost::shared_ptr<Transaction>();
}
return boost::make_shared<Transaction> (st, bValidate);
}
catch (...)
{
Log (lsWARNING) << "Exception constructing transaction";
return boost::shared_ptr<Transaction> ();
}
}
//
// Generic transaction construction
//
Transaction::Transaction(
TransactionType ttKind,
const RippleAddress& naPublicKey,
const RippleAddress& naSourceAccount,
uint32 uSeq,
const STAmount& saFee,
uint32 uSourceTag) :
mAccountFrom(naSourceAccount), mFromPubKey(naPublicKey), mInLedger(0), mStatus(NEW), mResult(temUNCERTAIN)
Transaction::Transaction (
TransactionType ttKind,
const RippleAddress& naPublicKey,
const RippleAddress& naSourceAccount,
uint32 uSeq,
const STAmount& saFee,
uint32 uSourceTag) :
mAccountFrom (naSourceAccount), mFromPubKey (naPublicKey), mInLedger (0), mStatus (NEW), mResult (temUNCERTAIN)
{
assert(mFromPubKey.isValid());
assert (mFromPubKey.isValid ());
mTransaction = boost::make_shared<SerializedTransaction>(ttKind);
mTransaction = boost::make_shared<SerializedTransaction> (ttKind);
// Log(lsINFO) << str(boost::format("Transaction: account: %s") % naSourceAccount.humanAccountID());
// Log(lsINFO) << str(boost::format("Transaction: mAccountFrom: %s") % mAccountFrom.humanAccountID());
// Log(lsINFO) << str(boost::format("Transaction: account: %s") % naSourceAccount.humanAccountID());
// Log(lsINFO) << str(boost::format("Transaction: mAccountFrom: %s") % mAccountFrom.humanAccountID());
mTransaction->setSigningPubKey(mFromPubKey);
mTransaction->setSourceAccount(mAccountFrom);
mTransaction->setSequence(uSeq);
mTransaction->setTransactionFee(saFee);
mTransaction->setSigningPubKey (mFromPubKey);
mTransaction->setSourceAccount (mAccountFrom);
mTransaction->setSequence (uSeq);
mTransaction->setTransactionFee (saFee);
if (uSourceTag)
{
mTransaction->makeFieldPresent(sfSourceTag);
mTransaction->setFieldU32(sfSourceTag, uSourceTag);
}
if (uSourceTag)
{
mTransaction->makeFieldPresent (sfSourceTag);
mTransaction->setFieldU32 (sfSourceTag, uSourceTag);
}
}
bool Transaction::sign(const RippleAddress& naAccountPrivate)
bool Transaction::sign (const RippleAddress& naAccountPrivate)
{
bool bResult = true;
bool bResult = true;
if (!naAccountPrivate.isValid())
{
Log(lsWARNING) << "No private key for signing";
bResult = false;
}
getSTransaction()->sign(naAccountPrivate);
if (!naAccountPrivate.isValid ())
{
Log (lsWARNING) << "No private key for signing";
bResult = false;
}
if (bResult)
{
updateID();
}
else
{
mStatus = INCOMPLETE;
}
getSTransaction ()->sign (naAccountPrivate);
return bResult;
if (bResult)
{
updateID ();
}
else
{
mStatus = INCOMPLETE;
}
return bResult;
}
@@ -100,223 +101,300 @@ bool Transaction::sign(const RippleAddress& naAccountPrivate)
// Misc.
//
bool Transaction::checkSign() const
bool Transaction::checkSign () const
{
if (!mFromPubKey.isValid())
{
Log(lsWARNING) << "Transaction has bad source public key";
return false;
}
return mTransaction->checkSign(mFromPubKey);
if (!mFromPubKey.isValid ())
{
Log (lsWARNING) << "Transaction has bad source public key";
return false;
}
return mTransaction->checkSign (mFromPubKey);
}
void Transaction::setStatus(TransStatus ts, uint32 lseq)
void Transaction::setStatus (TransStatus ts, uint32 lseq)
{
mStatus = ts;
mInLedger = lseq;
mStatus = ts;
mInLedger = lseq;
}
void Transaction::save()
void Transaction::save ()
{
if ((mStatus == INVALID) || (mStatus == REMOVED))
return;
if ((mStatus == INVALID) || (mStatus == REMOVED))
return;
char status;
switch (mStatus)
{
case NEW: status = TXN_SQL_NEW; break;
case INCLUDED: status = TXN_SQL_INCLUDED; break;
case CONFLICTED: status = TXN_SQL_CONFLICT; break;
case COMMITTED: status = TXN_SQL_VALIDATED; break;
case HELD: status = TXN_SQL_HELD; break;
default: status = TXN_SQL_UNKNOWN;
}
char status;
Database *db = theApp->getTxnDB()->getDB();
ScopedLock dbLock(theApp->getTxnDB()->getDBLock());
db->executeSQL(mTransaction->getSQLInsertReplaceHeader() + mTransaction->getSQL(getLedger(), status) + ";");
switch (mStatus)
{
case NEW:
status = TXN_SQL_NEW;
break;
case INCLUDED:
status = TXN_SQL_INCLUDED;
break;
case CONFLICTED:
status = TXN_SQL_CONFLICT;
break;
case COMMITTED:
status = TXN_SQL_VALIDATED;
break;
case HELD:
status = TXN_SQL_HELD;
break;
default:
status = TXN_SQL_UNKNOWN;
}
Database* db = theApp->getTxnDB ()->getDB ();
ScopedLock dbLock (theApp->getTxnDB ()->getDBLock ());
db->executeSQL (mTransaction->getSQLInsertReplaceHeader () + mTransaction->getSQL (getLedger (), status) + ";");
}
Transaction::pointer Transaction::transactionFromSQL(Database* db, bool bValidate)
Transaction::pointer Transaction::transactionFromSQL (Database* db, bool bValidate)
{
Serializer rawTxn;
std::string status;
uint32 inLedger;
Serializer rawTxn;
std::string status;
uint32 inLedger;
int txSize = 2048;
rawTxn.resize(txSize);
int txSize = 2048;
rawTxn.resize (txSize);
db->getStr("Status", status);
inLedger = db->getInt("LedgerSeq");
txSize = db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.getLength());
if (txSize > rawTxn.getLength())
{
rawTxn.resize(txSize);
db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.getLength());
}
db->getStr ("Status", status);
inLedger = db->getInt ("LedgerSeq");
txSize = db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ());
rawTxn.resize(txSize);
if (txSize > rawTxn.getLength ())
{
rawTxn.resize (txSize);
db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ());
}
SerializerIterator it(rawTxn);
SerializedTransaction::pointer txn = boost::make_shared<SerializedTransaction>(boost::ref(it));
Transaction::pointer tr = boost::make_shared<Transaction>(txn, bValidate);
rawTxn.resize (txSize);
TransStatus st(INVALID);
switch (status[0])
{
case TXN_SQL_NEW: st = NEW; break;
case TXN_SQL_CONFLICT: st = CONFLICTED; break;
case TXN_SQL_HELD: st = HELD; break;
case TXN_SQL_VALIDATED: st = COMMITTED; break;
case TXN_SQL_INCLUDED: st = INCLUDED; break;
case TXN_SQL_UNKNOWN: break;
default: assert(false);
}
tr->setStatus(st);
tr->setLedger(inLedger);
return tr;
SerializerIterator it (rawTxn);
SerializedTransaction::pointer txn = boost::make_shared<SerializedTransaction> (boost::ref (it));
Transaction::pointer tr = boost::make_shared<Transaction> (txn, bValidate);
TransStatus st (INVALID);
switch (status[0])
{
case TXN_SQL_NEW:
st = NEW;
break;
case TXN_SQL_CONFLICT:
st = CONFLICTED;
break;
case TXN_SQL_HELD:
st = HELD;
break;
case TXN_SQL_VALIDATED:
st = COMMITTED;
break;
case TXN_SQL_INCLUDED:
st = INCLUDED;
break;
case TXN_SQL_UNKNOWN:
break;
default:
assert (false);
}
tr->setStatus (st);
tr->setLedger (inLedger);
return tr;
}
// DAVID: would you rather duplicate this code or keep the lock longer?
Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
Transaction::pointer Transaction::transactionFromSQL (const std::string& sql)
{
Serializer rawTxn;
std::string status;
uint32 inLedger;
Serializer rawTxn;
std::string status;
uint32 inLedger;
int txSize = 2048;
rawTxn.resize(txSize);
int txSize = 2048;
rawTxn.resize (txSize);
{
ScopedLock sl(theApp->getTxnDB()->getDBLock());
Database* db = theApp->getTxnDB()->getDB();
{
ScopedLock sl (theApp->getTxnDB ()->getDBLock ());
Database* db = theApp->getTxnDB ()->getDB ();
if (!db->executeSQL(sql, true) || !db->startIterRows())
return Transaction::pointer();
if (!db->executeSQL (sql, true) || !db->startIterRows ())
return Transaction::pointer ();
db->getStr("Status", status);
inLedger = db->getInt("LedgerSeq");
txSize = db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.getLength());
if (txSize > rawTxn.getLength())
{
rawTxn.resize(txSize);
db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.getLength());
}
db->endIterRows();
}
rawTxn.resize(txSize);
db->getStr ("Status", status);
inLedger = db->getInt ("LedgerSeq");
txSize = db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ());
SerializerIterator it(rawTxn);
SerializedTransaction::pointer txn = boost::make_shared<SerializedTransaction>(boost::ref(it));
Transaction::pointer tr = boost::make_shared<Transaction>(txn, true);
if (txSize > rawTxn.getLength ())
{
rawTxn.resize (txSize);
db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ());
}
TransStatus st(INVALID);
switch (status[0])
{
case TXN_SQL_NEW: st = NEW; break;
case TXN_SQL_CONFLICT: st = CONFLICTED; break;
case TXN_SQL_HELD: st = HELD; break;
case TXN_SQL_VALIDATED: st = COMMITTED; break;
case TXN_SQL_INCLUDED: st = INCLUDED; break;
case TXN_SQL_UNKNOWN: break;
default: assert(false);
}
tr->setStatus(st);
tr->setLedger(inLedger);
return tr;
db->endIterRows ();
}
rawTxn.resize (txSize);
SerializerIterator it (rawTxn);
SerializedTransaction::pointer txn = boost::make_shared<SerializedTransaction> (boost::ref (it));
Transaction::pointer tr = boost::make_shared<Transaction> (txn, true);
TransStatus st (INVALID);
switch (status[0])
{
case TXN_SQL_NEW:
st = NEW;
break;
case TXN_SQL_CONFLICT:
st = CONFLICTED;
break;
case TXN_SQL_HELD:
st = HELD;
break;
case TXN_SQL_VALIDATED:
st = COMMITTED;
break;
case TXN_SQL_INCLUDED:
st = INCLUDED;
break;
case TXN_SQL_UNKNOWN:
break;
default:
assert (false);
}
tr->setStatus (st);
tr->setLedger (inLedger);
return tr;
}
Transaction::pointer Transaction::load(uint256 const& id)
Transaction::pointer Transaction::load (uint256 const& id)
{
std::string sql = "SELECT LedgerSeq,Status,RawTxn FROM Transactions WHERE TransID='";
sql.append(id.GetHex());
sql.append("';");
return transactionFromSQL(sql);
std::string sql = "SELECT LedgerSeq,Status,RawTxn FROM Transactions WHERE TransID='";
sql.append (id.GetHex ());
sql.append ("';");
return transactionFromSQL (sql);
}
bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedgerSeq,
bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::Delta& inMap,
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >& outMap)
{ // convert a straight SHAMap payload difference to a transaction difference table
// return value: true=ledgers are valid, false=a ledger is invalid
SHAMap::Delta::const_iterator it;
for(it = inMap.begin(); it != inMap.end(); ++it)
{
uint256 const& id = it->first;
SHAMapItem::ref first = it->second.first;
SHAMapItem::ref second = it->second.second;
bool Transaction::convertToTransactions (uint32 firstLedgerSeq, uint32 secondLedgerSeq,
bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::Delta& inMap,
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >& outMap)
{
// convert a straight SHAMap payload difference to a transaction difference table
// return value: true=ledgers are valid, false=a ledger is invalid
SHAMap::Delta::const_iterator it;
Transaction::pointer firstTrans, secondTrans;
if (!!first)
{ // transaction in our table
firstTrans = sharedTransaction(first->getData(), checkFirstTransactions);
if ((firstTrans->getStatus() == INVALID) || (firstTrans->getID() != id ))
{
firstTrans->setStatus(INVALID, firstLedgerSeq);
return false;
}
else firstTrans->setStatus(INCLUDED, firstLedgerSeq);
}
for (it = inMap.begin (); it != inMap.end (); ++it)
{
uint256 const& id = it->first;
SHAMapItem::ref first = it->second.first;
SHAMapItem::ref second = it->second.second;
if (!!second)
{ // transaction in other table
secondTrans = sharedTransaction(second->getData(), checkSecondTransactions);
if ((secondTrans->getStatus() == INVALID) || (secondTrans->getID() != id))
{
secondTrans->setStatus(INVALID, secondLedgerSeq);
return false;
}
else secondTrans->setStatus(INCLUDED, secondLedgerSeq);
}
assert(firstTrans || secondTrans);
if(firstTrans && secondTrans && (firstTrans->getStatus() != INVALID) && (secondTrans->getStatus() != INVALID))
return false; // one or the other SHAMap is structurally invalid or a miracle has happened
Transaction::pointer firstTrans, secondTrans;
outMap[id] = std::pair<Transaction::pointer, Transaction::pointer>(firstTrans, secondTrans);
}
return true;
if (!!first)
{
// transaction in our table
firstTrans = sharedTransaction (first->getData (), checkFirstTransactions);
if ((firstTrans->getStatus () == INVALID) || (firstTrans->getID () != id ))
{
firstTrans->setStatus (INVALID, firstLedgerSeq);
return false;
}
else firstTrans->setStatus (INCLUDED, firstLedgerSeq);
}
if (!!second)
{
// transaction in other table
secondTrans = sharedTransaction (second->getData (), checkSecondTransactions);
if ((secondTrans->getStatus () == INVALID) || (secondTrans->getID () != id))
{
secondTrans->setStatus (INVALID, secondLedgerSeq);
return false;
}
else secondTrans->setStatus (INCLUDED, secondLedgerSeq);
}
assert (firstTrans || secondTrans);
if (firstTrans && secondTrans && (firstTrans->getStatus () != INVALID) && (secondTrans->getStatus () != INVALID))
return false; // one or the other SHAMap is structurally invalid or a miracle has happened
outMap[id] = std::pair<Transaction::pointer, Transaction::pointer> (firstTrans, secondTrans);
}
return true;
}
// options 1 to include the date of the transaction
Json::Value Transaction::getJson(int options, bool binary) const
Json::Value Transaction::getJson (int options, bool binary) const
{
Json::Value ret(mTransaction->getJson(0, binary));
Json::Value ret (mTransaction->getJson (0, binary));
if (mInLedger)
{
ret["inLedger"] = mInLedger; // Deprecated.
ret["ledger_index"] = mInLedger;
if (mInLedger)
{
ret["inLedger"] = mInLedger; // Deprecated.
ret["ledger_index"] = mInLedger;
if (options == 1)
{
Ledger::pointer ledger=theApp->getLedgerMaster().getLedgerBySeq(mInLedger);
if (ledger)
ret["date"] = ledger->getCloseTimeNC();
}
}
if (options == 1)
{
Ledger::pointer ledger = theApp->getLedgerMaster ().getLedgerBySeq (mInLedger);
return ret;
if (ledger)
ret["date"] = ledger->getCloseTimeNC ();
}
}
return ret;
}
//
// Obsolete
//
static bool isHex(char j)
static bool isHex (char j)
{
if ((j >= '0') && (j <= '9')) return true;
if ((j >= 'A') && (j <= 'F')) return true;
if ((j >= 'a') && (j <= 'f')) return true;
return false;
if ((j >= '0') && (j <= '9')) return true;
if ((j >= 'A') && (j <= 'F')) return true;
if ((j >= 'a') && (j <= 'f')) return true;
return false;
}
bool Transaction::isHexTxID(const std::string& txid)
bool Transaction::isHexTxID (const std::string& txid)
{
if (txid.size() != 64) return false;
for (int i = 0; i < 64; ++i)
if (!isHex(txid[i])) return false;
return true;
if (txid.size () != 64) return false;
for (int i = 0; i < 64; ++i)
if (!isHex (txid[i])) return false;
return true;
}
// vim:ts=4

View File

@@ -9,113 +9,158 @@ class Database;
enum TransStatus
{
NEW = 0, // just received / generated
INVALID = 1, // no valid signature, insufficient funds
INCLUDED = 2, // added to the current ledger
CONFLICTED = 3, // losing to a conflicting transaction
COMMITTED = 4, // known to be in a ledger
HELD = 5, // not valid now, maybe later
REMOVED = 6, // taken out of a ledger
OBSOLETE = 7, // a compatible transaction has taken precedence
INCOMPLETE = 8 // needs more signatures
NEW = 0, // just received / generated
INVALID = 1, // no valid signature, insufficient funds
INCLUDED = 2, // added to the current ledger
CONFLICTED = 3, // losing to a conflicting transaction
COMMITTED = 4, // known to be in a ledger
HELD = 5, // not valid now, maybe later
REMOVED = 6, // taken out of a ledger
OBSOLETE = 7, // a compatible transaction has taken precedence
INCOMPLETE = 8 // needs more signatures
};
DEFINE_INSTANCE(Transaction);
DEFINE_INSTANCE (Transaction);
// This class is for constructing and examining transactions. Transactions are static so manipulation functions are unnecessary.
class Transaction : public boost::enable_shared_from_this<Transaction>, private IS_INSTANCE(Transaction)
class Transaction : public boost::enable_shared_from_this<Transaction>, private IS_INSTANCE (Transaction)
{
public:
typedef boost::shared_ptr<Transaction> pointer;
typedef const pointer& ref;
typedef boost::shared_ptr<Transaction> pointer;
typedef const pointer& ref;
public:
Transaction (SerializedTransaction::ref st, bool bValidate);
Transaction (SerializedTransaction::ref st, bool bValidate);
static Transaction::pointer sharedTransaction(Blob const& vucTransaction, bool bValidate);
static Transaction::pointer transactionFromSQL(Database* db, bool bValidate);
static Transaction::pointer sharedTransaction (Blob const & vucTransaction, bool bValidate);
static Transaction::pointer transactionFromSQL (Database * db, bool bValidate);
Transaction(
TransactionType ttKind,
const RippleAddress& naPublicKey, // To prove transaction is consistent and authorized.
const RippleAddress& naSourceAccount, // To identify the paying account.
uint32 uSeq, // To order transactions.
const STAmount& saFee, // Transaction fee.
uint32 uSourceTag); // User call back value.
Transaction (
TransactionType ttKind,
const RippleAddress & naPublicKey, // To prove transaction is consistent and authorized.
const RippleAddress & naSourceAccount, // To identify the paying account.
uint32 uSeq, // To order transactions.
const STAmount & saFee, // Transaction fee.
uint32 uSourceTag); // User call back value.
bool sign (const RippleAddress& naAccountPrivate);
bool sign (const RippleAddress & naAccountPrivate);
bool checkSign() const;
void updateID() { mTransactionID=mTransaction->getTransactionID(); }
bool checkSign () const;
SerializedTransaction::ref getSTransaction() { return mTransaction; }
void updateID ()
{
mTransactionID = mTransaction->getTransactionID ();
}
SerializedTransaction::ref getSTransaction ()
{
return mTransaction;
}
uint256 const& getID () const
{
return mTransactionID;
}
const RippleAddress& getFromAccount () const
{
return mAccountFrom;
}
STAmount getAmount () const
{
return mTransaction->getFieldU64 (sfAmount);
}
STAmount getFee () const
{
return mTransaction->getTransactionFee ();
}
uint32 getFromAccountSeq () const
{
return mTransaction->getSequence ();
}
uint32 getSourceTag () const
{
return mTransaction->getFieldU32 (sfSourceTag);
}
uint256 const& getID() const { return mTransactionID; }
const RippleAddress& getFromAccount() const { return mAccountFrom; }
STAmount getAmount() const { return mTransaction->getFieldU64(sfAmount); }
STAmount getFee() const { return mTransaction->getTransactionFee(); }
uint32 getFromAccountSeq() const { return mTransaction->getSequence(); }
uint32 getSourceTag() const { return mTransaction->getFieldU32(sfSourceTag); }
// VFALCO TODO Should this return a const reference?
Blob getSignature() const { return mTransaction->getSignature(); }
LedgerIndex getLedger() const { return mInLedger; }
TransStatus getStatus() const { return mStatus; }
Blob getSignature () const
{
return mTransaction->getSignature ();
}
TER getResult() { return mResult; }
void setResult(TER terResult) { mResult = terResult; }
LedgerIndex getLedger () const
{
return mInLedger;
}
void setStatus(TransStatus status, uint32 ledgerSeq);
void setStatus(TransStatus status) { mStatus=status; }
void setLedger(LedgerIndex ledger) { mInLedger = ledger; }
TransStatus getStatus () const
{
return mStatus;
}
// database functions
void save();
bool operator<(const Transaction&) const;
bool operator>(const Transaction&) const;
bool operator==(const Transaction&) const;
bool operator!=(const Transaction&) const;
bool operator<=(const Transaction&) const;
bool operator>=(const Transaction&) const;
TER getResult ()
{
return mResult;
}
Json::Value getJson(int options, bool binary = false) const;
void setResult (TER terResult)
{
mResult = terResult;
}
static Transaction::pointer load(uint256 const& id);
void setStatus (TransStatus status, uint32 ledgerSeq);
// conversion function
static bool convertToTransactions(uint32 ourLedgerSeq, uint32 otherLedgerSeq,
bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::Delta& inMap,
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >& outMap);
void setStatus (TransStatus status)
{
mStatus = status;
}
static bool isHexTxID(const std::string&);
void setLedger (LedgerIndex ledger)
{
mInLedger = ledger;
}
// database functions
void save ();
bool operator< (const Transaction&) const;
bool operator> (const Transaction&) const;
bool operator== (const Transaction&) const;
bool operator!= (const Transaction&) const;
bool operator<= (const Transaction&) const;
bool operator>= (const Transaction&) const;
Json::Value getJson (int options, bool binary = false) const;
static Transaction::pointer load (uint256 const & id);
// conversion function
static bool convertToTransactions (uint32 ourLedgerSeq, uint32 otherLedgerSeq,
bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::Delta & inMap,
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >& outMap);
static bool isHexTxID (const std::string&);
protected:
static Transaction::pointer transactionFromSQL(const std::string& statement);
static Transaction::pointer transactionFromSQL (const std::string & statement);
private:
uint256 mTransactionID;
RippleAddress mAccountFrom;
RippleAddress mFromPubKey; // Sign transaction with this. mSignPubKey
RippleAddress mSourcePrivate; // Sign transaction with this.
uint256 mTransactionID;
RippleAddress mAccountFrom;
RippleAddress mFromPubKey; // Sign transaction with this. mSignPubKey
RippleAddress mSourcePrivate; // Sign transaction with this.
LedgerIndex mInLedger;
TransStatus mStatus;
TER mResult;
LedgerIndex mInLedger;
TransStatus mStatus;
TER mResult;
SerializedTransaction::pointer mTransaction;
SerializedTransaction::pointer mTransaction;
};
#endif

View File

@@ -3,76 +3,85 @@
// Double check a transaction's metadata to make sure no system invariants were broken
bool TransactionEngine::checkInvariants(TER result, const SerializedTransaction& txn, TransactionEngineParams params)
bool TransactionEngine::checkInvariants (TER result, const SerializedTransaction& txn, TransactionEngineParams params)
{
#if 0
uint32 txnSeq = txn.getFieldU32(sfSequence);
uint32 txnSeq = txn.getFieldU32 (sfSequence);
LedgerEntryAction leaAction;
LedgerEntryAction leaAction;
uint256 srcActId = Ledger::getAccountRootIndex(txn.getFieldAccount(sfAccount));
SLE::pointer origSrcAct = mLedger->getSLE(srcActId);
SLE::pointer newSrcAct = mNodes.getEntry(srcActId, leaAction);
uint256 srcActId = Ledger::getAccountRootIndex (txn.getFieldAccount (sfAccount));
SLE::pointer origSrcAct = mLedger->getSLE (srcActId);
SLE::pointer newSrcAct = mNodes.getEntry (srcActId, leaAction);
if (!newSrcAct || !origSrcAct)
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction created or destroyed its issuing account";
assert(false);
return tefINTERNAL;
}
if (!newSrcAct || !origSrcAct)
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction created or destroyed its issuing account";
assert (false);
return tefINTERNAL;
}
if ((newSrcAct->getFieldU32(sfSequence) != (txnSeq + 1)) ||
(origSrcAct->getFieldU32(sfSequence) != txnSeq))
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction mangles sequence numbers";
WriteLog (lsFATAL, TransactionEngine) << "t:" << txnSeq << " o: " << origSrcAct->getFieldU32(sfSequence)
<< " n: " << newSrcAct->getFieldU32(sfSequence);
assert(false);
return tefINTERNAL;
}
if ((newSrcAct->getFieldU32 (sfSequence) != (txnSeq + 1)) ||
(origSrcAct->getFieldU32 (sfSequence) != txnSeq))
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction mangles sequence numbers";
WriteLog (lsFATAL, TransactionEngine) << "t:" << txnSeq << " o: " << origSrcAct->getFieldU32 (sfSequence)
<< " n: " << newSrcAct->getFieldU32 (sfSequence);
assert (false);
return tefINTERNAL;
}
int64 xrpChange = txn.getFieldAmount(sfFee).getSNValue();
for (LedgerEntrySet::const_iterator it = mNodes.begin(), end = mNodes.end(); it != end; ++it)
{
const LedgerEntrySetEntry& entry = it->second;
if (entry.mAction == taaMODIFY)
{
int64 xrpChange = txn.getFieldAmount (sfFee).getSNValue ();
for (LedgerEntrySet::const_iterator it = mNodes.begin (), end = mNodes.end (); it != end; ++it)
{
const LedgerEntrySetEntry& entry = it->second;
if (entry.mAction == taaMODIFY)
{
#if 0
if (entry.mEntry->getType() == ltRIPPLE_STATE)
{
// if this transaction pushes a ripple state over its limit, make sure it also modifies
// an offer placed by that same user
}
#endif
if (entry.mEntry->getType() == ltACCOUNT_ROOT)
{ // account modified
xrpChange += entry.mEntry->getFieldAmount(sfBalance).getSNValue();
xrpChange -= mLedger->getSLE(it->first)->getFieldAmount(sfBalance).getSNValue();
}
}
else if (entry.mAction == taaCREATE)
{
if (entry.mEntry->getType() == ltRIPPLE_STATE)
{
if (entry.mEntry->getFieldAmount(sfLowLimit).getIssuer() ==
entry.mEntry->getFieldAmount(sfHighLimit).getIssuer())
{
WriteLog (lsFATAL, TransactionEngine) << "Ripple line to self";
assert(false);
return tefINTERNAL;
}
}
if (entry.mEntry->getType() == ltACCOUNT_ROOT) // account created
xrpChange += entry.mEntry->getFieldAmount(sfBalance).getSNValue();
}
}
if (xrpChange != 0)
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction creates/destroys XRP";
assert(false);
return tefINTERNAL;
}
if (entry.mEntry->getType () == ltRIPPLE_STATE)
{
// if this transaction pushes a ripple state over its limit, make sure it also modifies
// an offer placed by that same user
}
#endif
return true;
if (entry.mEntry->getType () == ltACCOUNT_ROOT)
{
// account modified
xrpChange += entry.mEntry->getFieldAmount (sfBalance).getSNValue ();
xrpChange -= mLedger->getSLE (it->first)->getFieldAmount (sfBalance).getSNValue ();
}
}
else if (entry.mAction == taaCREATE)
{
if (entry.mEntry->getType () == ltRIPPLE_STATE)
{
if (entry.mEntry->getFieldAmount (sfLowLimit).getIssuer () ==
entry.mEntry->getFieldAmount (sfHighLimit).getIssuer ())
{
WriteLog (lsFATAL, TransactionEngine) << "Ripple line to self";
assert (false);
return tefINTERNAL;
}
}
if (entry.mEntry->getType () == ltACCOUNT_ROOT) // account created
xrpChange += entry.mEntry->getFieldAmount (sfBalance).getSNValue ();
}
}
if (xrpChange != 0)
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction creates/destroys XRP";
assert (false);
return tefINTERNAL;
}
#endif
return true;
}

View File

@@ -5,201 +5,208 @@
SETUP_LOG (TransactionEngine)
DECLARE_INSTANCE(TransactionEngine);
DECLARE_INSTANCE (TransactionEngine);
void TransactionEngine::txnWrite()
void TransactionEngine::txnWrite ()
{
// Write back the account states
typedef std::map<uint256, LedgerEntrySetEntry>::value_type u256_LES_pair;
BOOST_FOREACH(u256_LES_pair& it, mNodes)
{
SLE::ref sleEntry = it.second.mEntry;
// Write back the account states
typedef std::map<uint256, LedgerEntrySetEntry>::value_type u256_LES_pair;
BOOST_FOREACH (u256_LES_pair & it, mNodes)
{
SLE::ref sleEntry = it.second.mEntry;
switch (it.second.mAction)
{
case taaNONE:
assert(false);
break;
switch (it.second.mAction)
{
case taaNONE:
assert (false);
break;
case taaCACHED:
break;
case taaCACHED:
break;
case taaCREATE:
{
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: taaCREATE: " << sleEntry->getText();
case taaCREATE:
{
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: taaCREATE: " << sleEntry->getText ();
if (mLedger->writeBack(lepCREATE, sleEntry) & lepERROR)
assert(false);
}
break;
if (mLedger->writeBack (lepCREATE, sleEntry) & lepERROR)
assert (false);
}
break;
case taaMODIFY:
{
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: taaMODIFY: " << sleEntry->getText();
case taaMODIFY:
{
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: taaMODIFY: " << sleEntry->getText ();
if (mLedger->writeBack(lepNONE, sleEntry) & lepERROR)
assert(false);
}
break;
if (mLedger->writeBack (lepNONE, sleEntry) & lepERROR)
assert (false);
}
break;
case taaDELETE:
{
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: taaDELETE: " << sleEntry->getText();
case taaDELETE:
{
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: taaDELETE: " << sleEntry->getText ();
if (!mLedger->peekAccountStateMap()->delItem(it.first))
assert(false);
}
break;
}
}
if (!mLedger->peekAccountStateMap ()->delItem (it.first))
assert (false);
}
break;
}
}
}
TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, TransactionEngineParams params,
bool& didApply)
TER TransactionEngine::applyTransaction (const SerializedTransaction& txn, TransactionEngineParams params,
bool& didApply)
{
WriteLog (lsTRACE, TransactionEngine) << "applyTransaction>";
didApply = false;
assert(mLedger);
mNodes.init(mLedger, txn.getTransactionID(), mLedger->getLedgerSeq(), params);
WriteLog (lsTRACE, TransactionEngine) << "applyTransaction>";
didApply = false;
assert (mLedger);
mNodes.init (mLedger, txn.getTransactionID (), mLedger->getLedgerSeq (), params);
#ifdef DEBUG
if (1)
{
Serializer ser;
txn.add(ser);
SerializerIterator sit(ser);
SerializedTransaction s2(sit);
if (!s2.isEquivalent(txn))
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction serdes mismatch";
Json::StyledStreamWriter ssw;
WriteLog (lsINFO, TransactionEngine) << txn.getJson(0);
WriteLog (lsFATAL, TransactionEngine) << s2.getJson(0);
assert(false);
}
}
if (1)
{
Serializer ser;
txn.add (ser);
SerializerIterator sit (ser);
SerializedTransaction s2 (sit);
if (!s2.isEquivalent (txn))
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction serdes mismatch";
Json::StyledStreamWriter ssw;
WriteLog (lsINFO, TransactionEngine) << txn.getJson (0);
WriteLog (lsFATAL, TransactionEngine) << s2.getJson (0);
assert (false);
}
}
#endif
UPTR_T<Transactor> transactor = Transactor::makeTransactor(txn, params, this);
if (transactor.get() != NULL)
{
uint256 txID = txn.getTransactionID();
if (!txID)
{
WriteLog (lsWARNING, TransactionEngine) << "applyTransaction: invalid transaction id";
UPTR_T<Transactor> transactor = Transactor::makeTransactor (txn, params, this);
return temINVALID;
}
if (transactor.get () != NULL)
{
uint256 txID = txn.getTransactionID ();
TER terResult= transactor->apply();
std::string strToken;
std::string strHuman;
if (!txID)
{
WriteLog (lsWARNING, TransactionEngine) << "applyTransaction: invalid transaction id";
transResultInfo(terResult, strToken, strHuman);
return temINVALID;
}
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman;
TER terResult = transactor->apply ();
std::string strToken;
std::string strHuman;
if (isTesSuccess(terResult))
didApply = true;
else if (isTecClaim(terResult) && !isSetBit(params, tapRETRY))
{ // only claim the transaction fee
WriteLog (lsDEBUG, TransactionEngine) << "Reprocessing to only claim fee";
mNodes.clear();
transResultInfo (terResult, strToken, strHuman);
SLE::pointer txnAcct = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(txn.getSourceAccount()));
if (!txnAcct)
terResult = terNO_ACCOUNT;
else
{
uint32 t_seq = txn.getSequence();
uint32 a_seq = txnAcct->getFieldU32(sfSequence);
WriteLog (lsINFO, TransactionEngine) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman;
if (a_seq < t_seq)
terResult = terPRE_SEQ;
else if (a_seq > t_seq)
terResult = tefPAST_SEQ;
else
{
STAmount fee = txn.getTransactionFee();
STAmount balance = txnAcct->getFieldAmount(sfBalance);
if (isTesSuccess (terResult))
didApply = true;
else if (isTecClaim (terResult) && !isSetBit (params, tapRETRY))
{
// only claim the transaction fee
WriteLog (lsDEBUG, TransactionEngine) << "Reprocessing to only claim fee";
mNodes.clear ();
if (balance < fee)
terResult = terINSUF_FEE_B;
else
{
txnAcct->setFieldAmount(sfBalance, balance - fee);
txnAcct->setFieldU32(sfSequence, t_seq + 1);
entryModify(txnAcct);
didApply = true;
}
}
}
}
else
WriteLog (lsDEBUG, TransactionEngine) << "Not applying transaction";
SLE::pointer txnAcct = entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (txn.getSourceAccount ()));
if (didApply)
{
if (!checkInvariants(terResult, txn, params))
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction violates invariants";
WriteLog (lsFATAL, TransactionEngine) << txn.getJson(0);
WriteLog (lsFATAL, TransactionEngine) << transToken(terResult) << ": " << transHuman(terResult);
WriteLog (lsFATAL, TransactionEngine) << mNodes.getJson(0);
didApply = false;
terResult = tefINTERNAL;
}
else
{
// Transaction succeeded fully or (retries are not allowed and the transaction could claim a fee)
Serializer m;
mNodes.calcRawMeta(m, terResult, mTxnSeq++);
if (!txnAcct)
terResult = terNO_ACCOUNT;
else
{
uint32 t_seq = txn.getSequence ();
uint32 a_seq = txnAcct->getFieldU32 (sfSequence);
txnWrite();
if (a_seq < t_seq)
terResult = terPRE_SEQ;
else if (a_seq > t_seq)
terResult = tefPAST_SEQ;
else
{
STAmount fee = txn.getTransactionFee ();
STAmount balance = txnAcct->getFieldAmount (sfBalance);
Serializer s;
txn.add(s);
if (balance < fee)
terResult = terINSUF_FEE_B;
else
{
txnAcct->setFieldAmount (sfBalance, balance - fee);
txnAcct->setFieldU32 (sfSequence, t_seq + 1);
entryModify (txnAcct);
didApply = true;
}
}
}
}
else
WriteLog (lsDEBUG, TransactionEngine) << "Not applying transaction";
if (isSetBit(params, tapOPEN_LEDGER))
{
if (!mLedger->addTransaction(txID, s))
{
WriteLog (lsFATAL, TransactionEngine) << "Tried to add transaction to open ledger that already had it";
assert(false);
throw std::runtime_error("Duplicate transaction applied");
}
}
else
{
if (!mLedger->addTransaction(txID, s, m))
{
WriteLog (lsFATAL, TransactionEngine) << "Tried to add transaction to ledger that already had it";
assert(false);
throw std::runtime_error("Duplicate transaction applied to closed ledger");
}
if (didApply)
{
if (!checkInvariants (terResult, txn, params))
{
WriteLog (lsFATAL, TransactionEngine) << "Transaction violates invariants";
WriteLog (lsFATAL, TransactionEngine) << txn.getJson (0);
WriteLog (lsFATAL, TransactionEngine) << transToken (terResult) << ": " << transHuman (terResult);
WriteLog (lsFATAL, TransactionEngine) << mNodes.getJson (0);
didApply = false;
terResult = tefINTERNAL;
}
else
{
// Transaction succeeded fully or (retries are not allowed and the transaction could claim a fee)
Serializer m;
mNodes.calcRawMeta (m, terResult, mTxnSeq++);
// Charge whatever fee they specified.
STAmount saPaid = txn.getTransactionFee();
mLedger->destroyCoins(saPaid.getNValue());
}
}
}
txnWrite ();
mTxnAccount.reset();
mNodes.clear();
Serializer s;
txn.add (s);
if (!isSetBit(params, tapOPEN_LEDGER) && isTemMalformed(terResult))
{
// XXX Malformed or failed transaction in closed ledger must bow out.
}
if (isSetBit (params, tapOPEN_LEDGER))
{
if (!mLedger->addTransaction (txID, s))
{
WriteLog (lsFATAL, TransactionEngine) << "Tried to add transaction to open ledger that already had it";
assert (false);
throw std::runtime_error ("Duplicate transaction applied");
}
}
else
{
if (!mLedger->addTransaction (txID, s, m))
{
WriteLog (lsFATAL, TransactionEngine) << "Tried to add transaction to ledger that already had it";
assert (false);
throw std::runtime_error ("Duplicate transaction applied to closed ledger");
}
return terResult;
}
else
{
WriteLog (lsWARNING, TransactionEngine) << "applyTransaction: Invalid transaction: unknown transaction type";
return temUNKNOWN;
}
// Charge whatever fee they specified.
STAmount saPaid = txn.getTransactionFee ();
mLedger->destroyCoins (saPaid.getNValue ());
}
}
}
mTxnAccount.reset ();
mNodes.clear ();
if (!isSetBit (params, tapOPEN_LEDGER) && isTemMalformed (terResult))
{
// XXX Malformed or failed transaction in closed ledger must bow out.
}
return terResult;
}
else
{
WriteLog (lsWARNING, TransactionEngine) << "applyTransaction: Invalid transaction: unknown transaction type";
return temUNKNOWN;
}
}
// vim:ts=4

View File

@@ -1,67 +1,95 @@
#ifndef __TRANSACTIONENGINE__
#define __TRANSACTIONENGINE__
DEFINE_INSTANCE(TransactionEngine);
DEFINE_INSTANCE (TransactionEngine);
// A TransactionEngine applies serialized transactions to a ledger
// It can also, verify signatures, verify fees, and give rejection reasons
// One instance per ledger.
// Only one transaction applied at a time.
class TransactionEngine : private IS_INSTANCE(TransactionEngine)
class TransactionEngine : private IS_INSTANCE (TransactionEngine)
{
private:
LedgerEntrySet mNodes;
LedgerEntrySet mNodes;
TER setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator);
TER checkSig(const SerializedTransaction& txn);
TER setAuthorized (const SerializedTransaction & txn, bool bMustSetGenerator);
TER checkSig (const SerializedTransaction & txn);
TER takeOffers(
bool bPassive,
uint256 const& uBookBase,
const uint160& uTakerAccountID,
SLE::ref sleTakerAccount,
const STAmount& saTakerPays,
const STAmount& saTakerGets,
STAmount& saTakerPaid,
STAmount& saTakerGot);
TER takeOffers (
bool bPassive,
uint256 const & uBookBase,
const uint160 & uTakerAccountID,
SLE::ref sleTakerAccount,
const STAmount & saTakerPays,
const STAmount & saTakerGets,
STAmount & saTakerPaid,
STAmount & saTakerGot);
protected:
Ledger::pointer mLedger;
int mTxnSeq;
Ledger::pointer mLedger;
int mTxnSeq;
uint160 mTxnAccountID;
SLE::pointer mTxnAccount;
uint160 mTxnAccountID;
SLE::pointer mTxnAccount;
void txnWrite();
void txnWrite ();
public:
typedef boost::shared_ptr<TransactionEngine> pointer;
typedef boost::shared_ptr<TransactionEngine> pointer;
TransactionEngine() : mTxnSeq(0) { ; }
TransactionEngine(Ledger::ref ledger) : mLedger(ledger), mTxnSeq(0) { assert(mLedger); }
TransactionEngine () : mTxnSeq (0)
{
;
}
TransactionEngine (Ledger::ref ledger) : mLedger (ledger), mTxnSeq (0)
{
assert (mLedger);
}
LedgerEntrySet& getNodes() { return mNodes; }
Ledger::ref getLedger() { return mLedger; }
void setLedger(Ledger::ref ledger) { assert(ledger); mLedger = ledger; }
LedgerEntrySet& getNodes ()
{
return mNodes;
}
Ledger::ref getLedger ()
{
return mLedger;
}
void setLedger (Ledger::ref ledger)
{
assert (ledger);
mLedger = ledger;
}
SLE::pointer entryCreate(LedgerEntryType type, uint256 const& index) { return mNodes.entryCreate(type, index); }
SLE::pointer entryCache(LedgerEntryType type, uint256 const& index) { return mNodes.entryCache(type, index); }
void entryDelete(SLE::ref sleEntry) { mNodes.entryDelete(sleEntry); }
void entryModify(SLE::ref sleEntry) { mNodes.entryModify(sleEntry); }
SLE::pointer entryCreate (LedgerEntryType type, uint256 const & index)
{
return mNodes.entryCreate (type, index);
}
SLE::pointer entryCache (LedgerEntryType type, uint256 const & index)
{
return mNodes.entryCache (type, index);
}
void entryDelete (SLE::ref sleEntry)
{
mNodes.entryDelete (sleEntry);
}
void entryModify (SLE::ref sleEntry)
{
mNodes.entryModify (sleEntry);
}
TER applyTransaction(const SerializedTransaction&, TransactionEngineParams, bool& didApply);
bool checkInvariants(TER result, const SerializedTransaction& txn, TransactionEngineParams params);
TER applyTransaction (const SerializedTransaction&, TransactionEngineParams, bool & didApply);
bool checkInvariants (TER result, const SerializedTransaction & txn, TransactionEngineParams params);
};
inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
inline TransactionEngineParams operator| (const TransactionEngineParams& l1, const TransactionEngineParams& l2)
{
return static_cast<TransactionEngineParams>(static_cast<int>(l1) | static_cast<int>(l2));
return static_cast<TransactionEngineParams> (static_cast<int> (l1) | static_cast<int> (l2));
}
inline TransactionEngineParams operator&(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
inline TransactionEngineParams operator& (const TransactionEngineParams& l1, const TransactionEngineParams& l2)
{
return static_cast<TransactionEngineParams>(static_cast<int>(l1) & static_cast<int>(l2));
return static_cast<TransactionEngineParams> (static_cast<int> (l1) & static_cast<int> (l2));
}
#endif

View File

@@ -7,82 +7,87 @@
#define CACHED_TRANSACTION_AGE 1800
#endif
TransactionMaster::TransactionMaster() : mCache("TransactionCache", CACHED_TRANSACTION_NUM, CACHED_TRANSACTION_AGE)
TransactionMaster::TransactionMaster () : mCache ("TransactionCache", CACHED_TRANSACTION_NUM, CACHED_TRANSACTION_AGE)
{
;
;
}
bool TransactionMaster::inLedger(uint256 const& hash, uint32 ledger)
bool TransactionMaster::inLedger (uint256 const& hash, uint32 ledger)
{
Transaction::pointer txn = mCache.fetch(hash);
if (!txn)
return false;
txn->setStatus(COMMITTED, ledger);
return true;
Transaction::pointer txn = mCache.fetch (hash);
if (!txn)
return false;
txn->setStatus (COMMITTED, ledger);
return true;
}
Transaction::pointer TransactionMaster::fetch(uint256 const& txnID, bool checkDisk)
Transaction::pointer TransactionMaster::fetch (uint256 const& txnID, bool checkDisk)
{
Transaction::pointer txn = mCache.fetch(txnID);
if (!checkDisk || txn)
return txn;
Transaction::pointer txn = mCache.fetch (txnID);
txn = Transaction::load(txnID);
if (!txn)
return txn;
if (!checkDisk || txn)
return txn;
mCache.canonicalize(txnID, txn);
txn = Transaction::load (txnID);
return txn;
if (!txn)
return txn;
mCache.canonicalize (txnID, txn);
return txn;
}
SerializedTransaction::pointer TransactionMaster::fetch(SHAMapItem::ref item, SHAMapTreeNode::TNType type,
bool checkDisk, uint32 uCommitLedger)
SerializedTransaction::pointer TransactionMaster::fetch (SHAMapItem::ref item, SHAMapTreeNode::TNType type,
bool checkDisk, uint32 uCommitLedger)
{
SerializedTransaction::pointer txn;
Transaction::pointer iTx = theApp->getMasterTransaction().fetch(item->getTag(), false);
SerializedTransaction::pointer txn;
Transaction::pointer iTx = theApp->getMasterTransaction ().fetch (item->getTag (), false);
if (!iTx)
{
if (!iTx)
{
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
{
SerializerIterator sit(item->peekSerializer());
txn = boost::make_shared<SerializedTransaction>(boost::ref(sit));
}
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
{
Serializer s;
int length;
item->peekSerializer().getVL(s.modData(), 0, length);
SerializerIterator sit(s);
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
{
SerializerIterator sit (item->peekSerializer ());
txn = boost::make_shared<SerializedTransaction> (boost::ref (sit));
}
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
{
Serializer s;
int length;
item->peekSerializer ().getVL (s.modData (), 0, length);
SerializerIterator sit (s);
txn = boost::make_shared<SerializedTransaction>(boost::ref(sit));
}
}
else
{
if (uCommitLedger)
iTx->setStatus(COMMITTED, uCommitLedger);
txn = boost::make_shared<SerializedTransaction> (boost::ref (sit));
}
}
else
{
if (uCommitLedger)
iTx->setStatus (COMMITTED, uCommitLedger);
txn = iTx->getSTransaction();
}
txn = iTx->getSTransaction ();
}
return txn;
return txn;
}
bool TransactionMaster::canonicalize(Transaction::pointer& txn, bool may_be_new)
bool TransactionMaster::canonicalize (Transaction::pointer& txn, bool may_be_new)
{
uint256 tid = txn->getID();
if (!tid)
return false;
uint256 tid = txn->getID ();
if (mCache.canonicalize(tid, txn))
return true;
if (!tid)
return false;
if (may_be_new)
txn->save();
if (mCache.canonicalize (tid, txn))
return true;
return false;
if (may_be_new)
txn->save ();
return false;
}
// vim:ts=4

View File

@@ -8,19 +8,22 @@
class TransactionMaster
{
public:
TransactionMaster();
TransactionMaster ();
Transaction::pointer fetch(uint256 const& , bool checkDisk);
SerializedTransaction::pointer fetch(SHAMapItem::ref item, SHAMapTreeNode:: TNType type,
bool checkDisk, uint32 uCommitLedger);
Transaction::pointer fetch (uint256 const& , bool checkDisk);
SerializedTransaction::pointer fetch (SHAMapItem::ref item, SHAMapTreeNode:: TNType type,
bool checkDisk, uint32 uCommitLedger);
// return value: true = we had the transaction already
bool inLedger(uint256 const& hash, uint32 ledger);
bool canonicalize(Transaction::pointer& txn, bool maybeNew);
void sweep(void) { mCache.sweep(); }
// return value: true = we had the transaction already
bool inLedger (uint256 const& hash, uint32 ledger);
bool canonicalize (Transaction::pointer& txn, bool maybeNew);
void sweep (void)
{
mCache.sweep ();
}
private:
TaggedCache <uint256, Transaction, UptimeTimerAdapter> mCache;
TaggedCache <uint256, Transaction, UptimeTimerAdapter> mCache;
};
#endif

View File

@@ -3,195 +3,209 @@
SETUP_LOG (TransactionMetaSet)
TransactionMetaSet::TransactionMetaSet(uint256 const& txid, uint32 ledger, Blob const& vec) :
mTransactionID(txid), mLedger(ledger), mNodes(sfAffectedNodes, 32)
TransactionMetaSet::TransactionMetaSet (uint256 const& txid, uint32 ledger, Blob const& vec) :
mTransactionID (txid), mLedger (ledger), mNodes (sfAffectedNodes, 32)
{
Serializer s(vec);
SerializerIterator sit(s);
Serializer s (vec);
SerializerIterator sit (s);
UPTR_T<SerializedType> pobj = STObject::deserialize(sit, sfAffectedNodes);
STObject *obj = static_cast<STObject*>(pobj.get());
if (!obj)
throw std::runtime_error("bad metadata");
UPTR_T<SerializedType> pobj = STObject::deserialize (sit, sfAffectedNodes);
STObject* obj = static_cast<STObject*> (pobj.get ());
mResult = obj->getFieldU8(sfTransactionResult);
mIndex = obj->getFieldU32(sfTransactionIndex);
mNodes = * dynamic_cast<STArray*>(&obj->getField(sfAffectedNodes));
if (!obj)
throw std::runtime_error ("bad metadata");
mResult = obj->getFieldU8 (sfTransactionResult);
mIndex = obj->getFieldU32 (sfTransactionIndex);
mNodes = * dynamic_cast<STArray*> (&obj->getField (sfAffectedNodes));
}
bool TransactionMetaSet::isNodeAffected(uint256 const& node) const
bool TransactionMetaSet::isNodeAffected (uint256 const& node) const
{
BOOST_FOREACH(const STObject& it, mNodes)
if (it.getFieldH256(sfLedgerIndex) == node)
return true;
return false;
BOOST_FOREACH (const STObject & it, mNodes)
if (it.getFieldH256 (sfLedgerIndex) == node)
return true;
return false;
}
void TransactionMetaSet::setAffectedNode(uint256 const& node, SField::ref type, uint16 nodeType)
{ // make sure the node exists and force its type
BOOST_FOREACH(STObject& it, mNodes)
{
if (it.getFieldH256(sfLedgerIndex) == node)
{
it.setFName(type);
it.setFieldU16(sfLedgerEntryType, nodeType);
return;
}
}
void TransactionMetaSet::setAffectedNode (uint256 const& node, SField::ref type, uint16 nodeType)
{
// make sure the node exists and force its type
BOOST_FOREACH (STObject & it, mNodes)
{
if (it.getFieldH256 (sfLedgerIndex) == node)
{
it.setFName (type);
it.setFieldU16 (sfLedgerEntryType, nodeType);
return;
}
}
mNodes.push_back(STObject(type));
STObject& obj = mNodes.back();
mNodes.push_back (STObject (type));
STObject& obj = mNodes.back ();
assert(obj.getFName() == type);
obj.setFieldH256(sfLedgerIndex, node);
obj.setFieldU16(sfLedgerEntryType, nodeType);
assert (obj.getFName () == type);
obj.setFieldH256 (sfLedgerIndex, node);
obj.setFieldU16 (sfLedgerEntryType, nodeType);
}
static void addIfUnique(std::vector<RippleAddress>& vector, const RippleAddress& address)
static void addIfUnique (std::vector<RippleAddress>& vector, const RippleAddress& address)
{
BOOST_FOREACH(const RippleAddress& a, vector)
if (a == address)
return;
vector.push_back(address);
BOOST_FOREACH (const RippleAddress & a, vector)
if (a == address)
return;
vector.push_back (address);
}
std::vector<RippleAddress> TransactionMetaSet::getAffectedAccounts()
std::vector<RippleAddress> TransactionMetaSet::getAffectedAccounts ()
{
std::vector<RippleAddress> accounts;
accounts.reserve(10);
std::vector<RippleAddress> accounts;
accounts.reserve (10);
// This code should match the behavior of the JS method:
// Meta#getAffectedAccounts
BOOST_FOREACH(const STObject& it, mNodes)
{
int index = it.getFieldIndex((it.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields);
if (index != -1)
{
const STObject *inner = dynamic_cast<const STObject*>(&it.peekAtIndex(index));
if (inner)
{
BOOST_FOREACH(const SerializedType& field, inner->peekData())
{
const STAccount* sa = dynamic_cast<const STAccount*>(&field);
if (sa)
addIfUnique(accounts, sa->getValueNCA());
else if ((field.getFName() == sfLowLimit) || (field.getFName() == sfHighLimit) ||
(field.getFName() == sfTakerPays) || (field.getFName() == sfTakerGets))
{
const STAmount* lim = dynamic_cast<const STAmount*>(&field);
if (lim != NULL)
{
uint160 issuer = lim->getIssuer();
if (issuer.isNonZero())
{
RippleAddress na;
na.setAccountID(issuer);
addIfUnique(accounts, na);
}
}
else
{
WriteLog (lsFATAL, TransactionMetaSet) << "limit is not amount " << field.getJson(0);
}
}
}
}
else assert(false);
}
}
// This code should match the behavior of the JS method:
// Meta#getAffectedAccounts
BOOST_FOREACH (const STObject & it, mNodes)
{
int index = it.getFieldIndex ((it.getFName () == sfCreatedNode) ? sfNewFields : sfFinalFields);
return accounts;
if (index != -1)
{
const STObject* inner = dynamic_cast<const STObject*> (&it.peekAtIndex (index));
if (inner)
{
BOOST_FOREACH (const SerializedType & field, inner->peekData ())
{
const STAccount* sa = dynamic_cast<const STAccount*> (&field);
if (sa)
addIfUnique (accounts, sa->getValueNCA ());
else if ((field.getFName () == sfLowLimit) || (field.getFName () == sfHighLimit) ||
(field.getFName () == sfTakerPays) || (field.getFName () == sfTakerGets))
{
const STAmount* lim = dynamic_cast<const STAmount*> (&field);
if (lim != NULL)
{
uint160 issuer = lim->getIssuer ();
if (issuer.isNonZero ())
{
RippleAddress na;
na.setAccountID (issuer);
addIfUnique (accounts, na);
}
}
else
{
WriteLog (lsFATAL, TransactionMetaSet) << "limit is not amount " << field.getJson (0);
}
}
}
}
else assert (false);
}
}
return accounts;
}
STObject& TransactionMetaSet::getAffectedNode(SLE::ref node, SField::ref type)
STObject& TransactionMetaSet::getAffectedNode (SLE::ref node, SField::ref type)
{
assert(&type);
uint256 index = node->getIndex();
BOOST_FOREACH(STObject& it, mNodes)
{
if (it.getFieldH256(sfLedgerIndex) == index)
return it;
}
mNodes.push_back(STObject(type));
STObject& obj = mNodes.back();
assert (&type);
uint256 index = node->getIndex ();
BOOST_FOREACH (STObject & it, mNodes)
{
if (it.getFieldH256 (sfLedgerIndex) == index)
return it;
}
mNodes.push_back (STObject (type));
STObject& obj = mNodes.back ();
assert(obj.getFName() == type);
obj.setFieldH256(sfLedgerIndex, index);
obj.setFieldU16(sfLedgerEntryType, node->getFieldU16(sfLedgerEntryType));
assert (obj.getFName () == type);
obj.setFieldH256 (sfLedgerIndex, index);
obj.setFieldU16 (sfLedgerEntryType, node->getFieldU16 (sfLedgerEntryType));
return obj;
return obj;
}
STObject& TransactionMetaSet::getAffectedNode(uint256 const& node)
STObject& TransactionMetaSet::getAffectedNode (uint256 const& node)
{
BOOST_FOREACH(STObject& it, mNodes)
{
if (it.getFieldH256(sfLedgerIndex) == node)
return it;
}
assert(false);
throw std::runtime_error("Affected node not found");
BOOST_FOREACH (STObject & it, mNodes)
{
if (it.getFieldH256 (sfLedgerIndex) == node)
return it;
}
assert (false);
throw std::runtime_error ("Affected node not found");
}
const STObject& TransactionMetaSet::peekAffectedNode(uint256 const& node) const
const STObject& TransactionMetaSet::peekAffectedNode (uint256 const& node) const
{
BOOST_FOREACH(const STObject& it, mNodes)
if (it.getFieldH256(sfLedgerIndex) == node)
return it;
throw std::runtime_error("Affected node not found");
BOOST_FOREACH (const STObject & it, mNodes)
if (it.getFieldH256 (sfLedgerIndex) == node)
return it;
throw std::runtime_error ("Affected node not found");
}
void TransactionMetaSet::init(uint256 const& id, uint32 ledger)
void TransactionMetaSet::init (uint256 const& id, uint32 ledger)
{
mTransactionID = id;
mLedger = ledger;
mNodes = STArray(sfAffectedNodes, 32);
mTransactionID = id;
mLedger = ledger;
mNodes = STArray (sfAffectedNodes, 32);
}
void TransactionMetaSet::swap(TransactionMetaSet& s)
void TransactionMetaSet::swap (TransactionMetaSet& s)
{
assert((mTransactionID == s.mTransactionID) && (mLedger == s.mLedger));
mNodes.swap(s.mNodes);
assert ((mTransactionID == s.mTransactionID) && (mLedger == s.mLedger));
mNodes.swap (s.mNodes);
}
bool TransactionMetaSet::thread(STObject& node, uint256 const& prevTxID, uint32 prevLgrID)
bool TransactionMetaSet::thread (STObject& node, uint256 const& prevTxID, uint32 prevLgrID)
{
if (node.getFieldIndex(sfPreviousTxnID) == -1)
{
assert(node.getFieldIndex(sfPreviousTxnLgrSeq) == -1);
node.setFieldH256(sfPreviousTxnID, prevTxID);
node.setFieldU32(sfPreviousTxnLgrSeq, prevLgrID);
return true;
}
assert(node.getFieldH256(sfPreviousTxnID) == prevTxID);
assert(node.getFieldU32(sfPreviousTxnLgrSeq) == prevLgrID);
return false;
if (node.getFieldIndex (sfPreviousTxnID) == -1)
{
assert (node.getFieldIndex (sfPreviousTxnLgrSeq) == -1);
node.setFieldH256 (sfPreviousTxnID, prevTxID);
node.setFieldU32 (sfPreviousTxnLgrSeq, prevLgrID);
return true;
}
assert (node.getFieldH256 (sfPreviousTxnID) == prevTxID);
assert (node.getFieldU32 (sfPreviousTxnLgrSeq) == prevLgrID);
return false;
}
static bool compare(const STObject& o1, const STObject& o2)
static bool compare (const STObject& o1, const STObject& o2)
{
return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex);
return o1.getFieldH256 (sfLedgerIndex) < o2.getFieldH256 (sfLedgerIndex);
}
STObject TransactionMetaSet::getAsObject() const
STObject TransactionMetaSet::getAsObject () const
{
STObject metaData(sfTransactionMetaData);
assert(mResult != 255);
metaData.setFieldU8(sfTransactionResult, mResult);
metaData.setFieldU32(sfTransactionIndex, mIndex);
metaData.addObject(mNodes);
return metaData;
STObject metaData (sfTransactionMetaData);
assert (mResult != 255);
metaData.setFieldU8 (sfTransactionResult, mResult);
metaData.setFieldU32 (sfTransactionIndex, mIndex);
metaData.addObject (mNodes);
return metaData;
}
void TransactionMetaSet::addRaw(Serializer& s, TER result, uint32 index)
void TransactionMetaSet::addRaw (Serializer& s, TER result, uint32 index)
{
mResult = static_cast<int>(result);
mIndex = index;
assert((mResult == 0) || ((mResult > 100) && (mResult <= 255)));
mResult = static_cast<int> (result);
mIndex = index;
assert ((mResult == 0) || ((mResult > 100) && (mResult <= 255)));
mNodes.sort(compare);
mNodes.sort (compare);
getAsObject().add(s);
getAsObject ().add (s);
}
// vim:ts=4

View File

@@ -4,48 +4,78 @@
class TransactionMetaSet
{
public:
typedef boost::shared_ptr<TransactionMetaSet> pointer;
typedef const pointer& ref;
typedef boost::shared_ptr<TransactionMetaSet> pointer;
typedef const pointer& ref;
public:
TransactionMetaSet() : mLedger(0), mIndex(static_cast<uint32>(-1)), mResult(255) { ; }
TransactionMetaSet(uint256 const& txID, uint32 ledger, uint32 index) :
mTransactionID(txID), mLedger(ledger), mIndex(static_cast<uint32>(-1)), mResult(255) { ; }
TransactionMetaSet(uint256 const& txID, uint32 ledger, Blob const&);
TransactionMetaSet () : mLedger (0), mIndex (static_cast<uint32> (-1)), mResult (255)
{
;
}
TransactionMetaSet (uint256 const& txID, uint32 ledger, uint32 index) :
mTransactionID (txID), mLedger (ledger), mIndex (static_cast<uint32> (-1)), mResult (255)
{
;
}
TransactionMetaSet (uint256 const& txID, uint32 ledger, Blob const&);
void init(uint256 const& transactionID, uint32 ledger);
void clear() { mNodes.clear(); }
void swap(TransactionMetaSet&);
void init (uint256 const& transactionID, uint32 ledger);
void clear ()
{
mNodes.clear ();
}
void swap (TransactionMetaSet&);
uint256 const& getTxID() { return mTransactionID; }
uint32 getLgrSeq() { return mLedger; }
int getResult() const { return mResult; }
TER getResultTER() const { return static_cast<TER>(mResult); }
uint32 getIndex() const { return mIndex; }
uint256 const& getTxID ()
{
return mTransactionID;
}
uint32 getLgrSeq ()
{
return mLedger;
}
int getResult () const
{
return mResult;
}
TER getResultTER () const
{
return static_cast<TER> (mResult);
}
uint32 getIndex () const
{
return mIndex;
}
bool isNodeAffected(uint256 const& ) const;
void setAffectedNode(uint256 const& , SField::ref type, uint16 nodeType);
STObject& getAffectedNode(SLE::ref node, SField::ref type); // create if needed
STObject& getAffectedNode(uint256 const& );
const STObject& peekAffectedNode(uint256 const& ) const;
std::vector<RippleAddress> getAffectedAccounts();
bool isNodeAffected (uint256 const& ) const;
void setAffectedNode (uint256 const& , SField::ref type, uint16 nodeType);
STObject& getAffectedNode (SLE::ref node, SField::ref type); // create if needed
STObject& getAffectedNode (uint256 const& );
const STObject& peekAffectedNode (uint256 const& ) const;
std::vector<RippleAddress> getAffectedAccounts ();
Json::Value getJson(int p) const { return getAsObject().getJson(p); }
void addRaw(Serializer&, TER, uint32 index);
Json::Value getJson (int p) const
{
return getAsObject ().getJson (p);
}
void addRaw (Serializer&, TER, uint32 index);
STObject getAsObject() const;
STArray& getNodes(){ return(mNodes); }
STObject getAsObject () const;
STArray& getNodes ()
{
return (mNodes);
}
static bool thread(STObject& node, uint256 const& prevTxID, uint32 prevLgrID);
static bool thread (STObject& node, uint256 const& prevTxID, uint32 prevLgrID);
private:
uint256 mTransactionID;
uint32 mLedger;
uint32 mIndex;
int mResult;
uint256 mTransactionID;
uint32 mLedger;
uint32 mIndex;
int mResult;
STArray mNodes;
STArray mNodes;
};
#endif

View File

@@ -1,95 +1,105 @@
void TXQEntry::addCallbacks(const TXQEntry& otherEntry)
void TXQEntry::addCallbacks (const TXQEntry& otherEntry)
{
BOOST_FOREACH(const stCallback& callback, otherEntry.mCallbacks)
mCallbacks.push_back(callback);
BOOST_FOREACH (const stCallback & callback, otherEntry.mCallbacks)
mCallbacks.push_back (callback);
}
void TXQEntry::doCallbacks(TER result)
void TXQEntry::doCallbacks (TER result)
{
BOOST_FOREACH(const stCallback& callback, mCallbacks)
callback(mTxn, result);
BOOST_FOREACH (const stCallback & callback, mCallbacks)
callback (mTxn, result);
}
bool TXQueue::addEntryForSigCheck(TXQEntry::ref entry)
{ // we always dispatch a thread to check the signature
boost::mutex::scoped_lock sl(mLock);
if (!mTxMap.insert(valueType(entry->getID(), entry)).second)
{
if (!entry->mCallbacks.empty())
mTxMap.left.find(entry->getID())->second->addCallbacks(*entry);
return false;
}
return true;
}
bool TXQueue::addEntryForExecution(TXQEntry::ref entry)
bool TXQueue::addEntryForSigCheck (TXQEntry::ref entry)
{
boost::mutex::scoped_lock sl(mLock);
// we always dispatch a thread to check the signature
boost::mutex::scoped_lock sl (mLock);
entry->mSigChecked = true;
if (!mTxMap.insert (valueType (entry->getID (), entry)).second)
{
if (!entry->mCallbacks.empty ())
mTxMap.left.find (entry->getID ())->second->addCallbacks (*entry);
std::pair<mapType::iterator, bool> it = mTxMap.insert(valueType(entry->getID(), entry));
if (!it.second)
{ // There was an existing entry
it.first->right->mSigChecked = true;
if (!entry->mCallbacks.empty())
it.first->right->addCallbacks(*entry);
}
return false;
}
if (mRunning)
return false;
mRunning = true;
return true; // A thread needs to handle this account
return true;
}
TXQEntry::pointer TXQueue::removeEntry(uint256 const& id)
bool TXQueue::addEntryForExecution (TXQEntry::ref entry)
{
TXQEntry::pointer ret;
boost::mutex::scoped_lock sl (mLock);
boost::mutex::scoped_lock sl(mLock);
entry->mSigChecked = true;
mapType::left_map::iterator it = mTxMap.left.find(id);
if (it != mTxMap.left.end())
{
ret = it->second;
mTxMap.left.erase(it);
}
std::pair<mapType::iterator, bool> it = mTxMap.insert (valueType (entry->getID (), entry));
return ret;
if (!it.second)
{
// There was an existing entry
it.first->right->mSigChecked = true;
if (!entry->mCallbacks.empty ())
it.first->right->addCallbacks (*entry);
}
if (mRunning)
return false;
mRunning = true;
return true; // A thread needs to handle this account
}
void TXQueue::getJob(TXQEntry::pointer &job)
TXQEntry::pointer TXQueue::removeEntry (uint256 const& id)
{
boost::mutex::scoped_lock sl(mLock);
assert(mRunning);
TXQEntry::pointer ret;
if (job)
mTxMap.left.erase(job->getID());
boost::mutex::scoped_lock sl (mLock);
mapType::left_map::iterator it = mTxMap.left.begin();
if (it == mTxMap.left.end() || !it->second->mSigChecked)
{
job.reset();
mRunning = false;
}
else
job = it->second;
mapType::left_map::iterator it = mTxMap.left.find (id);
if (it != mTxMap.left.end ())
{
ret = it->second;
mTxMap.left.erase (it);
}
return ret;
}
bool TXQueue::stopProcessing(TXQEntry::ref finishedJob)
{ // returns true if a new thread must be dispatched
boost::mutex::scoped_lock sl(mLock);
assert(mRunning);
void TXQueue::getJob (TXQEntry::pointer& job)
{
boost::mutex::scoped_lock sl (mLock);
assert (mRunning);
mTxMap.left.erase(finishedJob->getID());
if (job)
mTxMap.left.erase (job->getID ());
mapType::left_map::iterator it = mTxMap.left.begin();
if ((it != mTxMap.left.end()) && it->second->mSigChecked)
return true;
mapType::left_map::iterator it = mTxMap.left.begin ();
mRunning = false;
return false;
if (it == mTxMap.left.end () || !it->second->mSigChecked)
{
job.reset ();
mRunning = false;
}
else
job = it->second;
}
bool TXQueue::stopProcessing (TXQEntry::ref finishedJob)
{
// returns true if a new thread must be dispatched
boost::mutex::scoped_lock sl (mLock);
assert (mRunning);
mTxMap.left.erase (finishedJob->getID ());
mapType::left_map::iterator it = mTxMap.left.begin ();
if ((it != mTxMap.left.end ()) && it->second->mSigChecked)
return true;
mRunning = false;
return false;
}

View File

@@ -17,57 +17,75 @@ class TXQeueue;
class TXQEntry
{
public:
typedef boost::shared_ptr<TXQEntry> pointer;
typedef const boost::shared_ptr<TXQEntry>& ref;
typedef boost::shared_ptr<TXQEntry> pointer;
typedef const boost::shared_ptr<TXQEntry>& ref;
typedef FUNCTION_TYPE<void (Transaction::pointer, TER)> stCallback; // must complete immediately
public:
TXQEntry(Transaction::ref tx, bool sigChecked) : mTxn(tx), mSigChecked(sigChecked) { ; }
TXQEntry() : mSigChecked(false) { ; }
TXQEntry (Transaction::ref tx, bool sigChecked) : mTxn (tx), mSigChecked (sigChecked)
{
;
}
TXQEntry () : mSigChecked (false)
{
;
}
Transaction::ref getTransaction() const { return mTxn; }
bool getSigChecked() const { return mSigChecked; }
uint256 const& getID() const { return mTxn->getID(); }
Transaction::ref getTransaction () const
{
return mTxn;
}
bool getSigChecked () const
{
return mSigChecked;
}
uint256 const& getID () const
{
return mTxn->getID ();
}
void doCallbacks(TER);
void doCallbacks (TER);
private:
friend class TXQueue;
friend class TXQueue;
Transaction::pointer mTxn;
bool mSigChecked;
std::list<stCallback> mCallbacks;
Transaction::pointer mTxn;
bool mSigChecked;
std::list<stCallback> mCallbacks;
void addCallbacks(const TXQEntry& otherEntry);
void addCallbacks (const TXQEntry& otherEntry);
};
class TXQueue
{
public:
TXQueue() : mRunning(false) { ; }
TXQueue () : mRunning (false)
{
;
}
// Return: true = must dispatch signature checker thread
bool addEntryForSigCheck(TXQEntry::ref);
// Return: true = must dispatch signature checker thread
bool addEntryForSigCheck (TXQEntry::ref);
// Call only if signature is okay. Returns true if new account, must dispatch
bool addEntryForExecution(TXQEntry::ref);
// Call only if signature is okay. Returns true if new account, must dispatch
bool addEntryForExecution (TXQEntry::ref);
// Call if signature is bad (returns entry so you can run its callbacks)
TXQEntry::pointer removeEntry(uint256 const& txID);
// Call if signature is bad (returns entry so you can run its callbacks)
TXQEntry::pointer removeEntry (uint256 const& txID);
// Transaction execution interface
void getJob(TXQEntry::pointer&);
bool stopProcessing(TXQEntry::ref finishedJob);
// Transaction execution interface
void getJob (TXQEntry::pointer&);
bool stopProcessing (TXQEntry::ref finishedJob);
private:
typedef boost::bimaps::unordered_set_of<uint256> leftType;
typedef boost::bimaps::list_of<TXQEntry::pointer> rightType;
typedef boost::bimap<leftType, rightType> mapType;
typedef mapType::value_type valueType;
typedef boost::bimaps::unordered_set_of<uint256> leftType;
typedef boost::bimaps::list_of<TXQEntry::pointer> rightType;
typedef boost::bimap<leftType, rightType> mapType;
typedef mapType::value_type valueType;
mapType mTxMap;
bool mRunning;
boost::mutex mLock;
mapType mTxMap;
bool mRunning;
boost::mutex mLock;
};
#endif

View File

@@ -1,233 +1,247 @@
SETUP_LOG (Transactor)
UPTR_T<Transactor> Transactor::makeTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine)
UPTR_T<Transactor> Transactor::makeTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine)
{
switch(txn.getTxnType())
{
case ttPAYMENT:
return UPTR_T<Transactor>(new PaymentTransactor(txn, params, engine));
case ttACCOUNT_SET:
return UPTR_T<Transactor>(new AccountSetTransactor(txn, params, engine));
case ttREGULAR_KEY_SET:
return UPTR_T<Transactor>(new RegularKeySetTransactor(txn, params, engine));
case ttTRUST_SET:
return UPTR_T<Transactor>(new TrustSetTransactor(txn, params, engine));
case ttOFFER_CREATE:
return UPTR_T<Transactor>(new OfferCreateTransactor(txn, params, engine));
case ttOFFER_CANCEL:
return UPTR_T<Transactor>(new OfferCancelTransactor(txn, params, engine));
case ttWALLET_ADD:
return UPTR_T<Transactor>(new WalletAddTransactor(txn, params, engine));
switch (txn.getTxnType ())
{
case ttPAYMENT:
return UPTR_T<Transactor> (new PaymentTransactor (txn, params, engine));
case ttFEATURE:
case ttFEE:
return UPTR_T<Transactor>(new ChangeTransactor(txn, params, engine));
case ttACCOUNT_SET:
return UPTR_T<Transactor> (new AccountSetTransactor (txn, params, engine));
default:
return UPTR_T<Transactor>();
}
case ttREGULAR_KEY_SET:
return UPTR_T<Transactor> (new RegularKeySetTransactor (txn, params, engine));
case ttTRUST_SET:
return UPTR_T<Transactor> (new TrustSetTransactor (txn, params, engine));
case ttOFFER_CREATE:
return UPTR_T<Transactor> (new OfferCreateTransactor (txn, params, engine));
case ttOFFER_CANCEL:
return UPTR_T<Transactor> (new OfferCancelTransactor (txn, params, engine));
case ttWALLET_ADD:
return UPTR_T<Transactor> (new WalletAddTransactor (txn, params, engine));
case ttFEATURE:
case ttFEE:
return UPTR_T<Transactor> (new ChangeTransactor (txn, params, engine));
default:
return UPTR_T<Transactor> ();
}
}
Transactor::Transactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : mTxn(txn), mEngine(engine), mParams(params)
Transactor::Transactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : mTxn (txn), mEngine (engine), mParams (params)
{
mHasAuthKey=false;
mHasAuthKey = false;
}
void Transactor::calculateFee()
void Transactor::calculateFee ()
{
mFeeDue = STAmount(mEngine->getLedger()->scaleFeeLoad(calculateBaseFee(), isSetBit(mParams, tapADMIN)));
mFeeDue = STAmount (mEngine->getLedger ()->scaleFeeLoad (calculateBaseFee (), isSetBit (mParams, tapADMIN)));
}
uint64 Transactor::calculateBaseFee()
uint64 Transactor::calculateBaseFee ()
{
return theConfig.FEE_DEFAULT;
return theConfig.FEE_DEFAULT;
}
TER Transactor::payFee()
TER Transactor::payFee ()
{
STAmount saPaid = mTxn.getTransactionFee();
if (!saPaid.isLegalNet())
return temBAD_AMOUNT;
STAmount saPaid = mTxn.getTransactionFee ();
// Only check fee is sufficient when the ledger is open.
if (isSetBit(mParams, tapOPEN_LEDGER) && saPaid < mFeeDue)
{
WriteLog (lsINFO, Transactor) << boost::str(boost::format("applyTransaction: Insufficient fee paid: %s/%s")
% saPaid.getText()
% mFeeDue.getText());
if (!saPaid.isLegalNet ())
return temBAD_AMOUNT;
return telINSUF_FEE_P;
}
// Only check fee is sufficient when the ledger is open.
if (isSetBit (mParams, tapOPEN_LEDGER) && saPaid < mFeeDue)
{
WriteLog (lsINFO, Transactor) << boost::str (boost::format ("applyTransaction: Insufficient fee paid: %s/%s")
% saPaid.getText ()
% mFeeDue.getText ());
if (saPaid.isNegative() || !saPaid.isNative())
return temBAD_FEE;
return telINSUF_FEE_P;
}
if (!saPaid) return tesSUCCESS;
if (saPaid.isNegative () || !saPaid.isNative ())
return temBAD_FEE;
// Deduct the fee, so it's not available during the transaction.
// Will only write the account back, if the transaction succeeds.
if (mSourceBalance < saPaid)
{
WriteLog (lsINFO, Transactor)
<< boost::str(boost::format("applyTransaction: Delay: insufficient balance: balance=%s paid=%s")
% mSourceBalance.getText()
% saPaid.getText());
if (!saPaid) return tesSUCCESS;
return terINSUF_FEE_B;
}
// Deduct the fee, so it's not available during the transaction.
// Will only write the account back, if the transaction succeeds.
if (mSourceBalance < saPaid)
{
WriteLog (lsINFO, Transactor)
<< boost::str (boost::format ("applyTransaction: Delay: insufficient balance: balance=%s paid=%s")
% mSourceBalance.getText ()
% saPaid.getText ());
mSourceBalance -= saPaid;
mTxnAccount->setFieldAmount(sfBalance, mSourceBalance);
return terINSUF_FEE_B;
}
return tesSUCCESS;
mSourceBalance -= saPaid;
mTxnAccount->setFieldAmount (sfBalance, mSourceBalance);
return tesSUCCESS;
}
TER Transactor::checkSig()
TER Transactor::checkSig ()
{
// Consistency: Check signature
// Verify the transaction's signing public key is the key authorized for signing.
if (mHasAuthKey && mSigningPubKey.getAccountID() == mTxnAccount->getFieldAccount160(sfRegularKey))
{
// Authorized to continue.
nothing();
}
else if (mSigningPubKey.getAccountID() == mTxnAccountID)
{
// Authorized to continue.
nothing();
}
else if (mHasAuthKey)
{
WriteLog (lsINFO, Transactor) << "applyTransaction: Delay: Not authorized to use account.";
// Consistency: Check signature
// Verify the transaction's signing public key is the key authorized for signing.
if (mHasAuthKey && mSigningPubKey.getAccountID () == mTxnAccount->getFieldAccount160 (sfRegularKey))
{
// Authorized to continue.
nothing ();
}
else if (mSigningPubKey.getAccountID () == mTxnAccountID)
{
// Authorized to continue.
nothing ();
}
else if (mHasAuthKey)
{
WriteLog (lsINFO, Transactor) << "applyTransaction: Delay: Not authorized to use account.";
return tefBAD_AUTH;
}
else
{
WriteLog (lsINFO, Transactor) << "applyTransaction: Invalid: Not authorized to use account.";
return tefBAD_AUTH;
}
else
{
WriteLog (lsINFO, Transactor) << "applyTransaction: Invalid: Not authorized to use account.";
return temBAD_AUTH_MASTER;
}
return temBAD_AUTH_MASTER;
}
return tesSUCCESS;
return tesSUCCESS;
}
TER Transactor::checkSeq()
TER Transactor::checkSeq ()
{
uint32 t_seq = mTxn.getSequence();
uint32 a_seq = mTxnAccount->getFieldU32(sfSequence);
uint32 t_seq = mTxn.getSequence ();
uint32 a_seq = mTxnAccount->getFieldU32 (sfSequence);
WriteLog (lsTRACE, Transactor) << "Aseq=" << a_seq << ", Tseq=" << t_seq;
WriteLog (lsTRACE, Transactor) << "Aseq=" << a_seq << ", Tseq=" << t_seq;
if (t_seq != a_seq)
{
if (a_seq < t_seq)
{
WriteLog (lsINFO, Transactor) << "applyTransaction: future sequence number";
if (t_seq != a_seq)
{
if (a_seq < t_seq)
{
WriteLog (lsINFO, Transactor) << "applyTransaction: future sequence number";
return terPRE_SEQ;
}
else
{
uint256 txID = mTxn.getTransactionID();
if (mEngine->getLedger()->hasTransaction(txID))
return tefALREADY;
}
return terPRE_SEQ;
}
else
{
uint256 txID = mTxn.getTransactionID ();
WriteLog (lsWARNING, Transactor) << "applyTransaction: past sequence number";
if (mEngine->getLedger ()->hasTransaction (txID))
return tefALREADY;
}
return tefPAST_SEQ;
}
WriteLog (lsWARNING, Transactor) << "applyTransaction: past sequence number";
if (mTxn.isFieldPresent(sfPreviousTxnID) &&
(mTxnAccount->getFieldH256(sfPreviousTxnID) != mTxn.getFieldH256(sfPreviousTxnID)))
return tefWRONG_PRIOR;
return tefPAST_SEQ;
}
mTxnAccount->setFieldU32(sfSequence, t_seq + 1);
if (mTxn.isFieldPresent (sfPreviousTxnID) &&
(mTxnAccount->getFieldH256 (sfPreviousTxnID) != mTxn.getFieldH256 (sfPreviousTxnID)))
return tefWRONG_PRIOR;
return tesSUCCESS;
mTxnAccount->setFieldU32 (sfSequence, t_seq + 1);
return tesSUCCESS;
}
// check stuff before you bother to lock the ledger
TER Transactor::preCheck()
TER Transactor::preCheck ()
{
mTxnAccountID = mTxn.getSourceAccount().getAccountID();
if (!mTxnAccountID)
{
WriteLog (lsWARNING, Transactor) << "applyTransaction: bad source id";
mTxnAccountID = mTxn.getSourceAccount ().getAccountID ();
return temBAD_SRC_ACCOUNT;
}
if (!mTxnAccountID)
{
WriteLog (lsWARNING, Transactor) << "applyTransaction: bad source id";
// Extract signing key
// Transactions contain a signing key. This allows us to trivially verify a transaction has at least been properly signed
// without going to disk. Each transaction also notes a source account id. This is used to verify that the signing key is
// associated with the account.
// XXX This could be a lot cleaner to prevent unnecessary copying.
mSigningPubKey = RippleAddress::createAccountPublic(mTxn.getSigningPubKey());
return temBAD_SRC_ACCOUNT;
}
// Consistency: really signed.
if (!mTxn.isKnownGood())
{
if (mTxn.isKnownBad() || (!isSetBit(mParams, tapNO_CHECK_SIGN) && !mTxn.checkSign(mSigningPubKey)))
{
mTxn.setBad();
WriteLog (lsWARNING, Transactor) << "applyTransaction: Invalid transaction: bad signature";
return temINVALID;
}
mTxn.setGood();
}
// Extract signing key
// Transactions contain a signing key. This allows us to trivially verify a transaction has at least been properly signed
// without going to disk. Each transaction also notes a source account id. This is used to verify that the signing key is
// associated with the account.
// XXX This could be a lot cleaner to prevent unnecessary copying.
mSigningPubKey = RippleAddress::createAccountPublic (mTxn.getSigningPubKey ());
return tesSUCCESS;
// Consistency: really signed.
if (!mTxn.isKnownGood ())
{
if (mTxn.isKnownBad () || (!isSetBit (mParams, tapNO_CHECK_SIGN) && !mTxn.checkSign (mSigningPubKey)))
{
mTxn.setBad ();
WriteLog (lsWARNING, Transactor) << "applyTransaction: Invalid transaction: bad signature";
return temINVALID;
}
mTxn.setGood ();
}
return tesSUCCESS;
}
TER Transactor::apply()
TER Transactor::apply ()
{
TER terResult = tesSUCCESS;
terResult=preCheck();
if(terResult != tesSUCCESS) return(terResult);
TER terResult = tesSUCCESS;
terResult = preCheck ();
calculateFee();
if (terResult != tesSUCCESS) return (terResult);
boost::recursive_mutex::scoped_lock sl(mEngine->getLedger()->mLock);
calculateFee ();
mTxnAccount = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(mTxnAccountID));
boost::recursive_mutex::scoped_lock sl (mEngine->getLedger ()->mLock);
// Find source account
// If are only forwarding, due to resource limitations, we might verifying only some transactions, this would be probabilistic.
mTxnAccount = mEngine->entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (mTxnAccountID));
if (!mTxnAccount)
{
if (mustHaveValidAccount())
{
WriteLog (lsTRACE, Transactor) << boost::str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") %
mTxn.getSourceAccount().humanAccountID());
// Find source account
// If are only forwarding, due to resource limitations, we might verifying only some transactions, this would be probabilistic.
return terNO_ACCOUNT;
}
}
else
{
mPriorBalance = mTxnAccount->getFieldAmount(sfBalance);
mSourceBalance = mPriorBalance;
mHasAuthKey = mTxnAccount->isFieldPresent(sfRegularKey);
}
if (!mTxnAccount)
{
if (mustHaveValidAccount ())
{
WriteLog (lsTRACE, Transactor) << boost::str (boost::format ("applyTransaction: Delay transaction: source account does not exist: %s") %
mTxn.getSourceAccount ().humanAccountID ());
terResult = checkSeq();
if (terResult != tesSUCCESS) return(terResult);
return terNO_ACCOUNT;
}
}
else
{
mPriorBalance = mTxnAccount->getFieldAmount (sfBalance);
mSourceBalance = mPriorBalance;
mHasAuthKey = mTxnAccount->isFieldPresent (sfRegularKey);
}
terResult = payFee();
if (terResult != tesSUCCESS) return(terResult);
terResult = checkSeq ();
terResult = checkSig();
if (terResult != tesSUCCESS) return(terResult);
if (terResult != tesSUCCESS) return (terResult);
if (mTxnAccount)
mEngine->entryModify(mTxnAccount);
terResult = payFee ();
return doApply();
if (terResult != tesSUCCESS) return (terResult);
terResult = checkSig ();
if (terResult != tesSUCCESS) return (terResult);
if (mTxnAccount)
mEngine->entryModify (mTxnAccount);
return doApply ();
}
// vim:ts=4

View File

@@ -6,40 +6,43 @@
class Transactor
{
public:
typedef boost::shared_ptr<Transactor> pointer;
typedef boost::shared_ptr<Transactor> pointer;
static UPTR_T<Transactor> makeTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine);
static UPTR_T<Transactor> makeTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine);
TER apply();
TER apply ();
protected:
const SerializedTransaction& mTxn;
TransactionEngine* mEngine;
TransactionEngineParams mParams;
const SerializedTransaction& mTxn;
TransactionEngine* mEngine;
TransactionEngineParams mParams;
uint160 mTxnAccountID;
STAmount mFeeDue;
STAmount mPriorBalance; // Balance before fees.
STAmount mSourceBalance; // Balance after fees.
SLE::pointer mTxnAccount;
bool mHasAuthKey;
RippleAddress mSigningPubKey;
uint160 mTxnAccountID;
STAmount mFeeDue;
STAmount mPriorBalance; // Balance before fees.
STAmount mSourceBalance; // Balance after fees.
SLE::pointer mTxnAccount;
bool mHasAuthKey;
RippleAddress mSigningPubKey;
virtual TER preCheck();
virtual TER checkSeq();
virtual TER payFee();
virtual TER preCheck ();
virtual TER checkSeq ();
virtual TER payFee ();
void calculateFee();
void calculateFee ();
// Returns the fee, not scaled for load (Should be in fee units. FIXME)
virtual uint64 calculateBaseFee();
// Returns the fee, not scaled for load (Should be in fee units. FIXME)
virtual uint64 calculateBaseFee ();
virtual TER checkSig();
virtual TER doApply()=0;
virtual TER checkSig ();
virtual TER doApply () = 0;
Transactor(const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine);
Transactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine);
virtual bool mustHaveValidAccount() { return true; }
virtual bool mustHaveValidAccount ()
{
return true;
}
};
#endif

View File

@@ -1,329 +1,333 @@
SETUP_LOG (TrustSetTransactor)
TER TrustSetTransactor::doApply()
TER TrustSetTransactor::doApply ()
{
TER terResult = tesSUCCESS;
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet>";
TER terResult = tesSUCCESS;
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet>";
const STAmount saLimitAmount = mTxn.getFieldAmount(sfLimitAmount);
const bool bQualityIn = mTxn.isFieldPresent(sfQualityIn);
const bool bQualityOut = mTxn.isFieldPresent(sfQualityOut);
const uint160 uCurrencyID = saLimitAmount.getCurrency();
uint160 uDstAccountID = saLimitAmount.getIssuer();
const bool bHigh = mTxnAccountID > uDstAccountID; // true, iff current is high account.
uint32 uQualityIn = bQualityIn ? mTxn.getFieldU32(sfQualityIn) : 0;
uint32 uQualityOut = bQualityOut ? mTxn.getFieldU32(sfQualityOut) : 0;
if (!saLimitAmount.isLegalNet())
return temBAD_AMOUNT;
if (bQualityIn && QUALITY_ONE == uQualityIn)
uQualityIn = 0;
const STAmount saLimitAmount = mTxn.getFieldAmount (sfLimitAmount);
const bool bQualityIn = mTxn.isFieldPresent (sfQualityIn);
const bool bQualityOut = mTxn.isFieldPresent (sfQualityOut);
const uint160 uCurrencyID = saLimitAmount.getCurrency ();
uint160 uDstAccountID = saLimitAmount.getIssuer ();
const bool bHigh = mTxnAccountID > uDstAccountID; // true, iff current is high account.
if (bQualityOut && QUALITY_ONE == uQualityOut)
uQualityOut = 0;
const uint32 uTxFlags = mTxn.getFlags();
if (uTxFlags & tfTrustSetMask)
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Invalid flags set.";
uint32 uQualityIn = bQualityIn ? mTxn.getFieldU32 (sfQualityIn) : 0;
uint32 uQualityOut = bQualityOut ? mTxn.getFieldU32 (sfQualityOut) : 0;
return temINVALID_FLAG;
}
if (!saLimitAmount.isLegalNet ())
return temBAD_AMOUNT;
const bool bSetAuth = isSetBit(uTxFlags, tfSetfAuth);
if (bQualityIn && QUALITY_ONE == uQualityIn)
uQualityIn = 0;
if (bSetAuth && !isSetBit(mTxnAccount->getFieldU32(sfFlags), lsfRequireAuth))
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Retry: Auth not required.";
if (bQualityOut && QUALITY_ONE == uQualityOut)
uQualityOut = 0;
return tefNO_AUTH_REQUIRED;
}
if (saLimitAmount.isNative())
{
WriteLog (lsINFO, TrustSetTransactor) << boost::str(boost::format("doTrustSet: Malformed transaction: Native credit limit: %s")
% saLimitAmount.getFullText());
const uint32 uTxFlags = mTxn.getFlags ();
return temBAD_LIMIT;
}
if (saLimitAmount.isNegative())
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Negative credit limit.";
return temBAD_LIMIT;
}
if (uTxFlags & tfTrustSetMask)
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Invalid flags set.";
// Check if destination makes sense.
if (!uDstAccountID || uDstAccountID == ACCOUNT_ONE)
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Destination account not specified.";
return temDST_NEEDED;
}
return temINVALID_FLAG;
}
if (mTxnAccountID == uDstAccountID)
{
SLE::pointer selDelete = mEngine->entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID));
const bool bSetAuth = isSetBit (uTxFlags, tfSetfAuth);
if (selDelete)
{
WriteLog (lsWARNING, TrustSetTransactor) << "doTrustSet: Clearing redundant line.";
if (bSetAuth && !isSetBit (mTxnAccount->getFieldU32 (sfFlags), lsfRequireAuth))
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Retry: Auth not required.";
return mEngine->getNodes().trustDelete(selDelete, mTxnAccountID, uDstAccountID);
}
else
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Can not extend credit to self.";
return temDST_IS_SRC;
}
}
SLE::pointer sleDst = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
if (!sleDst)
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Delay transaction: Destination account does not exist.";
return tecNO_DST;
}
const uint32 uOwnerCount = mTxnAccount->getFieldU32(sfOwnerCount);
// The reserve required to create the line.
const uint64 uReserveCreate = mEngine->getLedger()->getReserve(uOwnerCount + 1);
STAmount saLimitAllow = saLimitAmount;
saLimitAllow.setIssuer(mTxnAccountID);
SLE::pointer sleRippleState = mEngine->entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID));
if (sleRippleState)
{
STAmount saLowBalance;
STAmount saLowLimit;
STAmount saHighBalance;
STAmount saHighLimit;
uint32 uLowQualityIn;
uint32 uLowQualityOut;
uint32 uHighQualityIn;
uint32 uHighQualityOut;
const uint160& uLowAccountID = !bHigh ? mTxnAccountID : uDstAccountID;
const uint160& uHighAccountID = bHigh ? mTxnAccountID : uDstAccountID;
SLE::ref sleLowAccount = !bHigh ? mTxnAccount : sleDst;
SLE::ref sleHighAccount = bHigh ? mTxnAccount : sleDst;
return tefNO_AUTH_REQUIRED;
}
//
// Balances
//
if (saLimitAmount.isNative ())
{
WriteLog (lsINFO, TrustSetTransactor) << boost::str (boost::format ("doTrustSet: Malformed transaction: Native credit limit: %s")
% saLimitAmount.getFullText ());
saLowBalance = sleRippleState->getFieldAmount(sfBalance);
saHighBalance = -saLowBalance;
return temBAD_LIMIT;
}
//
// Limits
//
if (saLimitAmount.isNegative ())
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Negative credit limit.";
sleRippleState->setFieldAmount(!bHigh ? sfLowLimit : sfHighLimit, saLimitAllow);
return temBAD_LIMIT;
}
saLowLimit = !bHigh ? saLimitAllow : sleRippleState->getFieldAmount(sfLowLimit);
saHighLimit = bHigh ? saLimitAllow : sleRippleState->getFieldAmount(sfHighLimit);
// Check if destination makes sense.
if (!uDstAccountID || uDstAccountID == ACCOUNT_ONE)
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Destination account not specified.";
//
// Quality in
//
return temDST_NEEDED;
}
if (!bQualityIn)
{
// Not setting. Just get it.
if (mTxnAccountID == uDstAccountID)
{
SLE::pointer selDelete = mEngine->entryCache (ltRIPPLE_STATE, Ledger::getRippleStateIndex (mTxnAccountID, uDstAccountID, uCurrencyID));
uLowQualityIn = sleRippleState->getFieldU32(sfLowQualityIn);
uHighQualityIn = sleRippleState->getFieldU32(sfHighQualityIn);
}
else if (uQualityIn)
{
// Setting.
if (selDelete)
{
WriteLog (lsWARNING, TrustSetTransactor) << "doTrustSet: Clearing redundant line.";
sleRippleState->setFieldU32(!bHigh ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
return mEngine->getNodes ().trustDelete (selDelete, mTxnAccountID, uDstAccountID);
}
else
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Malformed transaction: Can not extend credit to self.";
uLowQualityIn = !bHigh ? uQualityIn : sleRippleState->getFieldU32(sfLowQualityIn);
uHighQualityIn = bHigh ? uQualityIn : sleRippleState->getFieldU32(sfHighQualityIn);
}
else
{
// Clearing.
return temDST_IS_SRC;
}
}
sleRippleState->makeFieldAbsent(!bHigh ? sfLowQualityIn : sfHighQualityIn);
SLE::pointer sleDst = mEngine->entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uDstAccountID));
uLowQualityIn = !bHigh ? 0 : sleRippleState->getFieldU32(sfLowQualityIn);
uHighQualityIn = bHigh ? 0 : sleRippleState->getFieldU32(sfHighQualityIn);
}
if (!sleDst)
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Delay transaction: Destination account does not exist.";
if (QUALITY_ONE == uLowQualityIn) uLowQualityIn = 0;
if (QUALITY_ONE == uHighQualityIn) uHighQualityIn = 0;
return tecNO_DST;
}
//
// Quality out
//
if (!bQualityOut)
{
// Not setting. Just get it.
uLowQualityOut = sleRippleState->getFieldU32(sfLowQualityOut);
uHighQualityOut = sleRippleState->getFieldU32(sfHighQualityOut);
}
else if (uQualityOut)
{
// Setting.
sleRippleState->setFieldU32(!bHigh ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
uLowQualityOut = !bHigh ? uQualityOut : sleRippleState->getFieldU32(sfLowQualityOut);
uHighQualityOut = bHigh ? uQualityOut : sleRippleState->getFieldU32(sfHighQualityOut);
}
else
{
// Clearing.
sleRippleState->makeFieldAbsent(!bHigh ? sfLowQualityOut : sfHighQualityOut);
uLowQualityOut = !bHigh ? 0 : sleRippleState->getFieldU32(sfLowQualityOut);
uHighQualityOut = bHigh ? 0 : sleRippleState->getFieldU32(sfHighQualityOut);
}
if (QUALITY_ONE == uLowQualityOut) uLowQualityOut = 0;
if (QUALITY_ONE == uHighQualityOut) uHighQualityOut = 0;
const bool bLowReserveSet = uLowQualityIn || uLowQualityOut || !!saLowLimit || saLowBalance.isPositive();
const bool bLowReserveClear = !bLowReserveSet;
const bool bHighReserveSet = uHighQualityIn || uHighQualityOut || !!saHighLimit || saHighBalance.isPositive();
const bool bHighReserveClear = !bHighReserveSet;
const bool bDefault = bLowReserveClear && bHighReserveClear;
const uint32 uFlagsIn = sleRippleState->getFieldU32(sfFlags);
uint32 uFlagsOut = uFlagsIn;
const bool bLowReserved = isSetBit(uFlagsIn, lsfLowReserve);
const bool bHighReserved = isSetBit(uFlagsIn, lsfHighReserve);
bool bReserveIncrease = false;
if (bSetAuth)
{
uFlagsOut |= (bHigh ? lsfHighAuth : lsfLowAuth);
}
if (bLowReserveSet && !bLowReserved)
{
// Set reserve for low account.
mEngine->getNodes().ownerCountAdjust(uLowAccountID, 1, sleLowAccount);
uFlagsOut |= lsfLowReserve;
if (!bHigh)
bReserveIncrease = true;
}
if (bLowReserveClear && bLowReserved)
{
// Clear reserve for low account.
mEngine->getNodes().ownerCountAdjust(uLowAccountID, -1, sleLowAccount);
uFlagsOut &= ~lsfLowReserve;
}
if (bHighReserveSet && !bHighReserved)
{
// Set reserve for high account.
mEngine->getNodes().ownerCountAdjust(uHighAccountID, 1, sleHighAccount);
uFlagsOut |= lsfHighReserve;
if (bHigh)
bReserveIncrease = true;
}
if (bHighReserveClear && bHighReserved)
{
// Clear reserve for high account.
mEngine->getNodes().ownerCountAdjust(uHighAccountID, -1, sleHighAccount);
uFlagsOut &= ~lsfHighReserve;
}
if (uFlagsIn != uFlagsOut)
sleRippleState->setFieldU32(sfFlags, uFlagsOut);
if (bDefault || CURRENCY_BAD == uCurrencyID)
{
// Delete.
terResult = mEngine->getNodes().trustDelete(sleRippleState, uLowAccountID, uHighAccountID);
}
else if (bReserveIncrease
&& mPriorBalance.getNValue() < uReserveCreate) // Reserve is not scaled by load.
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Delay transaction: Insufficent reserve to add trust line.";
// Another transaction could provide XRP to the account and then this transaction would succeed.
terResult = tecINSUF_RESERVE_LINE;
}
else
{
mEngine->entryModify(sleRippleState);
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Modify ripple line";
}
}
// Line does not exist.
else if (!saLimitAmount // Setting default limit.
&& (!bQualityIn || !uQualityIn) // Not setting quality in or setting default quality in.
&& (!bQualityOut || !uQualityOut)) // Not setting quality out or setting default quality out.
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Redundant: Setting non-existent ripple line to defaults.";
return tecNO_LINE_REDUNDANT;
}
else if (mPriorBalance.getNValue() < uReserveCreate) // Reserve is not scaled by load.
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Delay transaction: Line does not exist. Insufficent reserve to create line.";
// Another transaction could create the account and then this transaction would succeed.
terResult = tecNO_LINE_INSUF_RESERVE;
}
else if (CURRENCY_BAD == uCurrencyID)
{
terResult = temBAD_CURRENCY;
}
else
{
STAmount saBalance = STAmount(uCurrencyID, ACCOUNT_ONE); // Zero balance in currency.
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Creating ripple line: "
<< Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID).ToString();
// Create a new ripple line.
terResult = mEngine->getNodes().trustCreate(
bHigh,
mTxnAccountID,
uDstAccountID,
Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID),
mTxnAccount,
bSetAuth,
saBalance,
saLimitAllow, // Limit for who is being charged.
uQualityIn,
uQualityOut);
}
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet<";
return terResult;
const uint32 uOwnerCount = mTxnAccount->getFieldU32 (sfOwnerCount);
// The reserve required to create the line.
const uint64 uReserveCreate = mEngine->getLedger ()->getReserve (uOwnerCount + 1);
STAmount saLimitAllow = saLimitAmount;
saLimitAllow.setIssuer (mTxnAccountID);
SLE::pointer sleRippleState = mEngine->entryCache (ltRIPPLE_STATE, Ledger::getRippleStateIndex (mTxnAccountID, uDstAccountID, uCurrencyID));
if (sleRippleState)
{
STAmount saLowBalance;
STAmount saLowLimit;
STAmount saHighBalance;
STAmount saHighLimit;
uint32 uLowQualityIn;
uint32 uLowQualityOut;
uint32 uHighQualityIn;
uint32 uHighQualityOut;
const uint160& uLowAccountID = !bHigh ? mTxnAccountID : uDstAccountID;
const uint160& uHighAccountID = bHigh ? mTxnAccountID : uDstAccountID;
SLE::ref sleLowAccount = !bHigh ? mTxnAccount : sleDst;
SLE::ref sleHighAccount = bHigh ? mTxnAccount : sleDst;
//
// Balances
//
saLowBalance = sleRippleState->getFieldAmount (sfBalance);
saHighBalance = -saLowBalance;
//
// Limits
//
sleRippleState->setFieldAmount (!bHigh ? sfLowLimit : sfHighLimit, saLimitAllow);
saLowLimit = !bHigh ? saLimitAllow : sleRippleState->getFieldAmount (sfLowLimit);
saHighLimit = bHigh ? saLimitAllow : sleRippleState->getFieldAmount (sfHighLimit);
//
// Quality in
//
if (!bQualityIn)
{
// Not setting. Just get it.
uLowQualityIn = sleRippleState->getFieldU32 (sfLowQualityIn);
uHighQualityIn = sleRippleState->getFieldU32 (sfHighQualityIn);
}
else if (uQualityIn)
{
// Setting.
sleRippleState->setFieldU32 (!bHigh ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
uLowQualityIn = !bHigh ? uQualityIn : sleRippleState->getFieldU32 (sfLowQualityIn);
uHighQualityIn = bHigh ? uQualityIn : sleRippleState->getFieldU32 (sfHighQualityIn);
}
else
{
// Clearing.
sleRippleState->makeFieldAbsent (!bHigh ? sfLowQualityIn : sfHighQualityIn);
uLowQualityIn = !bHigh ? 0 : sleRippleState->getFieldU32 (sfLowQualityIn);
uHighQualityIn = bHigh ? 0 : sleRippleState->getFieldU32 (sfHighQualityIn);
}
if (QUALITY_ONE == uLowQualityIn) uLowQualityIn = 0;
if (QUALITY_ONE == uHighQualityIn) uHighQualityIn = 0;
//
// Quality out
//
if (!bQualityOut)
{
// Not setting. Just get it.
uLowQualityOut = sleRippleState->getFieldU32 (sfLowQualityOut);
uHighQualityOut = sleRippleState->getFieldU32 (sfHighQualityOut);
}
else if (uQualityOut)
{
// Setting.
sleRippleState->setFieldU32 (!bHigh ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
uLowQualityOut = !bHigh ? uQualityOut : sleRippleState->getFieldU32 (sfLowQualityOut);
uHighQualityOut = bHigh ? uQualityOut : sleRippleState->getFieldU32 (sfHighQualityOut);
}
else
{
// Clearing.
sleRippleState->makeFieldAbsent (!bHigh ? sfLowQualityOut : sfHighQualityOut);
uLowQualityOut = !bHigh ? 0 : sleRippleState->getFieldU32 (sfLowQualityOut);
uHighQualityOut = bHigh ? 0 : sleRippleState->getFieldU32 (sfHighQualityOut);
}
if (QUALITY_ONE == uLowQualityOut) uLowQualityOut = 0;
if (QUALITY_ONE == uHighQualityOut) uHighQualityOut = 0;
const bool bLowReserveSet = uLowQualityIn || uLowQualityOut || !!saLowLimit || saLowBalance.isPositive ();
const bool bLowReserveClear = !bLowReserveSet;
const bool bHighReserveSet = uHighQualityIn || uHighQualityOut || !!saHighLimit || saHighBalance.isPositive ();
const bool bHighReserveClear = !bHighReserveSet;
const bool bDefault = bLowReserveClear && bHighReserveClear;
const uint32 uFlagsIn = sleRippleState->getFieldU32 (sfFlags);
uint32 uFlagsOut = uFlagsIn;
const bool bLowReserved = isSetBit (uFlagsIn, lsfLowReserve);
const bool bHighReserved = isSetBit (uFlagsIn, lsfHighReserve);
bool bReserveIncrease = false;
if (bSetAuth)
{
uFlagsOut |= (bHigh ? lsfHighAuth : lsfLowAuth);
}
if (bLowReserveSet && !bLowReserved)
{
// Set reserve for low account.
mEngine->getNodes ().ownerCountAdjust (uLowAccountID, 1, sleLowAccount);
uFlagsOut |= lsfLowReserve;
if (!bHigh)
bReserveIncrease = true;
}
if (bLowReserveClear && bLowReserved)
{
// Clear reserve for low account.
mEngine->getNodes ().ownerCountAdjust (uLowAccountID, -1, sleLowAccount);
uFlagsOut &= ~lsfLowReserve;
}
if (bHighReserveSet && !bHighReserved)
{
// Set reserve for high account.
mEngine->getNodes ().ownerCountAdjust (uHighAccountID, 1, sleHighAccount);
uFlagsOut |= lsfHighReserve;
if (bHigh)
bReserveIncrease = true;
}
if (bHighReserveClear && bHighReserved)
{
// Clear reserve for high account.
mEngine->getNodes ().ownerCountAdjust (uHighAccountID, -1, sleHighAccount);
uFlagsOut &= ~lsfHighReserve;
}
if (uFlagsIn != uFlagsOut)
sleRippleState->setFieldU32 (sfFlags, uFlagsOut);
if (bDefault || CURRENCY_BAD == uCurrencyID)
{
// Delete.
terResult = mEngine->getNodes ().trustDelete (sleRippleState, uLowAccountID, uHighAccountID);
}
else if (bReserveIncrease
&& mPriorBalance.getNValue () < uReserveCreate) // Reserve is not scaled by load.
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Delay transaction: Insufficent reserve to add trust line.";
// Another transaction could provide XRP to the account and then this transaction would succeed.
terResult = tecINSUF_RESERVE_LINE;
}
else
{
mEngine->entryModify (sleRippleState);
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Modify ripple line";
}
}
// Line does not exist.
else if (!saLimitAmount // Setting default limit.
&& (!bQualityIn || !uQualityIn) // Not setting quality in or setting default quality in.
&& (!bQualityOut || !uQualityOut)) // Not setting quality out or setting default quality out.
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Redundant: Setting non-existent ripple line to defaults.";
return tecNO_LINE_REDUNDANT;
}
else if (mPriorBalance.getNValue () < uReserveCreate) // Reserve is not scaled by load.
{
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Delay transaction: Line does not exist. Insufficent reserve to create line.";
// Another transaction could create the account and then this transaction would succeed.
terResult = tecNO_LINE_INSUF_RESERVE;
}
else if (CURRENCY_BAD == uCurrencyID)
{
terResult = temBAD_CURRENCY;
}
else
{
STAmount saBalance = STAmount (uCurrencyID, ACCOUNT_ONE); // Zero balance in currency.
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet: Creating ripple line: "
<< Ledger::getRippleStateIndex (mTxnAccountID, uDstAccountID, uCurrencyID).ToString ();
// Create a new ripple line.
terResult = mEngine->getNodes ().trustCreate (
bHigh,
mTxnAccountID,
uDstAccountID,
Ledger::getRippleStateIndex (mTxnAccountID, uDstAccountID, uCurrencyID),
mTxnAccount,
bSetAuth,
saBalance,
saLimitAllow, // Limit for who is being charged.
uQualityIn,
uQualityOut);
}
WriteLog (lsINFO, TrustSetTransactor) << "doTrustSet<";
return terResult;
}
// vim:ts=4

View File

@@ -6,9 +6,9 @@
class TrustSetTransactor : public Transactor
{
public:
TrustSetTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {}
TER doApply();
TrustSetTransactor (const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine) : Transactor (txn, params, engine) {}
TER doApply ();
};
#endif

View File

@@ -4,27 +4,27 @@
// Versions
//
#define SERVER_VERSION_MAJOR 0
#define SERVER_VERSION_MINOR 9
#define SERVER_VERSION_SUB "-b"
#define SERVER_NAME "Ripple"
#define SERVER_VERSION_MAJOR 0
#define SERVER_VERSION_MINOR 9
#define SERVER_VERSION_SUB "-b"
#define SERVER_NAME "Ripple"
#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 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)
// Version we prefer to speak:
#define PROTO_VERSION_MAJOR 1
#define PROTO_VERSION_MINOR 2
#define PROTO_VERSION_MAJOR 1
#define PROTO_VERSION_MINOR 2
// Version we will speak to:
#define MIN_PROTO_MAJOR 1
#define MIN_PROTO_MINOR 2
#define MIN_PROTO_MAJOR 1
#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)
#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

View File

@@ -5,7 +5,7 @@
#include "../websocketpp/src/sockets/autotls.hpp"
#include "../websocketpp/src/websocketpp.hpp"
DEFINE_INSTANCE(WebSocketConnection);
DEFINE_INSTANCE (WebSocketConnection);
// This is for logging
struct WSConnectionLog;
@@ -17,231 +17,251 @@ class WSServerHandler;
// - Subscriptions
//
template <typename endpoint_type>
class WSConnection : public InfoSub, public IS_INSTANCE(WebSocketConnection),
public boost::enable_shared_from_this< WSConnection<endpoint_type> >
class WSConnection : public InfoSub, public IS_INSTANCE (WebSocketConnection),
public boost::enable_shared_from_this< WSConnection<endpoint_type> >
{
public:
typedef typename endpoint_type::connection_type connection;
typedef typename boost::shared_ptr<connection> connection_ptr;
typedef typename boost::weak_ptr<connection> weak_connection_ptr;
typedef typename endpoint_type::handler::message_ptr message_ptr;
typedef typename endpoint_type::connection_type connection;
typedef typename boost::shared_ptr<connection> connection_ptr;
typedef typename boost::weak_ptr<connection> weak_connection_ptr;
typedef typename endpoint_type::handler::message_ptr message_ptr;
public:
// WSConnection()
// : mHandler((WSServerHandler<websocketpp::WSDOOR_SERVER>*)(NULL)),
// mConnection(connection_ptr()) { ; }
// WSConnection()
// : mHandler((WSServerHandler<websocketpp::WSDOOR_SERVER>*)(NULL)),
// mConnection(connection_ptr()) { ; }
WSConnection(WSServerHandler<endpoint_type>* wshpHandler, const connection_ptr& cpConnection)
: mHandler(wshpHandler), mConnection(cpConnection), mNetwork(theApp->getOPs()),
mRemoteIP(cpConnection->get_socket().lowest_layer().remote_endpoint().address().to_string()),
mLoadSource(mRemoteIP), mPingTimer(cpConnection->get_io_service()), mPinged(false),
mRcvQueueRunning(false), mDead(false)
{
WriteLog (lsDEBUG, WSConnectionLog) << "Websocket connection from " << mRemoteIP;
setPingTimer();
}
WSConnection (WSServerHandler<endpoint_type>* wshpHandler, const connection_ptr& cpConnection)
: mHandler (wshpHandler), mConnection (cpConnection), mNetwork (theApp->getOPs ()),
mRemoteIP (cpConnection->get_socket ().lowest_layer ().remote_endpoint ().address ().to_string ()),
mLoadSource (mRemoteIP), mPingTimer (cpConnection->get_io_service ()), mPinged (false),
mRcvQueueRunning (false), mDead (false)
{
WriteLog (lsDEBUG, WSConnectionLog) << "Websocket connection from " << mRemoteIP;
setPingTimer ();
}
void preDestroy()
{ // sever connection
mPingTimer.cancel();
mConnection.reset();
void preDestroy ()
{
// sever connection
mPingTimer.cancel ();
mConnection.reset ();
boost::recursive_mutex::scoped_lock sl(mRcvQueueLock);
mDead = true;
}
boost::recursive_mutex::scoped_lock sl (mRcvQueueLock);
mDead = true;
}
virtual ~WSConnection() { ; }
virtual ~WSConnection ()
{
;
}
static void destroy(boost::shared_ptr< WSConnection<endpoint_type> >)
{ // Just discards the reference
}
static void destroy (boost::shared_ptr< WSConnection<endpoint_type> >)
{
// Just discards the reference
}
// Implement overridden functions from base class:
void send(const Json::Value& jvObj, bool broadcast)
{
connection_ptr ptr = mConnection.lock();
if (ptr)
mHandler->send(ptr, jvObj, broadcast);
}
// Implement overridden functions from base class:
void send (const Json::Value& jvObj, bool broadcast)
{
connection_ptr ptr = mConnection.lock ();
void send(const Json::Value& jvObj, const std::string& sObj, bool broadcast)
{
connection_ptr ptr = mConnection.lock();
if (ptr)
mHandler->send(ptr, sObj, broadcast);
}
if (ptr)
mHandler->send (ptr, jvObj, broadcast);
}
// Utilities
Json::Value invokeCommand(Json::Value& jvRequest)
{
if (theApp->getLoadManager().shouldCutoff(mLoadSource))
{
void send (const Json::Value& jvObj, const std::string& sObj, bool broadcast)
{
connection_ptr ptr = mConnection.lock ();
if (ptr)
mHandler->send (ptr, sObj, broadcast);
}
// Utilities
Json::Value invokeCommand (Json::Value& jvRequest)
{
if (theApp->getLoadManager ().shouldCutoff (mLoadSource))
{
#if SHOULD_DISCONNECT
// FIXME: Must dispatch to strand
connection_ptr ptr = mConnection.lock();
if (ptr)
ptr->close(websocketpp::close::status::PROTOCOL_ERROR, "overload");
return rpcError(rpcSLOW_DOWN);
// FIXME: Must dispatch to strand
connection_ptr ptr = mConnection.lock ();
if (ptr)
ptr->close (websocketpp::close::status::PROTOCOL_ERROR, "overload");
return rpcError (rpcSLOW_DOWN);
#endif
}
}
if (!jvRequest.isMember("command"))
{
Json::Value jvResult(Json::objectValue);
if (!jvRequest.isMember ("command"))
{
Json::Value jvResult (Json::objectValue);
jvResult["type"] = "response";
jvResult["status"] = "error";
jvResult["error"] = "missingCommand";
jvResult["request"] = jvRequest;
jvResult["type"] = "response";
jvResult["status"] = "error";
jvResult["error"] = "missingCommand";
jvResult["request"] = jvRequest;
if (jvRequest.isMember("id"))
{
jvResult["id"] = jvRequest["id"];
}
if (jvRequest.isMember ("id"))
{
jvResult["id"] = jvRequest["id"];
}
theApp->getLoadManager().adjust(mLoadSource, -5);
return jvResult;
}
theApp->getLoadManager ().adjust (mLoadSource, -5);
return jvResult;
}
int cost = 10;
RPCHandler mRPCHandler(&mNetwork, boost::dynamic_pointer_cast<InfoSub>(this->shared_from_this()));
Json::Value jvResult(Json::objectValue);
int cost = 10;
RPCHandler mRPCHandler (&mNetwork, boost::dynamic_pointer_cast<InfoSub> (this->shared_from_this ()));
Json::Value jvResult (Json::objectValue);
int iRole = mHandler->getPublic()
? RPCHandler::GUEST // Don't check on the public interface.
: iAdminGet(jvRequest, mRemoteIP);
int iRole = mHandler->getPublic ()
? RPCHandler::GUEST // Don't check on the public interface.
: iAdminGet (jvRequest, mRemoteIP);
if (RPCHandler::FORBID == iRole)
{
jvResult["result"] = rpcError(rpcFORBIDDEN);
}
else
{
jvResult["result"] = mRPCHandler.doCommand(jvRequest, iRole, cost);
}
if (RPCHandler::FORBID == iRole)
{
jvResult["result"] = rpcError (rpcFORBIDDEN);
}
else
{
jvResult["result"] = mRPCHandler.doCommand (jvRequest, iRole, cost);
}
if (theApp->getLoadManager().adjust(mLoadSource, -cost) && theApp->getLoadManager().shouldWarn(mLoadSource))
jvResult["warning"] = "load";
if (theApp->getLoadManager ().adjust (mLoadSource, -cost) && theApp->getLoadManager ().shouldWarn (mLoadSource))
jvResult["warning"] = "load";
// Currently we will simply unwrap errors returned by the RPC
// API, in the future maybe we can make the responses
// consistent.
//
// Regularize result. This is duplicate code.
if (jvResult["result"].isMember("error"))
{
jvResult = jvResult["result"];
jvResult["status"] = "error";
jvResult["request"] = jvRequest;
// Currently we will simply unwrap errors returned by the RPC
// API, in the future maybe we can make the responses
// consistent.
//
// Regularize result. This is duplicate code.
if (jvResult["result"].isMember ("error"))
{
jvResult = jvResult["result"];
jvResult["status"] = "error";
jvResult["request"] = jvRequest;
} else {
jvResult["status"] = "success";
}
}
else
{
jvResult["status"] = "success";
}
if (jvRequest.isMember("id"))
{
jvResult["id"] = jvRequest["id"];
}
if (jvRequest.isMember ("id"))
{
jvResult["id"] = jvRequest["id"];
}
jvResult["type"] = "response";
jvResult["type"] = "response";
return jvResult;
}
return jvResult;
}
bool onPingTimer(std::string&)
{
bool onPingTimer (std::string&)
{
#ifdef DISCONNECT_ON_WEBSOCKET_PING_TIMEOUTS
if (mPinged)
return true; // causes connection to close
if (mPinged)
return true; // causes connection to close
#endif
mPinged = true;
setPingTimer();
return false; // causes ping to be sent
}
mPinged = true;
setPingTimer ();
return false; // causes ping to be sent
}
void onPong(const std::string&)
{
mPinged = false;
}
void onPong (const std::string&)
{
mPinged = false;
}
static void pingTimer(weak_connection_ptr c, WSServerHandler<endpoint_type>* h, const boost::system::error_code& e)
{
if (e)
return;
static void pingTimer (weak_connection_ptr c, WSServerHandler<endpoint_type>* h, const boost::system::error_code& e)
{
if (e)
return;
connection_ptr ptr = c.lock();
if (ptr)
h->pingTimer(ptr);
}
connection_ptr ptr = c.lock ();
void setPingTimer()
{
connection_ptr ptr = mConnection.lock();
if (ptr)
{
mPingTimer.expires_from_now(boost::posix_time::seconds(theConfig.WEBSOCKET_PING_FREQ));
mPingTimer.async_wait(ptr->get_strand().wrap(boost::bind(
&WSConnection<endpoint_type>::pingTimer, mConnection, mHandler, boost::asio::placeholders::error)));
}
}
if (ptr)
h->pingTimer (ptr);
}
void rcvMessage(message_ptr msg, bool& msgRejected, bool& runQueue)
{
boost::recursive_mutex::scoped_lock sl(mRcvQueueLock);
if (mDead)
{
msgRejected = false;
runQueue = false;
return;
}
if (mDead || (mRcvQueue.size() >= 1000))
{
msgRejected = !mDead;
runQueue = false;
}
else
{
msgRejected = false;
mRcvQueue.push(msg);
if (mRcvQueueRunning)
runQueue = false;
else
{
runQueue = true;
mRcvQueueRunning = true;
}
}
}
void setPingTimer ()
{
connection_ptr ptr = mConnection.lock ();
message_ptr getMessage()
{
boost::recursive_mutex::scoped_lock sl(mRcvQueueLock);
if (mDead || mRcvQueue.empty())
{
mRcvQueueRunning = false;
return message_ptr();
}
message_ptr m = mRcvQueue.front();
mRcvQueue.pop();
return m;
}
if (ptr)
{
mPingTimer.expires_from_now (boost::posix_time::seconds (theConfig.WEBSOCKET_PING_FREQ));
mPingTimer.async_wait (ptr->get_strand ().wrap (boost::bind (
&WSConnection<endpoint_type>::pingTimer, mConnection, mHandler, boost::asio::placeholders::error)));
}
}
void rcvMessage (message_ptr msg, bool& msgRejected, bool& runQueue)
{
boost::recursive_mutex::scoped_lock sl (mRcvQueueLock);
if (mDead)
{
msgRejected = false;
runQueue = false;
return;
}
if (mDead || (mRcvQueue.size () >= 1000))
{
msgRejected = !mDead;
runQueue = false;
}
else
{
msgRejected = false;
mRcvQueue.push (msg);
if (mRcvQueueRunning)
runQueue = false;
else
{
runQueue = true;
mRcvQueueRunning = true;
}
}
}
message_ptr getMessage ()
{
boost::recursive_mutex::scoped_lock sl (mRcvQueueLock);
if (mDead || mRcvQueue.empty ())
{
mRcvQueueRunning = false;
return message_ptr ();
}
message_ptr m = mRcvQueue.front ();
mRcvQueue.pop ();
return m;
}
private:
typedef void (WSConnection::*doFuncPtr)(Json::Value& jvResult, Json::Value &jvRequest);
typedef void (WSConnection::*doFuncPtr) (Json::Value& jvResult, Json::Value& jvRequest);
WSServerHandler<endpoint_type>* mHandler;
weak_connection_ptr mConnection;
NetworkOPs& mNetwork;
std::string mRemoteIP;
LoadSource mLoadSource;
WSServerHandler<endpoint_type>* mHandler;
weak_connection_ptr mConnection;
NetworkOPs& mNetwork;
std::string mRemoteIP;
LoadSource mLoadSource;
boost::asio::deadline_timer mPingTimer;
bool mPinged;
boost::asio::deadline_timer mPingTimer;
bool mPinged;
boost::recursive_mutex mRcvQueueLock;
std::queue<message_ptr> mRcvQueue;
bool mRcvQueueRunning;
bool mDead;
boost::recursive_mutex mRcvQueueLock;
std::queue<message_ptr> mRcvQueue;
bool mRcvQueueRunning;
bool mDead;
};
#endif

View File

@@ -18,7 +18,7 @@
SETUP_LOG (WSDoor)
DECLARE_INSTANCE(WebSocketConnection);
DECLARE_INSTANCE (WebSocketConnection);
//
// This is a light weight, untrusted interface for web clients.
@@ -34,81 +34,83 @@ DECLARE_INSTANCE(WebSocketConnection);
// - NetworkOPs is smart enough to subscribe and or pass back messages
//
void WSDoor::startListening()
void WSDoor::startListening ()
{
setCallingThreadName("websocket");
// Generate a single SSL context for use by all connections.
boost::shared_ptr<boost::asio::ssl::context> mCtx;
mCtx = boost::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
setCallingThreadName ("websocket");
// Generate a single SSL context for use by all connections.
boost::shared_ptr<boost::asio::ssl::context> mCtx;
mCtx = boost::make_shared<boost::asio::ssl::context> (boost::asio::ssl::context::sslv23);
mCtx->set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
mCtx->set_options (
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
SSL_CTX_set_tmp_dh_callback(mCtx->native_handle(), handleTmpDh);
SSL_CTX_set_tmp_dh_callback (mCtx->native_handle (), handleTmpDh);
// Construct a single handler for all requests.
websocketpp::server_autotls::handler::ptr handler(new WSServerHandler<websocketpp::server_autotls>(mCtx, mPublic));
// Construct a single handler for all requests.
websocketpp::server_autotls::handler::ptr handler (new WSServerHandler<websocketpp::server_autotls> (mCtx, mPublic));
// Construct a websocket server.
mSEndpoint = new websocketpp::server_autotls(handler);
// Construct a websocket server.
mSEndpoint = new websocketpp::server_autotls (handler);
// mEndpoint->alog().unset_level(websocketpp::log::alevel::ALL);
// mEndpoint->elog().unset_level(websocketpp::log::elevel::ALL);
// mEndpoint->alog().unset_level(websocketpp::log::alevel::ALL);
// mEndpoint->elog().unset_level(websocketpp::log::elevel::ALL);
// Call the main-event-loop of the websocket server.
try
{
mSEndpoint->listen(
boost::asio::ip::tcp::endpoint(
boost::asio::ip::address().from_string(mIp), mPort));
}
catch (websocketpp::exception& e)
{
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what();
while (1) // temporary workaround for websocketpp throwing exceptions on access/close races
{ // https://github.com/zaphoyd/websocketpp/issues/98
try
{
mSEndpoint->get_io_service().run();
break;
}
catch (websocketpp::exception& e)
{
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what();
}
}
}
// Call the main-event-loop of the websocket server.
try
{
mSEndpoint->listen (
boost::asio::ip::tcp::endpoint (
boost::asio::ip::address ().from_string (mIp), mPort));
}
catch (websocketpp::exception& e)
{
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what ();
delete mSEndpoint;
while (1) // temporary workaround for websocketpp throwing exceptions on access/close races
{
// https://github.com/zaphoyd/websocketpp/issues/98
try
{
mSEndpoint->get_io_service ().run ();
break;
}
catch (websocketpp::exception& e)
{
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what ();
}
}
}
delete mSEndpoint;
}
WSDoor* WSDoor::createWSDoor(const std::string& strIp, const int iPort, bool bPublic)
WSDoor* WSDoor::createWSDoor (const std::string& strIp, const int iPort, bool bPublic)
{
WSDoor* wdpResult = new WSDoor(strIp, iPort, bPublic);
WSDoor* wdpResult = new WSDoor (strIp, iPort, bPublic);
WriteLog (lsINFO, WSDoor) <<
boost::str(boost::format("Websocket: %s: Listening: %s %d ")
% (bPublic ? "Public" : "Private")
% strIp
% iPort);
WriteLog (lsINFO, WSDoor) <<
boost::str (boost::format ("Websocket: %s: Listening: %s %d ")
% (bPublic ? "Public" : "Private")
% strIp
% iPort);
wdpResult->mThread = new boost::thread(boost::bind(&WSDoor::startListening, wdpResult));
wdpResult->mThread = new boost::thread (boost::bind (&WSDoor::startListening, wdpResult));
return wdpResult;
return wdpResult;
}
void WSDoor::stop()
void WSDoor::stop ()
{
if (mThread)
{
if (mSEndpoint)
mSEndpoint->stop();
if (mThread)
{
if (mSEndpoint)
mSEndpoint->stop ();
mThread->join();
}
mThread->join ();
}
}
// vim:ts=4

View File

@@ -15,8 +15,8 @@
namespace websocketpp
{
class server;
class server_autotls;
class server;
class server_autotls;
}
#endif
@@ -25,22 +25,25 @@ namespace websocketpp
class WSDoor
{
private:
websocketpp::server_autotls* mSEndpoint;
websocketpp::server_autotls* mSEndpoint;
boost::thread* mThread;
bool mPublic;
std::string mIp;
int mPort;
boost::thread* mThread;
bool mPublic;
std::string mIp;
int mPort;
void startListening();
void startListening ();
public:
WSDoor(const std::string& strIp, int iPort, bool bPublic) : mSEndpoint(0), mThread(0), mPublic(bPublic), mIp(strIp), mPort(iPort) { ; }
WSDoor (const std::string& strIp, int iPort, bool bPublic) : mSEndpoint (0), mThread (0), mPublic (bPublic), mIp (strIp), mPort (iPort)
{
;
}
void stop();
void stop ();
static WSDoor* createWSDoor(const std::string& strIp, const int iPort, bool bPublic);
static WSDoor* createWSDoor (const std::string& strIp, const int iPort, bool bPublic);
};
#endif

View File

@@ -1,10 +1,10 @@
#ifndef __WSHANDLER__
#define __WSHANDLER__
extern void initSSLContext(boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file);
extern void initSSLContext (boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file);
extern bool serverOkay(std::string& reason);
extern bool serverOkay (std::string& reason);
template <typename endpoint_type>
class WSConnection;
@@ -20,276 +20,305 @@ template <typename endpoint_type>
class WSServerHandler : public endpoint_type::handler
{
public:
typedef typename endpoint_type::handler::connection_ptr connection_ptr;
typedef typename endpoint_type::handler::message_ptr message_ptr;
typedef boost::shared_ptr< WSConnection<endpoint_type> > wsc_ptr;
typedef typename endpoint_type::handler::connection_ptr connection_ptr;
typedef typename endpoint_type::handler::message_ptr message_ptr;
typedef boost::shared_ptr< WSConnection<endpoint_type> > wsc_ptr;
// Private reasons to close.
enum {
crTooSlow = 4000, // Client is too slow.
};
// Private reasons to close.
enum
{
crTooSlow = 4000, // Client is too slow.
};
private:
boost::shared_ptr<boost::asio::ssl::context> mCtx;
boost::shared_ptr<boost::asio::ssl::context> mCtx;
protected:
boost::mutex mMapLock;
// For each connection maintain an associated object to track subscriptions.
boost::unordered_map<connection_ptr, boost::shared_ptr< WSConnection<endpoint_type> > > mMap;
bool mPublic;
boost::mutex mMapLock;
// For each connection maintain an associated object to track subscriptions.
boost::unordered_map<connection_ptr, boost::shared_ptr< WSConnection<endpoint_type> > > mMap;
bool mPublic;
public:
WSServerHandler(boost::shared_ptr<boost::asio::ssl::context> spCtx, bool bPublic) : mCtx(spCtx), mPublic(bPublic)
{
if (theConfig.WEBSOCKET_SECURE != 0)
{
initSSLContext(*mCtx, theConfig.WEBSOCKET_SSL_KEY,
theConfig.WEBSOCKET_SSL_CERT, theConfig.WEBSOCKET_SSL_CHAIN);
}
}
WSServerHandler (boost::shared_ptr<boost::asio::ssl::context> spCtx, bool bPublic) : mCtx (spCtx), mPublic (bPublic)
{
if (theConfig.WEBSOCKET_SECURE != 0)
{
initSSLContext (*mCtx, theConfig.WEBSOCKET_SSL_KEY,
theConfig.WEBSOCKET_SSL_CERT, theConfig.WEBSOCKET_SSL_CHAIN);
}
}
bool getPublic() { return mPublic; };
bool getPublic ()
{
return mPublic;
};
boost::asio::ssl::context& getASIOContext() { return *mCtx; }
boost::asio::ssl::context& getASIOContext ()
{
return *mCtx;
}
static void ssend(connection_ptr cpClient, message_ptr mpMessage)
{
try
{
cpClient->send(mpMessage->get_payload(), mpMessage->get_opcode());
}
catch (...)
{
cpClient->close(websocketpp::close::status::value(crTooSlow), std::string("Client is too slow."));
}
}
static void ssend (connection_ptr cpClient, message_ptr mpMessage)
{
try
{
cpClient->send (mpMessage->get_payload (), mpMessage->get_opcode ());
}
catch (...)
{
cpClient->close (websocketpp::close::status::value (crTooSlow), std::string ("Client is too slow."));
}
}
static void ssend(connection_ptr cpClient, const std::string& strMessage, bool broadcast)
{
try
{
WriteLog (broadcast ? lsTRACE : lsDEBUG, WSServerHandlerLog) << "Ws:: Sending '" << strMessage << "'";
static void ssend (connection_ptr cpClient, const std::string& strMessage, bool broadcast)
{
try
{
WriteLog (broadcast ? lsTRACE : lsDEBUG, WSServerHandlerLog) << "Ws:: Sending '" << strMessage << "'";
cpClient->send(strMessage);
}
catch (...)
{
cpClient->close(websocketpp::close::status::value(crTooSlow), std::string("Client is too slow."));
}
}
cpClient->send (strMessage);
}
catch (...)
{
cpClient->close (websocketpp::close::status::value (crTooSlow), std::string ("Client is too slow."));
}
}
void send(connection_ptr cpClient, message_ptr mpMessage)
{
cpClient->get_strand().post(boost::bind(
&WSServerHandler<endpoint_type>::ssend, cpClient, mpMessage));
}
void send (connection_ptr cpClient, message_ptr mpMessage)
{
cpClient->get_strand ().post (boost::bind (
&WSServerHandler<endpoint_type>::ssend, cpClient, mpMessage));
}
void send(connection_ptr cpClient, const std::string& strMessage, bool broadcast)
{
cpClient->get_strand().post(boost::bind(
&WSServerHandler<endpoint_type>::ssend, cpClient, strMessage, broadcast));
}
void send (connection_ptr cpClient, const std::string& strMessage, bool broadcast)
{
cpClient->get_strand ().post (boost::bind (
&WSServerHandler<endpoint_type>::ssend, cpClient, strMessage, broadcast));
}
void send(connection_ptr cpClient, const Json::Value& jvObj, bool broadcast)
{
Json::FastWriter jfwWriter;
void send (connection_ptr cpClient, const Json::Value& jvObj, bool broadcast)
{
Json::FastWriter jfwWriter;
// WriteLog (lsDEBUG, WSServerHandlerLog) << "Ws:: Object '" << jfwWriter.write(jvObj) << "'";
// WriteLog (lsDEBUG, WSServerHandlerLog) << "Ws:: Object '" << jfwWriter.write(jvObj) << "'";
send(cpClient, jfwWriter.write(jvObj), broadcast);
}
send (cpClient, jfwWriter.write (jvObj), broadcast);
}
void pingTimer(connection_ptr cpClient)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl(mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find(cpClient);
if (it == mMap.end())
return;
ptr = it->second;
}
std::string data("ping");
if (ptr->onPingTimer(data))
{
WriteLog (lsWARNING, WSServerHandlerLog) << "Connection pings out";
cpClient->close(websocketpp::close::status::PROTOCOL_ERROR, "ping timeout");
}
else
cpClient->ping(data);
}
void pingTimer (connection_ptr cpClient)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl (mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find (cpClient);
void on_send_empty(connection_ptr cpClient)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl(mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find(cpClient);
if (it == mMap.end())
return;
ptr = it->second;
}
if (it == mMap.end ())
return;
ptr->onSendEmpty();
}
ptr = it->second;
}
std::string data ("ping");
void on_open(connection_ptr cpClient)
{
boost::mutex::scoped_lock sl(mMapLock);
if (ptr->onPingTimer (data))
{
WriteLog (lsWARNING, WSServerHandlerLog) << "Connection pings out";
cpClient->close (websocketpp::close::status::PROTOCOL_ERROR, "ping timeout");
}
else
cpClient->ping (data);
}
try
{
mMap[cpClient] = boost::make_shared< WSConnection<endpoint_type> >(this, cpClient);
}
catch (...)
{
}
}
void on_send_empty (connection_ptr cpClient)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl (mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find (cpClient);
void on_pong(connection_ptr cpClient, std::string data)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl(mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find(cpClient);
if (it == mMap.end())
return;
ptr = it->second;
}
ptr->onPong(data);
}
if (it == mMap.end ())
return;
void on_close(connection_ptr cpClient)
{ // we cannot destroy the connection while holding the map lock or we deadlock with pubLedger
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl(mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find(cpClient);
if (it == mMap.end())
return;
ptr = it->second; // prevent the WSConnection from being destroyed until we release the lock
mMap.erase(it);
}
ptr->preDestroy(); // Must be done before we return
ptr = it->second;
}
// Must be done without holding the websocket send lock
theApp->getJobQueue().addJob(jtCLIENT, "WSClient::destroy",
BIND_TYPE(&WSConnection<endpoint_type>::destroy, ptr));
}
ptr->onSendEmpty ();
}
void on_message(connection_ptr cpClient, message_ptr mpMessage)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl(mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find(cpClient);
if (it == mMap.end())
return;
ptr = it->second;
}
void on_open (connection_ptr cpClient)
{
boost::mutex::scoped_lock sl (mMapLock);
bool bRejected, bRunQ;
ptr->rcvMessage(mpMessage, bRejected, bRunQ);
if (bRejected)
{
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) << "Ws:: Rejected("
<< cpClient->get_socket().lowest_layer().remote_endpoint().address().to_string()
<< ") '" << mpMessage->get_payload() << "'";
}
catch (...)
{
}
}
if (bRunQ)
theApp->getJobQueue().addJob(jtCLIENT, "WSClient::command",
BIND_TYPE(&WSServerHandler<endpoint_type>::do_messages, this, P_1, cpClient));
}
try
{
mMap[cpClient] = boost::make_shared< WSConnection<endpoint_type> > (this, cpClient);
}
catch (...)
{
}
}
void do_messages(Job& job, connection_ptr cpClient)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl(mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find(cpClient);
if (it == mMap.end())
return;
ptr = it->second;
}
void on_pong (connection_ptr cpClient, std::string data)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl (mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find (cpClient);
for (int i = 0; i < 10; ++i)
{
message_ptr msg = ptr->getMessage();
if (!msg)
return;
do_message(job, cpClient, ptr, msg);
}
theApp->getJobQueue().addJob(jtCLIENT, "WSClient::more",
BIND_TYPE(&WSServerHandler<endpoint_type>::do_messages, this, P_1, cpClient));
}
if (it == mMap.end ())
return;
void do_message(Job& job, const connection_ptr& cpClient, const wsc_ptr& conn, const message_ptr& mpMessage)
{
Json::Value jvRequest;
Json::Reader jrReader;
ptr = it->second;
}
ptr->onPong (data);
}
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) << "Ws:: Receiving("
<< cpClient->get_socket().lowest_layer().remote_endpoint().address().to_string()
<< ") '" << mpMessage->get_payload() << "'";
}
catch (...)
{
}
void on_close (connection_ptr cpClient)
{
// we cannot destroy the connection while holding the map lock or we deadlock with pubLedger
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl (mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find (cpClient);
if (mpMessage->get_opcode() != websocketpp::frame::opcode::TEXT)
{
Json::Value jvResult(Json::objectValue);
if (it == mMap.end ())
return;
jvResult["type"] = "error";
jvResult["error"] = "wsTextRequired"; // We only accept text messages.
ptr = it->second; // prevent the WSConnection from being destroyed until we release the lock
mMap.erase (it);
}
ptr->preDestroy (); // Must be done before we return
send(cpClient, jvResult, false);
}
else if (!jrReader.parse(mpMessage->get_payload(), jvRequest) || jvRequest.isNull() || !jvRequest.isObject())
{
Json::Value jvResult(Json::objectValue);
// Must be done without holding the websocket send lock
theApp->getJobQueue ().addJob (jtCLIENT, "WSClient::destroy",
BIND_TYPE (&WSConnection<endpoint_type>::destroy, ptr));
}
jvResult["type"] = "error";
jvResult["error"] = "jsonInvalid"; // Received invalid json.
jvResult["value"] = mpMessage->get_payload();
void on_message (connection_ptr cpClient, message_ptr mpMessage)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl (mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find (cpClient);
send(cpClient, jvResult, false);
}
else
{
if (jvRequest.isMember("command"))
job.rename(std::string("WSClient::") + jvRequest["command"].asString());
send(cpClient, conn->invokeCommand(jvRequest), false);
}
}
if (it == mMap.end ())
return;
boost::shared_ptr<boost::asio::ssl::context> on_tls_init()
{
return mCtx;
}
ptr = it->second;
}
// Respond to http requests.
bool http(connection_ptr cpClient)
{
std::string reason;
if (!serverOkay(reason))
{
cpClient->set_body(std::string("<HTML><BODY>Server cannot accept clients: ") + reason + "</BODY></HTML>");
return false;
}
cpClient->set_body(
"<!DOCTYPE html><html><head><title>" SYSTEM_NAME " Test</title></head>"
"<body><h1>" SYSTEM_NAME " Test</h1><p>This page shows http(s) connectivity is working.</p></body></html>");
return true;
}
bool bRejected, bRunQ;
ptr->rcvMessage (mpMessage, bRejected, bRunQ);
if (bRejected)
{
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) << "Ws:: Rejected("
<< cpClient->get_socket ().lowest_layer ().remote_endpoint ().address ().to_string ()
<< ") '" << mpMessage->get_payload () << "'";
}
catch (...)
{
}
}
if (bRunQ)
theApp->getJobQueue ().addJob (jtCLIENT, "WSClient::command",
BIND_TYPE (&WSServerHandler<endpoint_type>::do_messages, this, P_1, cpClient));
}
void do_messages (Job& job, connection_ptr cpClient)
{
wsc_ptr ptr;
{
boost::mutex::scoped_lock sl (mMapLock);
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find (cpClient);
if (it == mMap.end ())
return;
ptr = it->second;
}
for (int i = 0; i < 10; ++i)
{
message_ptr msg = ptr->getMessage ();
if (!msg)
return;
do_message (job, cpClient, ptr, msg);
}
theApp->getJobQueue ().addJob (jtCLIENT, "WSClient::more",
BIND_TYPE (&WSServerHandler<endpoint_type>::do_messages, this, P_1, cpClient));
}
void do_message (Job& job, const connection_ptr& cpClient, const wsc_ptr& conn, const message_ptr& mpMessage)
{
Json::Value jvRequest;
Json::Reader jrReader;
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) << "Ws:: Receiving("
<< cpClient->get_socket ().lowest_layer ().remote_endpoint ().address ().to_string ()
<< ") '" << mpMessage->get_payload () << "'";
}
catch (...)
{
}
if (mpMessage->get_opcode () != websocketpp::frame::opcode::TEXT)
{
Json::Value jvResult (Json::objectValue);
jvResult["type"] = "error";
jvResult["error"] = "wsTextRequired"; // We only accept text messages.
send (cpClient, jvResult, false);
}
else if (!jrReader.parse (mpMessage->get_payload (), jvRequest) || jvRequest.isNull () || !jvRequest.isObject ())
{
Json::Value jvResult (Json::objectValue);
jvResult["type"] = "error";
jvResult["error"] = "jsonInvalid"; // Received invalid json.
jvResult["value"] = mpMessage->get_payload ();
send (cpClient, jvResult, false);
}
else
{
if (jvRequest.isMember ("command"))
job.rename (std::string ("WSClient::") + jvRequest["command"].asString ());
send (cpClient, conn->invokeCommand (jvRequest), false);
}
}
boost::shared_ptr<boost::asio::ssl::context> on_tls_init ()
{
return mCtx;
}
// Respond to http requests.
bool http (connection_ptr cpClient)
{
std::string reason;
if (!serverOkay (reason))
{
cpClient->set_body (std::string ("<HTML><BODY>Server cannot accept clients: ") + reason + "</BODY></HTML>");
return false;
}
cpClient->set_body (
"<!DOCTYPE html><html><head><title>" SYSTEM_NAME " Test</title></head>"
"<body><h1>" SYSTEM_NAME " Test</h1><p>This page shows http(s) connectivity is working.</p></body></html>");
return true;
}
};
#endif

Some files were not shown because too many files have changed in this diff Show More