mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 22:45:52 +00:00
Reformatting using AStyle
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user