refactoring of payment import started

new_rpc
moneroexamples 5 years ago
parent afb13b144c
commit 085731f343

@ -34,7 +34,7 @@
"wallet_import" :
{
"_comment": "if fee is 0, then importing is free. fee is in base 1e12, e.g., 0.1 xmr is 0.1 x 1e12 = 100000000000",
"fee" : 0,
"fee" : 100000000000,
"testnet" :
{
"address" : "9tzmPMTViHYM3z6NAgQni1Qm1Emzxy5hQFibPgWD3LVTAz91yok5Eni1pH6zKhBHzpTU15GZooPHSGHXFvFuXEdmEG2sWAZ",

@ -3,7 +3,7 @@
#include "src/MicroCore.h"
#include "src/YourMoneroRequests.h"
#include "src/ThreadRAII.h"
#include "src/MysqlPing.h"
#include "src/db/MysqlPing.h"
#include <iostream>
#include <memory>

@ -7,9 +7,9 @@ set(SOURCE_FILES
tools.cpp
CmdLineOptions.cpp
CurrentBlockchainStatus.cpp
MySqlConnector.cpp
MySqlAccounts.cpp
ssqlses.cpp
db/MySqlConnector.cpp
db/MySqlAccounts.cpp
db/ssqlses.cpp
YourMoneroRequests.cpp
TxSearch.cpp
RPCCalls.cpp
@ -17,7 +17,7 @@ set(SOURCE_FILES
version.h.in
BlockchainSetup.cpp
ThreadRAII.cpp
MysqlPing.cpp
db/MysqlPing.cpp
TxUnlockChecker.cpp
UniversalIdentifier.cpp
RandomOutputs.cpp)

@ -601,7 +601,7 @@ CurrentBlockchainStatus::start_tx_search_thread(
{acc.address, ThreadRAII2<TxSearch>(std::move(tx_search))});
OMINFO << acc.address.substr(0,6)
+ " :TxSearch thread created.";
+ ": TxSearch thread created.";
}
catch (const std::exception& e)
{

@ -4,14 +4,14 @@
#include "om_log.h"
#include "MicroCore.h"
#include "ssqlses.h"
#include "db/ssqlses.h"
#include "TxUnlockChecker.h"
#include "BlockchainSetup.h"
#include "TxSearch.h"
#include "tools.h"
#include "ThreadRAII.h"
#include "RPCCalls.h"
#include "MySqlAccounts.h"
#include "db/MySqlAccounts.h"
#include "RandomOutputs.h"
#include <iostream>
@ -27,7 +27,7 @@ using namespace std;
class XmrAccount;
class MySqlAccounts;
class TxSearch;
/*
* This is a thread class. Probably it should be singleton, as we want

@ -132,7 +132,8 @@ public:
virtual std::vector<uint64_t>
get_tx_amount_output_indices(uint64_t const& tx_id) const
{
return core_storage.get_db().get_tx_amount_output_indices(tx_id);
return core_storage.get_db()
.get_tx_amount_output_indices(tx_id).front();
}
virtual bool

@ -1,636 +0,0 @@
//
// Created by mwo on 7/01/17.
//
#define MYSQLPP_SSQLS_NO_STATICS 1
#include "MySqlAccounts.h"
#include "TxSearch.h"
#include "CurrentBlockchainStatus.h"
#include "ssqlses.h"
namespace xmreg
{
MysqlInputs::MysqlInputs(shared_ptr<MySqlConnector> _conn)
: conn {_conn}
{}
bool
MysqlInputs::select_for_out(const uint64_t& output_id, vector<XmrInput>& ins)
{
try
{
conn->check_if_connected();
Query query = conn->query(XmrInput::SELECT_STMT4);
query.parse();
query.storein(ins, output_id);
return !ins.empty();
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
//throw e;
}
return false;
}
MysqlOutpus::MysqlOutpus(shared_ptr<MySqlConnector> _conn): conn {_conn}
{}
bool
MysqlOutpus::exist(const string& output_public_key_str, XmrOutput& out)
{
try
{
conn->check_if_connected();
Query query = conn->query(XmrOutput::EXIST_STMT);
query.parse();
vector<XmrOutput> outs;
query.storein(outs, output_public_key_str);
if (outs.empty())
return false;
out = std::move(outs.at(0));
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
return false;
}
return true;
}
MysqlTransactions::MysqlTransactions(shared_ptr<MySqlConnector> _conn): conn {_conn}
{}
uint64_t
MysqlTransactions::mark_spendable(const uint64_t& tx_id_no, bool spendable)
{
try
{
conn->check_if_connected();
Query query = conn->query(spendable ?
XmrTransaction::MARK_AS_SPENDABLE_STMT
: XmrTransaction::MARK_AS_NONSPENDABLE_STMT);
query.parse();
SimpleResult sr = query.execute(tx_id_no);
return sr.rows();
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
//throw e;
}
return 0;
}
uint64_t
MysqlTransactions::delete_tx(const uint64_t& tx_id_no)
{
try
{
conn->check_if_connected();
Query query = conn->query(XmrTransaction::DELETE_STMT);
query.parse();
SimpleResult sr = query.execute(tx_id_no);
return sr.rows();
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
//throw e;
}
return 0;
}
bool
MysqlTransactions::exist(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx)
{
try
{
conn->check_if_connected();
Query query = conn->query(XmrTransaction::EXIST_STMT);
query.parse();
vector<XmrTransaction> outs;
query.storein(outs, account_id, tx_hash_str);
if (outs.empty())
return false;
tx = outs.at(0);
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
return false;
}
return true;
}
bool
MysqlTransactions::get_total_recieved(const uint64_t& account_id, uint64_t& amount)
{
try
{
conn->check_if_connected();
Query query = conn->query(XmrTransaction::SUM_XMR_RECIEVED);
query.parse();
StoreQueryResult sqr = query.store(account_id);
if (!sqr.empty())
{
amount = sqr.at(0)["total_received"];
return true;
}
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
MysqlPayments::MysqlPayments(shared_ptr<MySqlConnector> _conn): conn {_conn}
{}
bool
MysqlPayments::select_by_payment_id(const string& payment_id, vector<XmrPayment>& payments)
{
try
{
conn->check_if_connected();
Query query = conn->query(XmrPayment::SELECT_STMT2);
query.parse();
payments.clear();
query.storein(payments, payment_id);
return !payments.empty();
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
//throw e;
}
return false;
}
MySqlAccounts::MySqlAccounts(shared_ptr<CurrentBlockchainStatus> _current_bc_status)
: current_bc_status {_current_bc_status}
{
// create connection to the mysql
conn = make_shared<MySqlConnector>();
_init();
}
MySqlAccounts::MySqlAccounts(shared_ptr<CurrentBlockchainStatus> _current_bc_status,
shared_ptr<MySqlConnector> _conn)
: current_bc_status {_current_bc_status}
{
conn = _conn;
_init();
}
bool
MySqlAccounts::select(const string& address, XmrAccount& account)
{
try
{
conn->check_if_connected();
Query query = conn->query(XmrAccount::SELECT_STMT2);
query.parse();
vector<XmrAccount> res;
query.storein(res, address);
if (!res.empty())
{
account = std::move(res.at(0));
return true;
}
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
//throw e;
}
return false;
}
template <typename T>
uint64_t
MySqlAccounts::insert(const T& data_to_insert)
{
try
{
conn->check_if_connected();
Query query = conn->query();
query.insert(data_to_insert);
SimpleResult sr = query.execute();
if (sr.rows() == 1)
return sr.insert_id();
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);;
}
return 0;
}
// Explicitly instantiate insert template for our tables
template
uint64_t MySqlAccounts::insert<XmrAccount>(const XmrAccount& data_to_insert);
template
uint64_t MySqlAccounts::insert<XmrTransaction>(const XmrTransaction& data_to_insert);
template
uint64_t MySqlAccounts::insert<XmrOutput>(const XmrOutput& data_to_insert);
template
uint64_t MySqlAccounts::insert<XmrInput>(const XmrInput& data_to_insert);
template
uint64_t MySqlAccounts::insert<XmrPayment>(const XmrPayment& data_to_insert);
template <typename T>
uint64_t
MySqlAccounts::insert(const vector<T>& data_to_insert)
{
try
{
conn->check_if_connected();
Query query = conn->query();
query.insert(data_to_insert.begin(), data_to_insert.end());
SimpleResult sr = query.execute();
return sr.rows();
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return 0;
}
// Explicitly instantiate insert template for our tables
template
uint64_t MySqlAccounts::insert<XmrOutput>(const vector<XmrOutput>& data_to_insert);
template
uint64_t MySqlAccounts::insert<XmrInput>(const vector<XmrInput>& data_to_insert);
template <typename T, size_t query_no>
bool
MySqlAccounts::select(uint64_t account_id, vector<T>& selected_data)
{
try
{
conn->check_if_connected();
Query query = conn->query((query_no == 1 ? T::SELECT_STMT : T::SELECT_STMT2));
query.parse();
selected_data.clear();
query.storein(selected_data, account_id);
return !selected_data.empty();
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
template
bool MySqlAccounts::select<XmrAccount>(uint64_t account_id, vector<XmrAccount>& selected_data);
template
bool MySqlAccounts::select<XmrTransaction>(uint64_t account_id, vector<XmrTransaction>& selected_data);
template
bool MySqlAccounts::select<XmrOutput>(uint64_t account_id, vector<XmrOutput>& selected_data);
template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id,
bool MySqlAccounts::select<XmrOutput, 2>(uint64_t tx_id, vector<XmrOutput>& selected_data);
template
bool MySqlAccounts::select<XmrInput>(uint64_t account_id, vector<XmrInput>& selected_data);
template
bool MySqlAccounts::select<XmrPayment>(uint64_t account_id, vector<XmrPayment>& selected_data);
template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id,
bool MySqlAccounts::select<XmrInput, 2>(uint64_t tx_id, vector<XmrInput>& selected_data);
template <typename T>
bool
MySqlAccounts::update(T const& orginal_row, T const& new_row)
{
try
{
conn->check_if_connected();
Query query = conn->query();
query.update(orginal_row, new_row);
SimpleResult sr = query.execute();
return sr.rows() == 1;
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
template
bool MySqlAccounts::update<XmrAccount>(XmrAccount const& orginal_row, XmrAccount const& new_row);
template
bool MySqlAccounts::update<XmrPayment>(XmrPayment const& orginal_row, XmrPayment const& new_row);
template <typename T>
bool
MySqlAccounts::select_for_tx(uint64_t tx_id, vector<T>& selected_data)
{
return select<T, 2>(tx_id, selected_data);
}
template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id,
bool MySqlAccounts::select_for_tx<XmrOutput>(uint64_t tx_id, vector<XmrOutput>& selected_data);
template // this will use SELECT_STMT2 which selectes based on transaction id, not account_id,
bool MySqlAccounts::select_for_tx<XmrInput>(uint64_t tx_id, vector<XmrInput>& selected_data);
template <typename T>
bool
MySqlAccounts::select_by_primary_id(uint64_t id, T& selected_data)
{
try
{
conn->check_if_connected();
Query query = conn->query(T::SELECT_STMT3);
query.parse();
vector<T> outs;
query.storein(outs, id);
if (!outs.empty())
{
selected_data = std::move(outs.at(0));
return true;
}
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
//throw e;
}
return false;
}
//template
//bool MySqlAccounts::select_by_primary_id<XmrTransaction>(uint64_t id, XmrTransaction& selected_data);
template
bool MySqlAccounts::select_by_primary_id<XmrInput>(uint64_t id, XmrInput& selected_data);
template
bool MySqlAccounts::select_by_primary_id<XmrOutput>(uint64_t id, XmrOutput& selected_data);
template
bool MySqlAccounts::select_by_primary_id<XmrPayment>(uint64_t id, XmrPayment& selected_data);
bool
MySqlAccounts::select_txs_for_account_spendability_check(
const uint64_t& account_id, vector<XmrTransaction>& txs)
{
for (auto it = txs.begin(); it != txs.end(); )
{
// first we check if txs stored in db are already spendable
// it means if they are older than 10 blocks. If yes,
// we mark them as spendable, as we assume that blocks
// older than 10 blocks are permanent, i.e, they wont get
// orphaned.
XmrTransaction& tx = *it;
if (bool {tx.spendable} == false)
{
if (current_bc_status->is_tx_unlocked(tx.unlock_time, tx.height))
{
// this tx was before marked as unspendable, but now
// it is spendable. Meaning, that its older than 10 blocks.
// so mark it as spendable in mysql, so that its permanet.
uint64_t no_row_updated = mark_tx_spendable(tx.id.data);
if (no_row_updated != 1)
{
cerr << "no_row_updated != 1 due to xmr_accounts->mark_tx_spendable(tx.id)\n";
return false;
}
tx.spendable = true;
}
else
{
// tx was marked as non-spendable, i.e., younger than 10 blocks
// so we still are going to use this txs, but we need to double
// check if its still valid, i.e., it's block did not get orphaned.
// we do this by checking if txs still exists in the blockchain
// and if its blockchain_tx_id is same as what we have in our mysql.
uint64_t blockchain_tx_id {0};
current_bc_status->tx_exist(tx.hash, blockchain_tx_id);
if (blockchain_tx_id != tx.blockchain_tx_id)
{
// tx does not exist in blockchain, or its blockchain_id changed
// for example, it was orhpaned, and then readded.
uint64_t no_row_updated = delete_tx(tx.id.data);
if (no_row_updated != 1)
{
cerr << "no_row_updated != 1 due to xmr_accounts->delete_tx(tx.id)\n";
return false;
}
// because txs does not exist in blockchain anymore,
// we assume its back to mempool, and it will be rescanned
// by tx search thread once added again to some block.
// so we remove it from txs vector
it = txs.erase(it);
continue;
}
// set unlock_time field so that frontend displies it
// as a locked tx, if unlock_time is zero.
// coinbtase txs have this set already. regular tx
// have unlock_time set to zero by default, but they cant
// be spent anyway.
if (tx.unlock_time == 0)
tx.unlock_time = tx.height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
} // else
} // if (bool {tx.spendable} == false)
++it;
} // for (auto it = txs.begin(); it != txs.end(); )
return true;
}
bool
MySqlAccounts::select_inputs_for_out(const uint64_t& output_id, vector<XmrInput>& ins)
{
return mysql_in->select_for_out(output_id, ins);
}
bool
MySqlAccounts::output_exists(const string& output_public_key_str, XmrOutput& out)
{
return mysql_out->exist(output_public_key_str, out);
}
bool
MySqlAccounts::tx_exists(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx)
{
return mysql_tx->exist(account_id, tx_hash_str, tx);
}
uint64_t
MySqlAccounts::mark_tx_spendable(const uint64_t& tx_id_no)
{
return mysql_tx->mark_spendable(tx_id_no);
}
uint64_t
MySqlAccounts::mark_tx_nonspendable(const uint64_t& tx_id_no)
{
return mysql_tx->mark_spendable(tx_id_no, false);
}
uint64_t
MySqlAccounts::delete_tx(const uint64_t& tx_id_no)
{
return mysql_tx->delete_tx(tx_id_no);
}
bool
MySqlAccounts::select_payment_by_id(const string& payment_id, vector<XmrPayment>& payments)
{
return mysql_payment->select_by_payment_id(payment_id, payments);
}
bool
MySqlAccounts::get_total_recieved(const uint64_t& account_id, uint64_t& amount)
{
return mysql_tx->get_total_recieved(account_id, amount);
}
void
MySqlAccounts::disconnect()
{
get_connection()->get_connection().disconnect();
}
shared_ptr<MySqlConnector>
MySqlAccounts::get_connection()
{
return conn;
}
void
MySqlAccounts::set_bc_status_provider(shared_ptr<CurrentBlockchainStatus> bc_status_provider)
{
current_bc_status = bc_status_provider;
}
void
MySqlAccounts::_init()
{
// use same connection when working with other tables
mysql_tx = make_shared<MysqlTransactions>(conn);
mysql_out = make_shared<MysqlOutpus>(conn);
mysql_in = make_shared<MysqlInputs>(conn);
mysql_payment = make_shared<MysqlPayments>(conn);
}
}

@ -1,250 +0,0 @@
//
// Created by mwo on 16/12/16.
//
#ifndef RESTBED_XMR_MYSQLACCOUNTS_H
#define RESTBED_XMR_MYSQLACCOUNTS_H
#include "tools.h"
#include "MySqlConnector.h"
#include <iostream>
#include <memory>
namespace xmreg
{
using namespace mysqlpp;
using namespace std;
using namespace nlohmann;
class XmrTransactionWithOutsAndIns;
class XmrInput;
class XmrOutput;
class XmrTransaction;
class XmrPayment;
class XmrAccount;
class TxSearch;
class Table;
class CurrentBlockchainStatus;
class MysqlInputs
{
shared_ptr<MySqlConnector> conn;
public:
MysqlInputs(shared_ptr<MySqlConnector> _conn);
bool
select_for_out(const uint64_t& output_id, vector<XmrInput>& ins);
};
class MysqlOutpus
{
shared_ptr<MySqlConnector> conn;
public:
MysqlOutpus(shared_ptr<MySqlConnector> _conn);
bool
exist(const string& output_public_key_str, XmrOutput& out);
};
class MysqlTransactions
{
shared_ptr<MySqlConnector> conn;
public:
MysqlTransactions(shared_ptr<MySqlConnector> _conn);
uint64_t
mark_spendable(const uint64_t& tx_id_no, bool spendable = true);
uint64_t
delete_tx(const uint64_t& tx_id_no);
bool
exist(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx);
bool
get_total_recieved(const uint64_t& account_id, uint64_t& amount);
};
class MysqlPayments
{
shared_ptr<MySqlConnector> conn;
public:
MysqlPayments(shared_ptr<MySqlConnector> _conn);
bool
select_by_payment_id(const string& payment_id, vector<XmrPayment>& payments);
};
class TxSearch;
class MySqlAccounts
{
shared_ptr<MySqlConnector> conn;
shared_ptr<MysqlTransactions> mysql_tx;
shared_ptr<MysqlOutpus> mysql_out;
shared_ptr<MysqlInputs> mysql_in;
shared_ptr<MysqlPayments> mysql_payment;
shared_ptr<CurrentBlockchainStatus> current_bc_status;
public:
MySqlAccounts(shared_ptr<CurrentBlockchainStatus> _current_bc_status);
MySqlAccounts(shared_ptr<CurrentBlockchainStatus> _current_bc_status,
shared_ptr<MySqlConnector> _conn);
bool
select(const string& address, XmrAccount& account);
template <typename T>
uint64_t
insert(const T& data_to_insert);
template <typename T>
uint64_t
insert(const vector<T>& data_to_insert);
/**
*
* @tparam T
* @tparam query_no which query to use, for SELECT_STMT or SELECT_STMT2
* @param account_id
* @param selected_data
* @return
*/
template <typename T, size_t query_no = 1>
bool
select(uint64_t account_id, vector<T>& selected_data);
template <typename T>
bool
update(T const& orginal_row, T const& new_row);
template <typename T>
bool
select_for_tx(uint64_t tx_id, vector<T>& selected_data);
template <typename T>
bool
select_by_primary_id(uint64_t id, T& selected_data);
bool
select_txs_for_account_spendability_check(const uint64_t& account_id,
vector<XmrTransaction>& txs);
bool
select_inputs_for_out(const uint64_t& output_id, vector<XmrInput>& ins);
bool
output_exists(const string& output_public_key_str, XmrOutput& out);
bool
tx_exists(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx);
uint64_t
mark_tx_spendable(const uint64_t& tx_id_no);
uint64_t
mark_tx_nonspendable(const uint64_t& tx_id_no);
uint64_t
delete_tx(const uint64_t& tx_id_no);
bool
select_payment_by_id(const string& payment_id, vector<XmrPayment>& payments);
bool
update_payment(XmrPayment& payment_orginal, XmrPayment& payment_new);
bool
get_total_recieved(const uint64_t& account_id, uint64_t& amount);
void
disconnect();
shared_ptr<MySqlConnector>
get_connection();
/**
* DONT use!!!
*
* Its only useful in unit tests when you know that nothing will insert
* any row between calling this and using the returned id
*
* @tparam T
* @param table_class
* @return
*/
template <typename T>
uint64_t
get_next_primary_id(T&& table_class)
{
static_assert(std::is_base_of<Table, std::decay_t<T>>::value, "given class is not Table");
string sql {"SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '"};
sql += table_class.table_name() + "' AND table_schema = '" + MySqlConnector::dbname + "'";
Query query = conn->query(sql);
query.parse();
try
{
conn->check_if_connected();
StoreQueryResult sr = query.store();
if (!sr.empty())
return sr[0][0];
}
catch (std::exception const& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return 0;
}
// this is useful in unit tests, as we can inject mock CurrentBlockchainStatus
// after an instance of MySqlAccounts has been created.
void
set_bc_status_provider(shared_ptr<CurrentBlockchainStatus> bc_status_provider);
private:
void _init();
};
}
#endif //RESTBED_XMR_MYSQLACCOUNTS_H

@ -1,98 +0,0 @@
//
// Created by mwo on 7/01/17.
//
#include "MySqlConnector.h"
#include <mysql++/mysql++.h>
#include <mysql++/ssqls.h>
#include <iostream>
#include <memory>
namespace xmreg {
string MySqlConnector::url;
size_t MySqlConnector::port;
string MySqlConnector::username;
string MySqlConnector::password;
string MySqlConnector::dbname;
MySqlConnector::MySqlConnector()
{
_init();
}
MySqlConnector::MySqlConnector(Option* _option)
{
conn.set_option(_option);
_init();
}
bool
MySqlConnector::connect()
{
if (conn.connected())
return true;
try
{
conn.connect(dbname.c_str(),
url.c_str(),
username.c_str(),
password.c_str(),
port);
}
catch (mysqlpp::ConnectionFailed const& e)
{
MYSQL_EXCEPTION_MSG(e);
return false;
}
return true;
}
bool
MySqlConnector::ping()
{
return conn.ping();
}
Query
MySqlConnector::query(const char *qstr)
{
return conn.query(qstr);
}
Query
MySqlConnector::query(const std::string &qstr)
{
return conn.query(qstr);
}
Connection&
MySqlConnector::get_connection()
{
return conn;
}
MySqlConnector::~MySqlConnector()
{
conn.disconnect();
};
void
MySqlConnector::_init()
{
if (!connect())
{
cerr << "Connection to Mysql failed!" << endl;
throw std::runtime_error("Connection to Mysql failed!");
}
}
}

@ -1,94 +0,0 @@
//
// Created by mwo on 9/12/16.
//
#ifndef RESTBED_XMR_MYSQLCONNECTOR_H
#define RESTBED_XMR_MYSQLCONNECTOR_H
//#include "tools.h"
#include <mysql++/mysql++.h>
#include <mysql++/ssqls.h>
#include <iostream>
namespace xmreg
{
using namespace mysqlpp;
using namespace std;
#define MYSQL_EXCEPTION_MSG(sql_excetption) cerr << "# ERR: SQLException in " << __FILE__ \
<< "(" << __FUNCTION__ << ") on line " << __LINE__ << endl \
<< "# ERR: " << sql_excetption.what() \
<< endl;
/*
* This is that creates connections
* our mysql database.
*
* Each thread has its own connection.
* This way when something breaks in one thread,
* other threads can still operate on the mysql.
*
*/
class MySqlConnector
{
Connection conn;
public:
static string url;
static size_t port;
static string username;
static string password;
static string dbname;
MySqlConnector();
MySqlConnector(Option* _option);
// dont want any copies of connection object.
// pass it around through shared or unique pointer
MySqlConnector (const MySqlConnector&) = delete;
MySqlConnector& operator= (const MySqlConnector&) = delete;
Query
query(const char* qstr = 0);
Query
query(const std::string& qstr);
virtual bool
connect();
bool
ping();
Connection&
get_connection();
// this throws exception if not connected
inline void
check_if_connected()
{
if (!conn.connected())
throw std::runtime_error("No connection to the mysqldb");
}
virtual ~MySqlConnector();
protected:
void _init();
};
}
#endif //RESTBED_XMR_MYSQLCONNECTOR_H

@ -1,49 +0,0 @@
//
// Created by mwo on 12/07/18.
//
#include "easylogging++.h"
#include "om_log.h"
#include "MysqlPing.h"
namespace xmreg
{
MysqlPing::MysqlPing(
std::shared_ptr<MySqlConnector> _conn,
seconds _ping_time)
: conn {_conn}, ping_time {_ping_time}
{}
void
MysqlPing::operator()()
{
while (keep_looping)
{
std::this_thread::sleep_for(chrono::seconds(ping_time));
if (auto c = conn.lock())
{
if (!c->ping())
{
OMERROR << "Pinging mysql failed. Stoping mysql pinging thread.";
why_stoped = StopReason::PingFailed;
break;
}
OMINFO << "Mysql ping successful." ;
}
else
{
OMERROR << "std::weak_ptr<MySqlConnector> conn expired!";
why_stoped = StopReason::PointerExpired;
break;
}
++counter;
}
}
}

@ -1,47 +0,0 @@
//
// Created by mwo on 12/07/18.
//
#ifndef OPENMONERO_MYSQLPING_H
#define OPENMONERO_MYSQLPING_H
#include "MySqlConnector.h"
#include <memory>
#include <thread>
#include <atomic>
namespace xmreg
{
using chrono::seconds;
using namespace literals::chrono_literals;
class MysqlPing
{
public:
enum class StopReason {NotYetStopped, PingFailed, PointerExpired};
MysqlPing(std::shared_ptr<MySqlConnector> _conn,
seconds _ping_time = 300s);
void operator()();
void stop() {keep_looping = false;}
uint64_t get_counter() const {return counter;}
StopReason get_stop_reason() const {return why_stoped;};
MysqlPing(MysqlPing&&) = default;
MysqlPing& operator=(MysqlPing&&) = default;
private:
std::weak_ptr<MySqlConnector> conn;
seconds ping_time; // in seconds
atomic<bool> keep_looping {true};
atomic<uint64_t> counter {0};
atomic<StopReason> why_stoped {StopReason::NotYetStopped};
};
}
#endif //OPENMONERO_MYSQLPING_H

@ -6,9 +6,9 @@
#include "TxSearch.h"
#include "MySqlAccounts.h"
#include "db/MySqlAccounts.h"
#include "ssqlses.h"
#include "db/ssqlses.h"
#include "CurrentBlockchainStatus.h"

@ -1,6 +1,6 @@
#pragma once
#include "MySqlAccounts.h"
#include "db/MySqlAccounts.h"
#include "OutputInputIdentification.h"
#include <memory>

@ -7,7 +7,7 @@
#include "YourMoneroRequests.h"
#include "ssqlses.h"
#include "db/ssqlses.h"
#include "OutputInputIdentification.h"
namespace xmreg
@ -47,7 +47,7 @@ YourMoneroRequests::login(const shared_ptr<Session> session, const Bytes & body)
if (!parse_request(body, required_values, j_request, j_response))
{
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -62,7 +62,7 @@ YourMoneroRequests::login(const shared_ptr<Session> session, const Bytes & body)
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -119,7 +119,7 @@ YourMoneroRequests::login(const shared_ptr<Session> session, const Bytes & body)
j_response = json {{"status", "error"},
{"reason", "Account creation failed"}};
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -147,13 +147,13 @@ YourMoneroRequests::login(const shared_ptr<Session> session, const Bytes & body)
else
{
// some error with loggin in or search thread start
session_close(session, j_response.dump());
session_close(session, j_response);
return;
} // else if (login_and_start_search_thread(xmr_address,
session_close(session, j_response.dump());
session_close(session, j_response);
}
void
@ -167,7 +167,7 @@ YourMoneroRequests::get_address_txs(
if (!parse_request(body, requested_values, j_request, j_response))
{
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -181,8 +181,8 @@ YourMoneroRequests::get_address_txs(
}
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
session_close(session, j_response.dump());
OMERROR << "json exception: " << e.what();
session_close(session, j_response, UNPROCESSABLE_ENTITY);
return;
}
@ -319,7 +319,7 @@ YourMoneroRequests::get_address_txs(
{"reason", "Search thread does not exist."}};
// some error with loggin in or search thread start
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -399,7 +399,7 @@ YourMoneroRequests::get_address_info(
if (!parse_request(body, requested_values, j_request, j_response))
{
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -414,7 +414,7 @@ YourMoneroRequests::get_address_info(
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -541,7 +541,7 @@ YourMoneroRequests::get_address_info(
{"reason", "Search thread does not exist."}};
// some error with loggin in or search thread start
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -567,7 +567,7 @@ YourMoneroRequests::get_unspent_outs(
if (!parse_request(body, requested_values, j_request, j_response))
{
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -594,13 +594,13 @@ YourMoneroRequests::get_unspent_outs(
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
catch (boost::bad_lexical_cast const& e)
{
cerr << "Bed lexical cast" << e.what() << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -628,7 +628,7 @@ YourMoneroRequests::get_unspent_outs(
if (!login_and_start_search_thread(xmr_address, view_key, acc, j_response))
{
// some error with loggin in or search thread start
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -760,7 +760,7 @@ YourMoneroRequests::get_unspent_outs(
{"reason", "Search thread does not exist."}};
// some error with loggin in or search thread start
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -784,7 +784,7 @@ YourMoneroRequests::get_random_outs(
if (!parse_request(body, requested_values, j_request, j_response))
{
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -797,7 +797,7 @@ YourMoneroRequests::get_random_outs(
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
};
@ -807,7 +807,7 @@ YourMoneroRequests::get_random_outs(
j_response["status"] = "error";
j_response["error"] = fmt::format("Request ring size {:d} too large",
count);
session_close(session, j_response.dump());
session_close(session, j_response);
}
vector<uint64_t> amounts;
@ -827,7 +827,7 @@ YourMoneroRequests::get_random_outs(
catch (boost::bad_lexical_cast& e)
{
cerr << "Bed lexical cast" << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -922,7 +922,7 @@ YourMoneroRequests::submit_raw_tx(
OMERROR << j_response["Error"];
session_close(session, j_response.dump(),
session_close(session, j_response,
UNPROCESSABLE_ENTITY);
return;
}
@ -936,7 +936,7 @@ YourMoneroRequests::submit_raw_tx(
OMERROR << j_response["Error"];
session_close(session, j_response.dump(),
session_close(session, j_response,
UNPROCESSABLE_ENTITY);
return;
}
@ -951,7 +951,7 @@ YourMoneroRequests::submit_raw_tx(
OMERROR << j_response["Error"];
session_close(session, j_response.dump(),
session_close(session, j_response,
UNPROCESSABLE_ENTITY);
return;
}
@ -965,7 +965,7 @@ YourMoneroRequests::submit_raw_tx(
OMERROR << j_response["Error"];
session_close(session, j_response.dump(),
session_close(session, j_response,
UNPROCESSABLE_ENTITY);
return;
}
@ -998,7 +998,17 @@ YourMoneroRequests::import_wallet_request(
j_response["status"] = "error";
j_response["error"] = "Some error occured";
// if current_bc_status-> is zero, we just import the wallet.
// get account from mysql db if exists
auto xmr_account = select_account(xmr_address);
if (!xmr_account)
{
session_close(session, j_response, UNPROCESSABLE_ENTITY,
"The account does not exists!");
return;
}
// if import_fee is zero, we just import the wallet.
// we dont care about any databases or anything, as importing
// wallet is free.
// just reset the scanned block height in mysql and finish.
@ -1009,7 +1019,10 @@ YourMoneroRequests::import_wallet_request(
{
OMERROR << xmr_address.substr(0,6)
+ ": updating searched_blk_no failed!";
j_response["error"] = "Updating searched_blk_no failed!";
session_close(session, j_response, UNPROCESSABLE_ENTITY,
"Updating searched_blk_no failed!");
return;
}
j_response["request_fulfilled"] = true;
@ -1017,212 +1030,176 @@ YourMoneroRequests::import_wallet_request(
j_response["new_request"] = true;
j_response["error"] = "";
string response_body = j_response.dump();
auto response_headers
= make_headers({{ "Content-Length",
std::to_string(response_body.size())}});
session->close( OK, response_body, response_headers);
session_close(session, j_response);
return;
}
XmrAccount acc;
if (!xmr_accounts->select(xmr_address, acc))
{
OMERROR << xmr_address.substr(0,6) +
": address does not exists!";
j_response["error"] = "The account does not exists!";
string response_body = j_response.dump();
auto response_headers
= make_headers({{ "Content-Length",
std::to_string(response_body.size())}});
auto xmr_payment = select_payment(*xmr_account);
session->close( OK, response_body, response_headers);
if (!xmr_payment)
{
session_close(session, j_response, UNPROCESSABLE_ENTITY,
"Selecting payment details faild!");
return;
}
if (xmr_payment->id == mysqlpp::null)
{
// no current payment record exist,
// so we have to create new one.
// a placeholder for existing or new payment data
vector<XmrPayment> xmr_payments;
// payment request is new, so create its entry in
// Payments table
uint64_t payment_table_id {0};
// select this payment if its existing one
if (xmr_accounts->select(acc.id.data, xmr_payments))
{
// payment record exists, so now we need to check if
// actually payment has been done, and updated
// mysql record accordingly.
crypto::hash8 random_payment_id8 = crypto::rand<crypto::hash8>();
if (xmr_payments.size() > 1)
{
OMERROR << xmr_address.substr(0,6) +
"More than one payment record found!";
j_response["error"] = "TMore than one payment record found!";
string integrated_address =
current_bc_status->get_account_integrated_address_as_str(
random_payment_id8);
string response_body = j_response.dump();
auto response_headers
= make_headers({{ "Content-Length",
to_string(response_body.size())}});
xmr_payment->account_id = xmr_account->id.data;
xmr_payment->payment_id = pod_to_hex(random_payment_id8);
xmr_payment->import_fee = current_bc_status
->get_bc_setup().import_fee; // xmr
xmr_payment->request_fulfilled = false;
xmr_payment->tx_hash = ""; // no tx_hash yet with the payment
xmr_payment->payment_address = integrated_address;
if ((payment_table_id = xmr_accounts->insert(*xmr_payment)) == 0)
{
OMERROR << xmr_address.substr(0, 6)
+ ": failed to create new payment record!";
session->close( OK, response_body, response_headers);
session_close(session, j_response, UNPROCESSABLE_ENTITY,
"Failed to create new payment record!");
return;
}
XmrPayment& xmr_payment = xmr_payments[0];
// payment entry created
bool request_fulfilled = bool {xmr_payment.request_fulfilled};
j_response["payment_id"] = payment_table_id;
j_response["import_fee"] = std::to_string(
xmr_payment->import_fee);
j_response["new_request"] = true;
j_response["request_fulfilled"]
= bool {xmr_payment->request_fulfilled};
j_response["payment_address"] = xmr_payment->payment_address;
j_response["status"] = "Payment not yet received";
j_response["error"] = "";
string integrated_address =
current_bc_status->get_account_integrated_address_as_str(
xmr_payment.payment_id);
session_close(session, j_response);
return;
} // if (xmr_payment->id == mysqlpp::null)
j_response["payment_id"] = xmr_payment.payment_id;
j_response["import_fee"] = std::to_string(xmr_payment.import_fee);
j_response["new_request"] = false;
j_response["request_fulfilled"] = request_fulfilled;
j_response["payment_address"] = integrated_address;
j_response["status"] = "Payment not yet received";
string tx_hash_with_payment;
bool request_fulfilled = bool {xmr_payment->request_fulfilled};
string integrated_address =
current_bc_status->get_account_integrated_address_as_str(
xmr_payment->payment_id);
j_response["payment_id"] = xmr_payment->payment_id;
j_response["import_fee"] = std::to_string(xmr_payment->import_fee);
j_response["new_request"] = false;
j_response["request_fulfilled"] = request_fulfilled;
j_response["payment_address"] = integrated_address;
j_response["status"] = "Payment not yet received";
string tx_hash_with_payment;
// if payment has not yet been done
if (!request_fulfilled)
// if payment has not yet been done
if (!request_fulfilled)
{
// check if it has just been done now
// if yes, mark it in mysql
if(current_bc_status->search_if_payment_made(
xmr_payment->payment_id,
xmr_payment->import_fee,
tx_hash_with_payment))
{
// check if it has just been done now
// if yes, mark it in mysql
if(current_bc_status->search_if_payment_made(
xmr_payment.payment_id,
xmr_payment.import_fee,
tx_hash_with_payment))
XmrPayment updated_xmr_payment = *xmr_payment;
// updated values
updated_xmr_payment.request_fulfilled = true;
updated_xmr_payment.tx_hash = tx_hash_with_payment;
// save to mysql
if (xmr_accounts->update(*xmr_payment, updated_xmr_payment))
{
XmrPayment updated_xmr_payment = xmr_payment;
// updated values
updated_xmr_payment.request_fulfilled = true;
updated_xmr_payment.tx_hash = tx_hash_with_payment;
// set scanned_block_height to 0 to begin
// scanning entire blockchain
// save to mysql
if (xmr_accounts->update(xmr_payment, updated_xmr_payment))
{
XmrAccount acc;
// set scanned_block_height to 0 to begin
// scanning entire blockchain
if (xmr_accounts->select(xmr_address, acc))
{
XmrAccount updated_acc = acc;
XmrAccount acc;
updated_acc.scanned_block_height = 0;
if (xmr_accounts->select(xmr_address, acc))
if (xmr_accounts->update(acc, updated_acc))
{
XmrAccount updated_acc = acc;
// if success, set acc to updated_acc;
request_fulfilled = true;
updated_acc.scanned_block_height = 0;
if (xmr_accounts->update(acc, updated_acc))
// change search blk number in the search thread
if (!current_bc_status
->set_new_searched_blk_no(xmr_address, 0))
{
// if success, set acc to updated_acc;
request_fulfilled = true;
// change search blk number in the search thread
if (!current_bc_status
->set_new_searched_blk_no(xmr_address, 0))
{
OMERROR << xmr_address.substr(0,6) +
": updating searched_blk_no failed!\n";
j_response["error"] = "Updating searched_blk_no"
" failed!";
}
j_response["request_fulfilled"]
= request_fulfilled;
j_response["status"]
= "Payment received. Thank you.";
j_response["new_request"] = true;
j_response["error"] = "";
OMERROR << xmr_address.substr(0,6) +
": updating searched_blk_no failed!\n";
j_response["error"] = "Updating searched_blk_no"
" failed!";
}
}
else
{
OMERROR << xmr_address.substr(0,6) +
": updating accounts "
"payment db failed! \n";
j_response["error"]
= "Updating accounts "
"payment db failed!";
j_response["request_fulfilled"]
= request_fulfilled;
j_response["status"]
= "Payment received. Thank you.";
j_response["new_request"] = true;
j_response["error"] = "";
}
}
else
{
OMERROR << xmr_address.substr(0,6) +
"Updating payment db failed!\n";
j_response["error"] = "Updating payment mysql failed!";
": updating accounts "
"payment db failed! \n";
j_response["error"]
= "Updating accounts "
"payment db failed!";
}
}
else
{
OMERROR << xmr_address.substr(0,6) +
"Updating payment db failed!\n";
j_response["error"] = "Updating payment mysql failed!";
}
} // if(current_bc_status->search_if_payment_made(
} // if(current_bc_status->search_if_payment_made(
} // if (!request_fulfilled)
else
{
// if payment has been made, and we get new request to import txs
// indicate that this is new requeest, but request was fulfiled.
// front end should give proper message in this case
j_response["request_fulfilled"] = request_fulfilled;
j_response["status"] = "Wallet already imported or "
"in the progress.";
j_response["new_request"] = false;
j_response["error"] = "";
}
} // if (xmr_accounts->select_payment_by_address(xmr_address, xmr_payment))
} // if (!request_fulfilled)
else
{
// payment request is new, so create its entry in
// Payments table
uint64_t payment_table_id {0};
crypto::hash8 random_payment_id8 = crypto::rand<crypto::hash8>();
string integrated_address =
current_bc_status->get_account_integrated_address_as_str(
random_payment_id8);
XmrPayment xmr_payment;
xmr_payment.id = mysqlpp::null;
xmr_payment.account_id = acc.id.data;
xmr_payment.payment_id = pod_to_hex(random_payment_id8);
xmr_payment.import_fee = current_bc_status
->get_bc_setup().import_fee; // xmr
xmr_payment.request_fulfilled = false;
xmr_payment.tx_hash = ""; // no tx_hash yet with the payment
xmr_payment.payment_address = integrated_address;
// if payment has been made, and we get new request to import txs
// indicate that this is new requeest, but request was fulfiled.
// front end should give proper message in this case
if ((payment_table_id = xmr_accounts->insert(xmr_payment)) != 0)
{
// payment entry created
j_response["payment_id"] = payment_table_id;
j_response["import_fee"] = std::to_string(
xmr_payment.import_fee);
j_response["new_request"] = true;
j_response["request_fulfilled"]
= bool {xmr_payment.request_fulfilled};
j_response["payment_address"] = xmr_payment.payment_address;
j_response["status"] = "Payment not yet received";
j_response["error"] = "";
}
j_response["request_fulfilled"] = request_fulfilled;
j_response["status"] = "Wallet already imported or "
"in the progress.";
j_response["new_request"] = false;
j_response["error"] = "";
}
string response_body = j_response.dump();
auto response_headers = make_headers({{ "Content-Length",
std::to_string(response_body.size())}});
session->close( OK, response_body, response_headers);
session_close(session, j_response);
}
@ -1244,7 +1221,7 @@ YourMoneroRequests::import_recent_wallet_request(
if (!parse_request(body, requested_values, j_request, j_response))
{
j_response["Error"] = "Cant parse json body";
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -1259,7 +1236,7 @@ YourMoneroRequests::import_recent_wallet_request(
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -1280,7 +1257,7 @@ YourMoneroRequests::import_recent_wallet_request(
cerr << msg << '\n';
j_response["Error"] = msg;
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -1368,7 +1345,7 @@ YourMoneroRequests::get_tx(
if (!parse_request(body, requested_values, j_request, j_response))
{
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -1385,7 +1362,7 @@ YourMoneroRequests::get_tx(
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -1399,7 +1376,7 @@ YourMoneroRequests::get_tx(
{
cerr << "Cant parse tx hash! : " << tx_hash_str << '\n';
j_response["status"] = "Cant parse tx hash! : " + tx_hash_str;
session_close(session, j_response.dump());
session_close(session, j_response);
return;
}
@ -1781,7 +1758,7 @@ YourMoneroRequests::generic_options_handler(
session->fetch(content_length,
[](const shared_ptr< Session > session,
const Bytes & body)
const Bytes &)
{
session->close( OK, string{}, make_headers());
});
@ -1930,19 +1907,6 @@ YourMoneroRequests::login_and_start_search_thread(
}
void
YourMoneroRequests::session_close(
const shared_ptr< Session > session,
string response_body,
int return_code)
{
auto response_headers = make_headers({{"Content-Length",
to_string(response_body.size())}});
session->close(return_code, response_body, response_headers);
}
bool
YourMoneroRequests::parse_request(
const Bytes& body,
@ -1986,6 +1950,80 @@ YourMoneroRequests::parse_request(
}
}
boost::optional<XmrAccount>
YourMoneroRequests::select_account(
string const& xmr_address) const
{
boost::optional<XmrAccount> acc;
if (!xmr_accounts->select(xmr_address, *acc))
{
OMERROR << xmr_address.substr(0,6) +
": address does not exists!";
return acc;
}
return {};
}
boost::optional<XmrPayment>
YourMoneroRequests::select_payment(
XmrAccount const& xmr_account) const
{
vector<XmrPayment> xmr_payments;
if (!xmr_accounts->select(xmr_account.id.data,
xmr_payments))
{
OMERROR << xmr_account.address.substr(0,6) +
": address does not exists!";
return {};
}
if (xmr_payments.size() > 1)
{
OMERROR << xmr_account.address.substr(0,6) +
": more than one payment record found!";
return {};
}
// if xmr_payments is empty it means
// that the given account has no import
// paymnet record created. so new
// paymnet will be created
if (xmr_payments.empty())
{
OMINFO << xmr_account.address.substr(0,6) +
": no payment record found!";
return {XmrPayment{}};
}
return {xmr_payments.at(1)};
}
void
YourMoneroRequests::session_close(
const shared_ptr< Session > session,
json& j_response,
int return_code,
string error_msg) const
{
if (return_code != OK)
{
j_response["error"] = error_msg;
}
string response_body = j_response.dump();
auto response_headers
= make_headers({{ "Content-Length",
std::to_string(response_body.size())}});
session->close( return_code,
response_body, response_headers);
}
}

@ -12,7 +12,7 @@
#include "version.h"
#include "CurrentBlockchainStatus.h"
#include "MySqlAccounts.h"
#include "db/MySqlAccounts.h"
#include "../gen/version.h"
#include "../ext/restbed/source/restbed"
@ -147,17 +147,24 @@ private:
json& j_response);
inline void
session_close(const shared_ptr< Session > session,
string response_body,
int return_code = OK);
bool
parse_request(const Bytes& body,
vector<string>& values_map,
json& j_request,
json& j_response);
boost::optional<XmrAccount>
select_account(string const& xmr_address) const;
boost::optional<XmrPayment>
select_payment(XmrAccount const& xmr_account) const;
void
session_close(
const shared_ptr< Session > session,
json& j_response,
int return_code = OK,
string error_msg = "") const;
};

@ -1,140 +0,0 @@
//
// Created by mwo on 7/01/17.
//
#include "ssqlses.h"
namespace xmreg
{
ostream& operator<< (std::ostream& os, const Table& data)
{
os << data.table_name() << ": " << data.to_json().dump() << '\n';
return os;
};
json
XmrAccount::to_json() const
{
json j {{"id" , id.data},
{"address" , address},
{"viewkey" , viewkey},
{"scanned_block_height" , scanned_block_height},
{"scanned_block_timestamp", static_cast<uint64_t>(scanned_block_timestamp)},
{"start_height" , start_height}
};
return j;
}
json
XmrTransaction::to_json() const
{
json j {{"id" , id.data},
{"hash" , hash},
{"prefix_hash" , prefix_hash},
{"tx_pub_key" , tx_pub_key},
{"account_id" , account_id},
{"total_received" , total_received},
{"total_sent" , total_sent},
{"height" , height},
{"payment_id" , payment_id},
{"unlock_time" , unlock_time},
{"coinbase" , bool {coinbase}},
{"is_rct" , bool {is_rct}},
{"rct_type" , rct_type},
{"spendable" , bool {spendable}},
{"mixin" , mixin},
{"timestamp" , static_cast<uint64_t>(timestamp)}
};
return j;
}
DateTime
XmrTransaction::timestamp_to_DateTime(time_t timestamp)
{
return DateTime(timestamp);
}
ostream& operator<< (std::ostream& os, const XmrTransaction& acc)
{
os << "XmrTransactions: " << acc.to_json().dump() << '\n';
return os;
};
json
XmrOutput::to_json() const
{
json j {{"id" , id.data},
{"account_id" , account_id},
{"tx_id" , tx_id},
{"out_pub_key" , out_pub_key},
{"tx_pub_key" , tx_pub_key},
{"amount" , amount},
{"global_index" , global_index},
{"out_index" , out_index},
{"mixin" , mixin},
{"timestamp" , static_cast<uint64_t>(timestamp)}
};
return j;
}
ostream& operator<< (std::ostream& os, const XmrOutput& out) {
os << "XmrOutputs: " << out.to_json().dump() << '\n';
return os;
};
json
XmrInput::to_json() const
{
json j {{"id" , id.data},
{"account_id" , account_id},
{"tx_id" , tx_id},
{"output_id" , output_id},
{"key_image" , key_image},
{"amount" , amount},
{"timestamp" , static_cast<uint64_t>(timestamp)}
};
return j;
}
ostream& operator<< (std::ostream& os, const XmrInput& out)
{
os << "XmrInput: " << out.to_json().dump() << '\n';
return os;
};
json
XmrPayment::to_json() const
{
json j {{"id" , id.data},
{"account_id" , account_id},
{"payment_id" , payment_id},
{"tx_hash" , tx_hash},
{"request_fulfilled", bool {request_fulfilled}},
{"import_fee" , import_fee},
{"payment_address" , payment_address},
};
return j;
}
ostream& operator<< (std::ostream& os, const XmrPayment& out) {
os << "XmrPayment: " << out.to_json().dump() << '\n';
return os;
};
}

@ -1,329 +0,0 @@
//
// Created by mwo on 14/12/16.
//
#ifndef RESTBED_XMR_SSQLSES_H
#define RESTBED_XMR_SSQLSES_H
#include "../ext/json.hpp"
#include <mysql++/mysql++.h>
#include <mysql++/ssqls.h>
namespace xmreg
{
using namespace std;
using namespace nlohmann;
using namespace mysqlpp;
/**
* Base class for all mysql table based classes that we use.
*/
class Table
{
public:
virtual string table_name() const = 0;
virtual json to_json() const = 0;
friend std::ostream& operator<< (std::ostream& stream, const Table& data);
};
sql_create_8(Accounts, 1, 6,
sql_bigint_unsigned_null, id,
sql_varchar , address,
sql_char , viewkey_hash,
sql_bigint_unsigned, scanned_block_height,
sql_timestamp , scanned_block_timestamp,
sql_bigint_unsigned, start_height,
sql_timestamp , created,
sql_timestamp , modified);
struct XmrAccount : public Accounts, Table
{
static constexpr const char* SELECT_STMT = R"(
SELECT * FROM `Accounts` WHERE `id` = (%0q)
)";
static constexpr const char* SELECT_STMT2 = R"(
SELECT * FROM `Accounts` WHERE `address` = (%0q)
)";
// SELECT_STMT3 same as SELECT_STMT which is fine
// easier to work with templates later
static constexpr const char* SELECT_STMT3 = R"(
SELECT * FROM `Accounts` WHERE `id` = (%0q)
)";
static constexpr const char* INSERT_STMT = R"(
INSERT INTO `Accounts` (`address`, `viewkey_hash`,
`scanned_block_height`,
`scanned_block_timestamp`, `start_height`)
VALUES
(%0q, %1q, %2q, %3q, %4q);
)";
using Accounts::Accounts;
// viewkey is not stored in mysql db or anywhere
// so need to be populated when user logs in.
string viewkey;
string table_name() const override { return this->table();};
json to_json() const override;
};
sql_create_17(Transactions, 1, 17,
sql_bigint_unsigned_null, id,
sql_varchar , hash,
sql_varchar , prefix_hash,
sql_varchar , tx_pub_key,
sql_bigint_unsigned , account_id,
sql_bigint_unsigned , blockchain_tx_id,
sql_bigint_unsigned , total_received,
sql_bigint_unsigned , total_sent,
sql_bigint_unsigned , unlock_time,
sql_bigint_unsigned , height,
sql_bool , coinbase,
sql_bool , is_rct,
sql_int , rct_type,
sql_bool , spendable,
sql_varchar , payment_id,
sql_bigint_unsigned , mixin,
sql_timestamp , timestamp);
struct XmrTransaction : public Transactions, Table
{
static constexpr const char* SELECT_STMT = R"(
SELECT * FROM `Transactions` WHERE `account_id` = (%0q)
)";
static constexpr const char* SELECT_STMT2 = R"(
SELECT * FROM `Transactions` WHERE `id` = (%0q)
)";
// same as SELECT_STMT2 for similicity later on
static constexpr const char* SELECT_STMT3 = R"(
SELECT * FROM `Transactions` WHERE `id` = (%0q)
)";
static constexpr const char* EXIST_STMT = R"(
SELECT * FROM `Transactions` WHERE `account_id` = (%0q) AND `hash` = (%1q)
)";
static constexpr const char* DELETE_STMT = R"(
DELETE FROM `Transactions` WHERE `id` = (%0q)
)";
static constexpr const char* INSERT_STMT = R"(
INSERT IGNORE INTO `Transactions` (`hash`, `prefix_hash`, `tx_pub_key`, `account_id`,
`blockchain_tx_id`,
`total_received`, `total_sent`, `unlock_time`,
`height`, `coinbase`, `is_rct`, `rct_type`,
`spendable`,
`payment_id`, `mixin`, `timestamp`)
VALUES (%0q, %1q, %2q, %3q,
%4q,
%5q, %6q, %7q,
%8q, %9q, %10q, %11q,
%12q,
%13q, %14q, %15q);
)";
static constexpr const char* MARK_AS_SPENDABLE_STMT = R"(
UPDATE `Transactions` SET `spendable` = 1, `timestamp` = CURRENT_TIMESTAMP
WHERE `id` = %0q;
)";
static constexpr const char* MARK_AS_NONSPENDABLE_STMT = R"(
UPDATE `Transactions` SET `spendable` = 0, `timestamp` = CURRENT_TIMESTAMP
WHERE `id` = %0q;
)";
static constexpr const char* SUM_XMR_RECIEVED = R"(
SELECT SUM(`total_received`) AS total_received
FROM `Transactions`
WHERE `account_id` = %0q
GROUP BY `account_id`
)";
using Transactions::Transactions;
static DateTime
timestamp_to_DateTime(time_t timestamp);
string table_name() const override { return this->table();};
json to_json() const override;
};
sql_create_13(Outputs, 1, 13,
sql_bigint_unsigned_null, id, // this is null so that we can set it to mysqlpp:null when inserting rows
sql_bigint_unsigned, account_id, // this way auto_increment of the id will take place and we can
sql_bigint_unsigned, tx_id, // use vector of outputs to write at once to mysql
sql_varchar , out_pub_key,
sql_varchar , rct_outpk,
sql_varchar , rct_mask,
sql_varchar , rct_amount,
sql_varchar , tx_pub_key,
sql_bigint_unsigned, amount,
sql_bigint_unsigned, global_index,
sql_bigint_unsigned, out_index,
sql_bigint_unsigned, mixin,
sql_timestamp , timestamp);
struct XmrOutput : public Outputs, Table
{
static constexpr const char* SELECT_STMT = R"(
SELECT * FROM `Outputs` WHERE `account_id` = (%0q)
)";
static constexpr const char* SELECT_STMT2 = R"(
SELECT * FROM `Outputs` WHERE `tx_id` = (%0q)
)";
static constexpr const char* SELECT_STMT3 = R"(
SELECT * FROM `Outputs` WHERE `id` = (%0q)
)";
static constexpr const char* EXIST_STMT = R"(
SELECT * FROM `Outputs` WHERE `out_pub_key` = (%0q)
)";
static constexpr const char* INSERT_STMT = R"(
INSERT IGNORE INTO `Outputs` (`account_id`, `tx_id`, `out_pub_key`,
`tx_pub_key`,
`rct_outpk`, `rct_mask`, `rct_amount`,
`amount`, `global_index`,
`out_index`, `mixin`, `timestamp`)
VALUES (%0q, %1q, %2q,
%3q,
%4q, %5q, %6q,
%7q, %8q,
%9q, %10q, %11q);
)";
using Outputs::Outputs;
string
get_rct() const
{
return rct_outpk + rct_mask + rct_amount;
}
string table_name() const override { return this->table();};
json to_json() const override;
};
sql_create_7(Inputs, 1, 7,
sql_bigint_unsigned_null, id,
sql_bigint_unsigned , account_id,
sql_bigint_unsigned , tx_id,
sql_bigint_unsigned , output_id,
sql_varchar , key_image,
sql_bigint_unsigned , amount,
sql_timestamp , timestamp);
struct XmrInput : public Inputs, Table
{
static constexpr const char* SELECT_STMT = R"(
SELECT * FROM `Inputs` WHERE `account_id` = (%0q)
)";
static constexpr const char* SELECT_STMT2 = R"(
SELECT * FROM `Inputs` WHERE `tx_id` = (%0q)
)";
static constexpr const char* SELECT_STMT3 = R"(
SELECT * FROM `Inputs` WHERE `id` = (%0q)
)";
static constexpr const char* SELECT_STMT4 = R"(
SELECT * FROM `Inputs` WHERE `output_id` = (%0q)
)";
static constexpr const char* INSERT_STMT = R"(
INSERT IGNORE INTO `Inputs` (`account_id`, `tx_id`, `output_id`,
`key_image`, `amount` , `timestamp`)
VALUES (%0q, %1q, %2q,
%3q, %4q, %5q);
)";
using Inputs::Inputs;
string table_name() const override { return this->table();};
json to_json() const override;
};
sql_create_9(Payments, 1, 7,
sql_bigint_unsigned_null, id,
sql_bigint_unsigned , account_id,
sql_varchar , payment_id,
sql_varchar , tx_hash,
sql_boolean , request_fulfilled,
sql_bigint_unsigned , import_fee,
sql_varchar , payment_address,
sql_timestamp , created,
sql_timestamp , modified);
struct XmrPayment : public Payments, Table
{
static constexpr const char* SELECT_STMT = R"(
SELECT * FROM `Payments` WHERE `account_id` = (%0q)
)";
static constexpr const char* SELECT_STMT2 = R"(
SELECT * FROM `Payments` WHERE `payment_id` = (%0q)
)";
static constexpr const char* SELECT_STMT3 = R"(
SELECT * FROM `Payments` WHERE `id` = (%0q)
)";
static constexpr const char* INSERT_STMT = R"(
INSERT IGNORE INTO `Payments` (`account_id`, `payment_id`, `tx_hash`,
`request_fulfilled`, `import_fee`,
`payment_address`)
VALUES (%0q, %1q, %2q, %3q, %4q, %5q);
)";
using Payments::Payments;
string table_name() const override { return this->table();};
json to_json() const override;
};
}
#endif //RESTBED_XMR_SSQLSES_H

@ -4,7 +4,7 @@
#include "../src/MicroCore.h"
#include "../src/YourMoneroRequests.h"
#include "../src/MysqlPing.h"
#include "../src/db/MysqlPing.h"
//#include "chaingen.h"
//#include "chaingen_tests_list.h"
@ -336,6 +336,8 @@ TEST_F(MYSQL_TEST, InsertAndGetAccount)
bool is_success = xmr_accounts->select(xmr_addr, acc);
ASSERT_TRUE(is_success);
EXPECT_EQ(acc.id.data, expected_primary_id);
EXPECT_EQ(acc.scanned_block_height, mock_current_blockchain_height);
EXPECT_EQ(acc.scanned_block_timestamp, mock_current_blockchain_timestamp);
@ -1100,7 +1102,7 @@ make_mock_payment_data(string last_char_pub_key = "0")
mock_data.import_fee = 10000000010ull; // xmr
mock_data.request_fulfilled = false;
mock_data.tx_hash = ""; // no tx_hash yet with the payment
mock_data.payment_address = "5DUWE29P72Eb8inMa41HuNJG4tj9CcaNKGr6EVSbvhWGJdpDQCiNNYBUNF1oDb8BczU5aD68d3HNKXaEsPq8cvbQLK4Tiiy";
mock_data.payment_address = "5DUWE29P72Eb8inMa41HuNJG4tj9CcaNKGr6EVSbvhWGJdpDQCiNNYBUNF1oDb8BczU5aD68d3HNKXaEsPq8cvbQLGi6vcb2zkW7mhsWor";
return mock_data;
}

Loading…
Cancel
Save