still some proplem qith ssqlses.h

pull/1/head
moneroexamples 8 years ago
parent d82ac19546
commit ea6dce4292

@ -1,11 +1,6 @@
#include "src/CmdLineOptions.h" #include "src/CmdLineOptions.h"
#include "src/MicroCore.h" #include "src/MicroCore.h"
#include "src/MySqlAccounts.h"
#include "src/YourMoneroRequests.h" #include "src/YourMoneroRequests.h"
#include "src/tools.h"
#include "ext/restbed/source/restbed"
#include <iostream> #include <iostream>
#include <memory> #include <memory>
@ -31,9 +26,9 @@ xmreg::CmdLineOptions opts {ac, av};
auto address_opt = opts.get_option<string>("address"); auto address_opt = opts.get_option<string>("address");
auto viewkey_opt = opts.get_option<string>("viewkey"); auto viewkey_opt = opts.get_option<string>("viewkey");
auto help_opt = opts.get_option<bool>("help"); auto help_opt = opts.get_option<bool>("help");
auto testnet_opt = opts.get_option<bool>("testnet"); auto testnet_opt = opts.get_option<bool>("testnet");
auto use_ssl_opt = opts.get_option<bool>("use-ssl"); auto use_ssl_opt = opts.get_option<bool>("use-ssl");
// if help was chosen, display help text and finish // if help was chosen, display help text and finish
if (*help_opt) if (*help_opt)
@ -48,11 +43,11 @@ string address_str = address_opt ? *address_opt : "";
string viewkey_str = viewkey_opt ? *viewkey_opt : ""; string viewkey_str = viewkey_opt ? *viewkey_opt : "";
auto port_opt = opts.get_option<string>("port"); auto port_opt = opts.get_option<string>("port");
auto bc_path_opt = opts.get_option<string>("bc-path"); auto bc_path_opt = opts.get_option<string>("bc-path");
//cast port number in string to uint16 //cast port number in string to uint16
uint16_t app_port = boost::lexical_cast<uint16_t>(*port_opt); uint16_t app_port = boost::lexical_cast<uint16_t>(*port_opt);
// get blockchain path // get blockchain path
path blockchain_path; path blockchain_path;
@ -75,9 +70,9 @@ xmreg::MySqlConnector::dbname = "openmonero";
xmreg::CurrentBlockchainStatus::set_blockchain_path(blockchain_path.string()); xmreg::CurrentBlockchainStatus::set_blockchain_path(blockchain_path.string());
xmreg::CurrentBlockchainStatus::set_testnet(testnet); xmreg::CurrentBlockchainStatus::set_testnet(testnet);
xmreg::CurrentBlockchainStatus::refresh_block_status_every_seconds = 60; xmreg::CurrentBlockchainStatus::refresh_block_status_every_seconds = 60;
xmreg::CurrentBlockchainStatus::import_payment_address = address_str; xmreg::CurrentBlockchainStatus::import_payment_address = address_str;
xmreg::CurrentBlockchainStatus::import_payment_viewkey = viewkey_str; xmreg::CurrentBlockchainStatus::import_payment_viewkey = viewkey_str;
xmreg::CurrentBlockchainStatus::import_fee = 0.01e12; xmreg::CurrentBlockchainStatus::import_fee = static_cast<uint64_t>(0.01e12);
// since CurrentBlockchainStatus class monitors current status // since CurrentBlockchainStatus class monitors current status
// of the blockchain (e.g, current height), its seems logical to // of the blockchain (e.g, current height), its seems logical to
@ -124,11 +119,11 @@ auto get_unspent_outs = your_xmr.make_resource(
&xmreg::YourMoneroRequests::get_unspent_outs, &xmreg::YourMoneroRequests::get_unspent_outs,
"/get_unspent_outs"); "/get_unspent_outs");
auto get_random_outs = your_xmr.make_resource( auto get_random_outs = your_xmr.make_resource(
&xmreg::YourMoneroRequests::get_random_outs, &xmreg::YourMoneroRequests::get_random_outs,
"/get_random_outs"); "/get_random_outs");
auto submit_raw_tx = your_xmr.make_resource( auto submit_raw_tx = your_xmr.make_resource(
&xmreg::YourMoneroRequests::submit_raw_tx, &xmreg::YourMoneroRequests::submit_raw_tx,
"/submit_raw_tx"); "/submit_raw_tx");

@ -5,10 +5,10 @@ project(myxrm)
set(SOURCE_FILES set(SOURCE_FILES
MicroCore.cpp MicroCore.cpp
tools.cpp tools.cpp
CmdLineOptions.cpp MySqlConnector.h CmdLineOptions.cpp
CurrentBlockchainStatus.h CurrentBlockchainStatus.cpp
ssqlses.h MySqlConnector.cpp
MySqlAccounts.h) MySqlAccounts.cpp)
# make static library called libmyxrm # make static library called libmyxrm
# that we are going to link to # that we are going to link to

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -8,408 +8,408 @@
namespace namespace
{ {
// NOTE: These values should match blockchain.cpp // NOTE: These values should match blockchain.cpp
// TODO: Refactor // TODO: Refactor
const uint64_t mainnet_hard_fork_version_1_till = 1009826; const uint64_t mainnet_hard_fork_version_1_till = 1009826;
const uint64_t testnet_hard_fork_version_1_till = 624633; const uint64_t testnet_hard_fork_version_1_till = 624633;
} }
namespace xmreg namespace xmreg
{ {
/** /**
* The constructor is interesting, as * The constructor is interesting, as
* m_mempool and m_blockchain_storage depend * m_mempool and m_blockchain_storage depend
* on each other. * on each other.
* *
* So basically m_mempool is initialized with * So basically m_mempool is initialized with
* reference to Blockchain (i.e., Blockchain&) * reference to Blockchain (i.e., Blockchain&)
* and m_blockchain_storage is initialized with * and m_blockchain_storage is initialized with
* reference to m_mempool (i.e., tx_memory_pool&) * reference to m_mempool (i.e., tx_memory_pool&)
* *
* The same is done in cryptonode::core. * The same is done in cryptonode::core.
*/ */
MicroCore::MicroCore(): MicroCore::MicroCore():
m_mempool(m_blockchain_storage), m_mempool(m_blockchain_storage),
m_blockchain_storage(m_mempool) m_blockchain_storage(m_mempool)
{} {}
/** /**
* Initialized the MicroCore object. * Initialized the MicroCore object.
* *
* Create BlockchainLMDB on the heap. * Create BlockchainLMDB on the heap.
* Open database files located in blockchain_path. * Open database files located in blockchain_path.
* Initialize m_blockchain_storage with the BlockchainLMDB object. * Initialize m_blockchain_storage with the BlockchainLMDB object.
*/ */
bool bool
MicroCore::init(const string& _blockchain_path) MicroCore::init(const string& _blockchain_path)
{ {
int db_flags = 0; int db_flags = 0;
blockchain_path = _blockchain_path;
//db_flags |= MDB_RDONLY; blockchain_path = _blockchain_path;
db_flags |= MDB_NOLOCK;
//db_flags |= MDB_SYNC;
// uint64_t DEFAULT_FLAGS = MDB_NOMETASYNC | MDB_NORDAHEAD; //db_flags |= MDB_RDONLY;
db_flags |= MDB_NOLOCK;
//db_flags |= MDB_SYNC;
//db_flags = DEFAULT_FLAGS; // uint64_t DEFAULT_FLAGS = MDB_NOMETASYNC | MDB_NORDAHEAD;
HardFork* m_hardfork = nullptr; //db_flags = DEFAULT_FLAGS;
BlockchainDB* db = nullptr; HardFork* m_hardfork = nullptr;
db = new BlockchainLMDB();
bool use_testnet {false}; BlockchainDB* db = nullptr;
db = new BlockchainLMDB();
uint64_t hard_fork_version_1_till = use_testnet ? testnet_hard_fork_version_1_till : mainnet_hard_fork_version_1_till; bool use_testnet {false};
m_hardfork = new HardFork(*db, 1, hard_fork_version_1_till); uint64_t hard_fork_version_1_till = use_testnet ? testnet_hard_fork_version_1_till : mainnet_hard_fork_version_1_till;
try m_hardfork = new HardFork(*db, 1, hard_fork_version_1_till);
{
// try opening lmdb database files
db->open(blockchain_path, db_flags);
}
catch (const std::exception& e)
{
cerr << "Error opening database: " << e.what();
return false;
}
// check if the blockchain database
// is successful opened
if(!db->is_open())
{
return false;
}
// initialize Blockchain object to manage try
// the database. {
return m_blockchain_storage.init(db, m_hardfork, false); // try opening lmdb database files
db->open(blockchain_path, db_flags);
} }
catch (const std::exception& e)
/**
* Get m_blockchain_storage.
* Initialize m_blockchain_storage with the BlockchainLMDB object.
*/
Blockchain&
MicroCore::get_core()
{ {
return m_blockchain_storage; cerr << "Error opening database: " << e.what();
return false;
} }
/** // check if the blockchain database
* Get block by its height // is successful opened
* if(!db->is_open())
* returns true if success
*/
bool
MicroCore::get_block_by_height(const uint64_t& height, block& blk)
{ {
return false;
}
crypto::hash block_id; // initialize Blockchain object to manage
// the database.
return m_blockchain_storage.init(db, m_hardfork, false);
}
try /**
{ * Get m_blockchain_storage.
block_id = m_blockchain_storage.get_block_id_by_height(height); * Initialize m_blockchain_storage with the BlockchainLMDB object.
} */
catch (const exception& e) Blockchain&
{ MicroCore::get_core()
cerr << e.what() << endl; {
return false; return m_blockchain_storage;
} }
/**
* Get block by its height
*
* returns true if success
*/
bool
MicroCore::get_block_by_height(const uint64_t& height, block& blk)
{
if (!m_blockchain_storage.get_block_by_hash(block_id, blk)) crypto::hash block_id;
{
cerr << "Block with hash " << block_id
<< "and height " << height << " not found!"
<< endl;
return false;
}
return true; try
{
block_id = m_blockchain_storage.get_block_id_by_height(height);
} }
catch (const exception& e)
bool
MicroCore::get_block_from_height(const uint64_t& height, block& blk)
{ {
cerr << e.what() << endl;
return false;
}
crypto::hash block_id;
try if (!m_blockchain_storage.get_block_by_hash(block_id, blk))
{ {
blk = m_blockchain_storage.get_db().get_block_from_height(height); cerr << "Block with hash " << block_id
} << "and height " << height << " not found!"
catch (const exception& e) << endl;
{ return false;
cerr << e.what() << endl;
return false;
}
return true;
} }
return true;
}
/** bool
* Get transaction tx from the blockchain using it hash MicroCore::get_block_from_height(const uint64_t& height, block& blk)
*/ {
bool
MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx)
{
if (m_blockchain_storage.have_tx(tx_hash))
{
// get transaction with given hash
tx = m_blockchain_storage.get_db().get_tx(tx_hash);
}
else
{
cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl;
return false;
}
crypto::hash block_id;
return true; try
{
blk = m_blockchain_storage.get_db().get_block_from_height(height);
} }
catch (const exception& e)
bool
MicroCore::get_tx(const string& tx_hash_str, transaction& tx)
{ {
cerr << e.what() << endl;
return false;
}
// parse tx hash string to hash object return true;
crypto::hash tx_hash; }
if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash))
{
cerr << "Cant parse tx hash: " << tx_hash_str << endl;
return false;
}
if (!get_tx(tx_hash, tx))
{
return false;
}
return true; /**
* Get transaction tx from the blockchain using it hash
*/
bool
MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx)
{
if (m_blockchain_storage.have_tx(tx_hash))
{
// get transaction with given hash
tx = m_blockchain_storage.get_db().get_tx(tx_hash);
} }
else
{
cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl;
return false;
}
return true;
}
bool
MicroCore::get_tx(const string& tx_hash_str, transaction& tx)
{
// parse tx hash string to hash object
crypto::hash tx_hash;
/** if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash))
* Find output with given public key in a given transaction
*/
bool
MicroCore::find_output_in_tx(const transaction& tx,
const public_key& output_pubkey,
tx_out& out,
size_t& output_index)
{ {
cerr << "Cant parse tx hash: " << tx_hash_str << endl;
return false;
}
size_t idx {0};
if (!get_tx(tx_hash, tx))
{
return false;
}
// search in the ouputs for an output which
// public key matches to what we want
auto it = std::find_if(tx.vout.begin(), tx.vout.end(),
[&](const tx_out& o)
{
const txout_to_key& tx_in_to_key
= boost::get<txout_to_key>(o.target);
++idx; return true;
}
return tx_in_to_key.key == output_pubkey;
});
if (it != tx.vout.end())
{
// we found the desired public key
out = *it;
output_index = idx > 0 ? idx - 1 : idx;
//cout << idx << " " << output_index << endl;
return true; /**
} * Find output with given public key in a given transaction
*/
bool
MicroCore::find_output_in_tx(const transaction& tx,
const public_key& output_pubkey,
tx_out& out,
size_t& output_index)
{
return false; size_t idx {0};
}
/** // search in the ouputs for an output which
* Returns tx hash in a given block which // public key matches to what we want
* contains given output's public key auto it = std::find_if(tx.vout.begin(), tx.vout.end(),
*/ [&](const tx_out& o)
bool {
MicroCore::get_tx_hash_from_output_pubkey(const public_key& output_pubkey, const txout_to_key& tx_in_to_key
const uint64_t& block_height, = boost::get<txout_to_key>(o.target);
crypto::hash& tx_hash,
cryptonote::transaction& tx_found)
{
tx_hash = null_hash; ++idx;
// get block of given height return tx_in_to_key.key == output_pubkey;
block blk; });
if (!get_block_by_height(block_height, blk))
{
cerr << "Cant get block of height: " << block_height << endl;
return false;
}
if (it != tx.vout.end())
{
// we found the desired public key
out = *it;
output_index = idx > 0 ? idx - 1 : idx;
// get all transactions in the block found //cout << idx << " " << output_index << endl;
// initialize the first list with transaction for solving
// the block i.e. coinbase.
list<transaction> txs {blk.miner_tx};
list<crypto::hash> missed_txs;
if (!m_blockchain_storage.get_transactions(blk.tx_hashes, txs, missed_txs)) return true;
{ }
cerr << "Cant find transcations in block: " << block_height << endl;
return false;
}
if (!missed_txs.empty()) return false;
{ }
cerr << "Transactions not found in blk: " << block_height << endl;
for (const crypto::hash& h : missed_txs)
{
cerr << " - tx hash: " << h << endl;
}
return false; /**
} * Returns tx hash in a given block which
* contains given output's public key
*/
bool
MicroCore::get_tx_hash_from_output_pubkey(const public_key& output_pubkey,
const uint64_t& block_height,
crypto::hash& tx_hash,
cryptonote::transaction& tx_found)
{
tx_hash = null_hash;
// search outputs in each transactions // get block of given height
// until output with pubkey of interest is found block blk;
for (const transaction& tx : txs) if (!get_block_by_height(block_height, blk))
{ {
cerr << "Cant get block of height: " << block_height << endl;
return false;
}
tx_out found_out;
// we dont need here output_index // get all transactions in the block found
size_t output_index; // initialize the first list with transaction for solving
// the block i.e. coinbase.
list<transaction> txs {blk.miner_tx};
list<crypto::hash> missed_txs;
if (find_output_in_tx(tx, output_pubkey, found_out, output_index)) if (!m_blockchain_storage.get_transactions(blk.tx_hashes, txs, missed_txs))
{ {
// we found the desired public key cerr << "Cant find transcations in block: " << block_height << endl;
tx_hash = get_transaction_hash(tx); return false;
tx_found = tx; }
return true; if (!missed_txs.empty())
} {
cerr << "Transactions not found in blk: " << block_height << endl;
for (const crypto::hash& h : missed_txs)
{
cerr << " - tx hash: " << h << endl;
} }
return false; return false;
} }
uint64_t // search outputs in each transactions
MicroCore::get_blk_timestamp(uint64_t blk_height) // until output with pubkey of interest is found
for (const transaction& tx : txs)
{ {
cryptonote::block blk;
if (!get_block_by_height(blk_height, blk)) tx_out found_out;
// we dont need here output_index
size_t output_index;
if (find_output_in_tx(tx, output_pubkey, found_out, output_index))
{ {
cerr << "Cant get block by height: " << blk_height << endl; // we found the desired public key
return 0; tx_hash = get_transaction_hash(tx);
tx_found = tx;
return true;
} }
return blk.timestamp;
} }
return false;
}
/** uint64_t
* De-initialized Blockchain. MicroCore::get_blk_timestamp(uint64_t blk_height)
* {
* since blockchain is opened as MDB_RDONLY cryptonote::block blk;
* need to manually free memory taken on heap
* by BlockchainLMDB if (!get_block_by_height(blk_height, blk))
*/
MicroCore::~MicroCore()
{ {
delete &m_blockchain_storage.get_db(); cerr << "Cant get block by height: " << blk_height << endl;
return 0;
} }
return blk.timestamp;
}
bool
init_blockchain(const string& path,
MicroCore& mcore,
Blockchain*& core_storage)
{
// initialize the core using the blockchain path /**
if (!mcore.init(path)) * De-initialized Blockchain.
{ *
cerr << "Error accessing blockchain." << endl; * since blockchain is opened as MDB_RDONLY
return false; * need to manually free memory taken on heap
} * by BlockchainLMDB
*/
MicroCore::~MicroCore()
{
delete &m_blockchain_storage.get_db();
}
// get the high level Blockchain object to interact
// with the blockchain lmdb database
core_storage = &(mcore.get_core());
return true; bool
} init_blockchain(const string& path,
MicroCore& mcore,
Blockchain*& core_storage)
{
string // initialize the core using the blockchain path
MicroCore::get_blkchain_path() if (!mcore.init(path))
{ {
return blockchain_path; cerr << "Error accessing blockchain." << endl;
return false;
} }
// get the high level Blockchain object to interact
// with the blockchain lmdb database
core_storage = &(mcore.get_core());
return true;
}
// this is not finished! string
bool MicroCore::get_blkchain_path()
MicroCore::get_random_outs_for_amounts(const uint64_t& amount, {
const uint64_t& no_of_outputs, return blockchain_path;
vector<pair<uint64_t, public_key>>& found_outputs) }
{
uint64_t total_number_of_outputs = m_blockchain_storage.get_db().get_num_outputs(amount);
// ensure we don't include outputs that aren't yet eligible to be used // this is not finished!
// outpouts are sorted by height bool
while (total_number_of_outputs > 0) MicroCore::get_random_outs_for_amounts(const uint64_t& amount,
{ const uint64_t& no_of_outputs,
const tx_out_index toi = m_blockchain_storage.get_db() vector<pair<uint64_t, public_key>>& found_outputs)
.get_output_tx_and_index(amount, total_number_of_outputs - 1); {
const uint64_t height = m_blockchain_storage.get_db().get_tx_block_height(toi.first); uint64_t total_number_of_outputs = m_blockchain_storage.get_db().get_num_outputs(amount);
if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_blockchain_storage.get_db().height())
break;
--total_number_of_outputs; // ensure we don't include outputs that aren't yet eligible to be used
} // outpouts are sorted by height
while (total_number_of_outputs > 0)
{
const tx_out_index toi = m_blockchain_storage.get_db()
.get_output_tx_and_index(amount, total_number_of_outputs - 1);
const uint64_t height = m_blockchain_storage.get_db().get_tx_block_height(toi.first);
std::unordered_set<uint64_t> seen_indices; if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_blockchain_storage.get_db().height())
break;
// for each amount that we need to get mixins for, get <n> random outputs --total_number_of_outputs;
// from BlockchainDB where <n> is req.outs_count (number of mixins). }
for (uint64_t i = 0; i < no_of_outputs; ++i)
{
}
return false; std::unordered_set<uint64_t> seen_indices;
// for each amount that we need to get mixins for, get <n> random outputs
// from BlockchainDB where <n> is req.outs_count (number of mixins).
for (uint64_t i = 0; i < no_of_outputs; ++i)
{
} }
return false;
}
} }

@ -13,87 +13,87 @@
namespace xmreg namespace xmreg
{ {
using namespace cryptonote; using namespace cryptonote;
using namespace crypto; using namespace crypto;
using namespace std; using namespace std;
/** /**
* Micro version of cryptonode::core class * Micro version of cryptonode::core class
* Micro version of constructor, * Micro version of constructor,
* init and destructor are implemted. * init and destructor are implemted.
* *
* Just enough to read the blockchain * Just enough to read the blockchain
* database for use in the example. * database for use in the example.
*/ */
class MicroCore { class MicroCore {
string blockchain_path; string blockchain_path;
tx_memory_pool m_mempool; tx_memory_pool m_mempool;
Blockchain m_blockchain_storage; Blockchain m_blockchain_storage;
public: public:
MicroCore(); MicroCore();
bool bool
init(const string& _blockchain_path); init(const string& _blockchain_path);
Blockchain& Blockchain&
get_core(); get_core();
bool bool
get_block_by_height(const uint64_t& height, block& blk); get_block_by_height(const uint64_t& height, block& blk);
bool bool
get_block_from_height(const uint64_t& height, block& blk); get_block_from_height(const uint64_t& height, block& blk);
bool bool
get_tx(const crypto::hash& tx_hash, transaction& tx); get_tx(const crypto::hash& tx_hash, transaction& tx);
bool bool
get_tx(const string& tx_hash, transaction& tx); get_tx(const string& tx_hash, transaction& tx);
bool bool
find_output_in_tx(const transaction& tx, find_output_in_tx(const transaction& tx,
const public_key& output_pubkey, const public_key& output_pubkey,
tx_out& out, tx_out& out,
size_t& output_index); size_t& output_index);
bool bool
get_tx_hash_from_output_pubkey(const public_key& output_pubkey, get_tx_hash_from_output_pubkey(const public_key& output_pubkey,
const uint64_t& block_height, const uint64_t& block_height,
crypto::hash& tx_hash, crypto::hash& tx_hash,
transaction& tx_found); transaction& tx_found);
uint64_t uint64_t
get_blk_timestamp(uint64_t blk_height); get_blk_timestamp(uint64_t blk_height);
string string
get_blkchain_path(); get_blkchain_path();
bool bool
get_random_outs_for_amounts(const uint64_t& amount, get_random_outs_for_amounts(const uint64_t& amount,
const uint64_t& no_of_outputs, const uint64_t& no_of_outputs,
vector<pair<uint64_t, public_key>>& found_outputs); vector<pair<uint64_t, public_key>>& found_outputs);
virtual ~MicroCore(); virtual ~MicroCore();
}; };
bool bool
init_blockchain(const string& path, init_blockchain(const string& path,
MicroCore& mcore, MicroCore& mcore,
Blockchain*& core_storage); Blockchain*& core_storage);

@ -0,0 +1,921 @@
//
// Created by mwo on 7/01/17.
//
#include "MySqlAccounts.h"
#include "ssqlses.h"
namespace xmreg
{
MysqlTransactionWithOutsAndIns::MysqlTransactionWithOutsAndIns(shared_ptr<MySqlConnector> _conn)
: conn{_conn}
{}
bool
MysqlTransactionWithOutsAndIns::select(
const uint64_t &address_id,
vector<XmrTransactionWithOutsAndIns>& txs)
{
Query query = conn->query(XmrTransactionWithOutsAndIns::SELECT_STMT);
query.parse();
try
{
query.storein(txs, address_id);
if (!txs.empty())
{
return true;
}
}
catch (mysqlpp::Exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool
MysqlTransactionWithOutsAndIns::select_for_tx(
const uint64_t &tx_id,
vector<XmrTransactionWithOutsAndIns>& txs)
{
Query query = conn->query(XmrTransactionWithOutsAndIns::SELECT_STMT2);
query.parse();
try
{
query.storein(txs, tx_id);
if (!txs.empty())
{
return true;
}
}
catch (mysqlpp::Exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
MysqlInputs::MysqlInputs(shared_ptr<MySqlConnector> _conn): conn {_conn}
{}
bool
MysqlInputs::select(const uint64_t& address_id, vector<XmrInput>& ins)
{
Query query = conn->query(XmrInput::SELECT_STMT);
query.parse();
try
{
query.storein(ins, address_id);
if (!ins.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool
MysqlInputs::select_for_tx(const uint64_t& address_id, vector<XmrInput>& ins)
{
Query query = conn->query(XmrInput::SELECT_STMT2);
query.parse();
try
{
query.storein(ins, address_id);
if (!ins.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool
MysqlInputs::select_for_out(const uint64_t& output_id, vector<XmrInput>& ins)
{
Query query = conn->query(XmrInput::SELECT_STMT3);
query.parse();
try
{
query.storein(ins, output_id);
if (!ins.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t
MysqlInputs::insert(const XmrInput& in_data)
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrInput::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrInput::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(in_data.account_id,
in_data.tx_id,
in_data.output_id,
in_data.key_image,
in_data.amount,
in_data.timestamp);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
MysqlOutpus::MysqlOutpus(shared_ptr<MySqlConnector> _conn): conn {_conn}
{}
bool
MysqlOutpus::select(const uint64_t& address_id, vector<XmrOutput>& outs)
{
Query query = conn->query(XmrOutput::SELECT_STMT);
query.parse();
try
{
query.storein(outs, address_id);
if (!outs.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool
MysqlOutpus::select_for_tx(const uint64_t& tx_id, vector<XmrOutput>& outs)
{
Query query = conn->query(XmrOutput::SELECT_STMT2);
query.parse();
try
{
query.storein(outs, tx_id);
if (!outs.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool
MysqlOutpus::exist(const string& output_public_key_str, XmrOutput& out)
{
Query query = conn->query(XmrOutput::EXIST_STMT);
query.parse();
try
{
vector<XmrOutput> outs;
query.storein(outs, output_public_key_str);
if (outs.empty())
{
return false;
}
out = outs.at(0);
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return true;
}
uint64_t
MysqlOutpus::insert(const XmrOutput& out_data)
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrOutput::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrOutput::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(out_data.account_id,
out_data.tx_id,
out_data.out_pub_key,
out_data.tx_pub_key,
out_data.amount,
out_data.global_index,
out_data.out_index,
out_data.mixin,
out_data.timestamp);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
MysqlTransactions::MysqlTransactions(shared_ptr<MySqlConnector> _conn): conn {_conn}
{}
bool
MysqlTransactions::select(const uint64_t& address_id, vector<XmrTransaction>& txs)
{
//
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(
// XmrTransaction::SELECT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrTransaction::SELECT_STMT);
query.parse();
try
{
query.storein(txs, address_id);
if (!txs.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t
MysqlTransactions::insert(const XmrTransaction& tx_data)
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrTransaction::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrTransaction::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(tx_data.hash,
tx_data.prefix_hash,
tx_data.account_id,
tx_data.total_received,
tx_data.total_sent,
tx_data.unlock_time,
tx_data.height,
tx_data.coinbase,
tx_data.payment_id,
tx_data.mixin,
tx_data.timestamp);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
bool
MysqlTransactions::exist(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx)
{
Query query = conn->query(XmrTransaction::EXIST_STMT);
query.parse();
try
{
vector<XmrTransaction> outs;
query.storein(outs, account_id, tx_hash_str);
if (outs.empty())
{
return false;
}
tx = outs.at(0);
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return true;
}
uint64_t
MysqlTransactions::get_total_recieved(const uint64_t& account_id)
{
Query query = conn->query(XmrTransaction::SUM_XMR_RECIEVED);
query.parse();
try
{
StoreQueryResult sqr = query.store(account_id);
if (!sqr)
{
return 0;
}
Row row = sqr.at(0);
return row["total_received"];
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
}
MysqlPayments::MysqlPayments(shared_ptr<MySqlConnector> _conn): conn {_conn}
{}
bool
MysqlPayments::select(const string& address, vector<XmrPayment>& payments)
{
Query query = conn->query(XmrPayment::SELECT_STMT);
query.parse();
try
{
query.storein(payments, address);
if (!payments.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool
MysqlPayments::select_by_payment_id(const string& payment_id, vector<XmrPayment>& payments)
{
Query query = conn->query(XmrPayment::SELECT_STMT2);
query.parse();
try
{
query.storein(payments, payment_id);
if (!payments.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t
MysqlPayments::insert(const XmrPayment& payment_data)
{
Query query = conn->query(XmrPayment::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(payment_data.address,
payment_data.payment_id,
payment_data.tx_hash,
payment_data.request_fulfilled,
payment_data.payment_address,
payment_data.import_fee);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
bool
MysqlPayments::update(XmrPayment& payment_orginal, XmrPayment& payment_new)
{
Query query = conn->query();
try
{
query.update(payment_orginal, payment_new);
SimpleResult sr = query.execute();
if (sr.rows() == 1)
return true;
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return false;
}
return false;
}
MySqlAccounts::MySqlAccounts()
{
// create connection to the mysql
conn = make_shared<MySqlConnector>();
// 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);
mysql_tx_inout = make_shared<MysqlTransactionWithOutsAndIns>(conn);
}
bool
MySqlAccounts::select(const string& address, XmrAccount& account)
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrAccount::SELECT_STMT);
query.parse();
try
{
vector<XmrAccount> res;
query.storein(res, address);
if (!res.empty())
{
account = res.at(0);
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool
MySqlAccounts::select(const int64_t& acc_id, XmrAccount& account)
{
//static shared_ptr<Query> query;
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT2);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrAccount::SELECT_STMT2);
query.parse();
try
{
vector<XmrAccount> res;
query.storein(res, acc_id);
if (!res.empty())
{
account = res.at(0);
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t
MySqlAccounts::insert(const string& address, const uint64_t& current_blkchain_height)
{
// static shared_ptr<Query> query;
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrAccount::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrAccount::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
// scanned_block_height and start_height are
// set to current blockchain height
// when account is created.
SimpleResult sr = query.execute(address,
current_blkchain_height,
current_blkchain_height);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
uint64_t
MySqlAccounts::insert_tx(const XmrTransaction& tx_data)
{
return mysql_tx->insert(tx_data);
}
uint64_t
MySqlAccounts::insert_output(const XmrOutput& tx_out)
{
return mysql_out->insert(tx_out);
}
uint64_t
MySqlAccounts::insert_input(const XmrInput& tx_in)
{
return mysql_in->insert(tx_in);
}
bool
MySqlAccounts::select_txs(const string& xmr_address, vector<XmrTransaction>& txs)
{
// having address first get its address_id
// a placeholder for exciting or new account data
xmreg::XmrAccount acc;
// select this account if its existing one
if (!select(xmr_address, acc))
{
cerr << "Address" << xmr_address << "does not exist in database" << endl;
return false;
}
return mysql_tx->select(acc.id, txs);
}
bool
MySqlAccounts::select_txs(const uint64_t& account_id, vector<XmrTransaction>& txs)
{
return mysql_tx->select(account_id, txs);
}
bool
MySqlAccounts::select_txs_with_inputs_and_outputs(const uint64_t& account_id,
vector<XmrTransactionWithOutsAndIns>& txs)
{
return mysql_tx_inout->select(account_id, txs);
}
bool
MySqlAccounts::select_outputs(const uint64_t& account_id, vector<XmrOutput>& outs)
{
return mysql_out->select(account_id, outs);
}
bool
MySqlAccounts::select_outputs_for_tx(const uint64_t& tx_id, vector<XmrOutput>& outs)
{
return mysql_out->select_for_tx(tx_id, outs);
}
bool
MySqlAccounts::select_inputs(const uint64_t& account_id, vector<XmrInput>& ins)
{
return mysql_in->select(account_id, ins);
}
bool
MySqlAccounts::select_inputs_for_tx(const uint64_t& tx_id, vector<XmrTransactionWithOutsAndIns>& ins)
{
return mysql_tx_inout->select_for_tx(tx_id, ins);
}
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::insert_payment(const XmrPayment& payment)
{
return mysql_payment->insert(payment);
}
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::select_payment_by_address(const string& address, vector<XmrPayment>& payments)
{
return mysql_payment->select(address, payments);
}
bool
MySqlAccounts::select_payment_by_address(const string& address, XmrPayment& payment)
{
vector<XmrPayment> payments;
bool r = mysql_payment->select(address, payments);
if (!r)
{
return false;
}
if (payments.empty())
{
return false;
}
// always get last payment details.
payment = payments.back();
return r;
}
bool
MySqlAccounts::update_payment(XmrPayment& payment_orginal, XmrPayment& payment_new)
{
return mysql_payment->update(payment_orginal, payment_new);
}
uint64_t
MySqlAccounts::get_total_recieved(const uint64_t& account_id)
{
return mysql_tx->get_total_recieved(account_id);
}
bool
MySqlAccounts::update(XmrAccount& acc_orginal, XmrAccount& acc_new)
{
Query query = conn->query();
try
{
query.update(acc_orginal, acc_new);
SimpleResult sr = query.execute();
if (sr.rows() == 1)
return true;
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return false;
}
return false;
}
}

@ -5,13 +5,9 @@
#ifndef RESTBED_XMR_MYSQLACCOUNTS_H #ifndef RESTBED_XMR_MYSQLACCOUNTS_H
#define RESTBED_XMR_MYSQLACCOUNTS_H #define RESTBED_XMR_MYSQLACCOUNTS_H
#include "tools.h" #include "tools.h"
#include "ssqlses.h"
#include "MySqlConnector.h" #include "MySqlConnector.h"
//#include "ssqlses.h"
#include <mysql++/mysql++.h>
#include <mysql++/ssqls.h>
#include <iostream> #include <iostream>
@ -26,6 +22,13 @@ using namespace std;
using namespace nlohmann; using namespace nlohmann;
class XmrTransactionWithOutsAndIns;
class XmrInput;
class XmrOutput;
class XmrTransaction;
class XmrPayment;
class XmrAccount;
class MysqlTransactionWithOutsAndIns class MysqlTransactionWithOutsAndIns
{ {
@ -33,57 +36,13 @@ class MysqlTransactionWithOutsAndIns
public: public:
MysqlTransactionWithOutsAndIns(shared_ptr<MySqlConnector> _conn) : conn{_conn} {} MysqlTransactionWithOutsAndIns(shared_ptr<MySqlConnector> _conn);
bool bool
select(const uint64_t &address_id, vector<XmrTransactionWithOutsAndIns>& txs) { select(const uint64_t &address_id, vector<XmrTransactionWithOutsAndIns>& txs);
Query query = conn->query(XmrTransactionWithOutsAndIns::SELECT_STMT);
query.parse();
try
{
query.storein(txs, address_id);
if (!txs.empty())
{
return true;
}
}
catch (mysqlpp::Exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool bool
select_for_tx(const uint64_t &tx_id, vector<XmrTransactionWithOutsAndIns>& txs) { select_for_tx(const uint64_t &tx_id, vector<XmrTransactionWithOutsAndIns>& txs);
Query query = conn->query(XmrTransactionWithOutsAndIns::SELECT_STMT2);
query.parse();
try
{
query.storein(txs, tx_id);
if (!txs.empty())
{
return true;
}
}
catch (mysqlpp::Exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception &e) {
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
}; };
@ -95,135 +54,21 @@ class MysqlInputs
public: public:
MysqlInputs(shared_ptr<MySqlConnector> _conn): conn {_conn} MysqlInputs(shared_ptr<MySqlConnector> _conn);
{}
bool bool
select(const uint64_t& address_id, vector<XmrInput>& ins) select(const uint64_t& address_id, vector<XmrInput>& ins);
{
Query query = conn->query(XmrInput::SELECT_STMT);
query.parse();
try
{
query.storein(ins, address_id);
if (!ins.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool bool
select_for_tx(const uint64_t& address_id, vector<XmrInput>& ins) select_for_tx(const uint64_t& address_id, vector<XmrInput>& ins);
{
Query query = conn->query(XmrInput::SELECT_STMT2);
query.parse();
try
{
query.storein(ins, address_id);
if (!ins.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool bool
select_for_out(const uint64_t& output_id, vector<XmrInput>& ins) select_for_out(const uint64_t& output_id, vector<XmrInput>& ins);
{
Query query = conn->query(XmrInput::SELECT_STMT3);
query.parse();
try
{
query.storein(ins, output_id);
if (!ins.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t uint64_t
insert(const XmrInput& in_data) insert(const XmrInput& in_data);
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrInput::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrInput::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(in_data.account_id,
in_data.tx_id,
in_data.output_id,
in_data.key_image,
in_data.amount,
in_data.timestamp);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
}; };
@ -236,143 +81,22 @@ class MysqlOutpus
public: public:
MysqlOutpus(shared_ptr<MySqlConnector> _conn): conn {_conn} MysqlOutpus(shared_ptr<MySqlConnector> _conn);
{}
bool bool
select(const uint64_t& address_id, vector<XmrOutput>& outs) select(const uint64_t& address_id, vector<XmrOutput>& outs);
{
Query query = conn->query(XmrOutput::SELECT_STMT);
query.parse();
try
{
query.storein(outs, address_id);
if (!outs.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool bool
select_for_tx(const uint64_t& tx_id, vector<XmrOutput>& outs) select_for_tx(const uint64_t& tx_id, vector<XmrOutput>& outs);
{
Query query = conn->query(XmrOutput::SELECT_STMT2);
query.parse();
try
{
query.storein(outs, tx_id);
if (!outs.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool bool
exist(const string& output_public_key_str, XmrOutput& out) exist(const string& output_public_key_str, XmrOutput& out);
{
Query query = conn->query(XmrOutput::EXIST_STMT);
query.parse();
try
{
vector<XmrOutput> outs;
query.storein(outs, output_public_key_str);
if (outs.empty())
{
return false;
}
out = outs.at(0);
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return true;
}
uint64_t uint64_t
insert(const XmrOutput& out_data) insert(const XmrOutput& out_data);
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrOutput::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrOutput::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(out_data.account_id,
out_data.tx_id,
out_data.out_pub_key,
out_data.tx_pub_key,
out_data.amount,
out_data.global_index,
out_data.out_index,
out_data.mixin,
out_data.timestamp);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
}; };
@ -385,155 +109,22 @@ class MysqlTransactions
public: public:
MysqlTransactions(shared_ptr<MySqlConnector> _conn): conn {_conn} MysqlTransactions(shared_ptr<MySqlConnector> _conn);
{}
bool bool
select(const uint64_t& address_id, vector<XmrTransaction>& txs) select(const uint64_t& address_id, vector<XmrTransaction>& txs);
{
//
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(
// XmrTransaction::SELECT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrTransaction::SELECT_STMT);
query.parse();
try
{
query.storein(txs, address_id);
if (!txs.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t uint64_t
insert(const XmrTransaction& tx_data) insert(const XmrTransaction& tx_data);
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrTransaction::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrTransaction::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(tx_data.hash,
tx_data.prefix_hash,
tx_data.account_id,
tx_data.total_received,
tx_data.total_sent,
tx_data.unlock_time,
tx_data.height,
tx_data.coinbase,
tx_data.payment_id,
tx_data.mixin,
tx_data.timestamp);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
bool bool
exist(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx) exist(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx);
{
Query query = conn->query(XmrTransaction::EXIST_STMT);
query.parse();
try
{
vector<XmrTransaction> outs;
query.storein(outs, account_id, tx_hash_str);
if (outs.empty())
{
return false;
}
tx = outs.at(0);
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return true;
}
uint64_t uint64_t
get_total_recieved(const uint64_t& account_id) get_total_recieved(const uint64_t& account_id);
{
Query query = conn->query(XmrTransaction::SUM_XMR_RECIEVED);
query.parse();
try
{
StoreQueryResult sqr = query.store(account_id);
if (!sqr)
{
return 0;
}
Row row = sqr.at(0);
return row["total_received"];
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
}
}; };
@ -545,121 +136,21 @@ class MysqlPayments
public: public:
MysqlPayments(shared_ptr<MySqlConnector> _conn): conn {_conn} MysqlPayments(shared_ptr<MySqlConnector> _conn);
{}
bool bool
select(const string& address, vector<XmrPayment>& payments) select(const string& address, vector<XmrPayment>& payments);
{
Query query = conn->query(XmrPayment::SELECT_STMT);
query.parse();
try
{
query.storein(payments, address);
if (!payments.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool bool
select_by_payment_id(const string& payment_id, vector<XmrPayment>& payments) select_by_payment_id(const string& payment_id, vector<XmrPayment>& payments);
{
Query query = conn->query(XmrPayment::SELECT_STMT2);
query.parse();
try
{
query.storein(payments, payment_id);
if (!payments.empty())
{
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t uint64_t
insert(const XmrPayment& payment_data) insert(const XmrPayment& payment_data);
{
Query query = conn->query(XmrPayment::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
SimpleResult sr = query.execute(payment_data.address,
payment_data.payment_id,
payment_data.tx_hash,
payment_data.request_fulfilled,
payment_data.payment_address,
payment_data.import_fee);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
bool bool
update(XmrPayment& payment_orginal, XmrPayment& payment_new) update(XmrPayment& payment_orginal, XmrPayment& payment_new);
{
Query query = conn->query();
try
{
query.update(payment_orginal, payment_new);
SimpleResult sr = query.execute();
if (sr.rows() == 1)
return true;
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return false;
}
return false;
}
}; };
@ -681,312 +172,80 @@ class MySqlAccounts
public: public:
MySqlAccounts();
MySqlAccounts()
{
// create connection to the mysql
conn = make_shared<MySqlConnector>();
// 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);
mysql_tx_inout = make_shared<MysqlTransactionWithOutsAndIns>(conn);
}
bool bool
select(const string& address, XmrAccount& account) select(const string& address, XmrAccount& account);
{
// static shared_ptr<Query> query;
//
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrAccount::SELECT_STMT);
query.parse();
try
{
vector<XmrAccount> res;
query.storein(res, address);
if (!res.empty())
{
account = res.at(0);
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
catch (std::exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
bool bool
select(const int64_t& acc_id, XmrAccount& account) select(const int64_t& acc_id, XmrAccount& account);
{
//static shared_ptr<Query> query;
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrAccount::SELECT_STMT2);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrAccount::SELECT_STMT2);
query.parse();
try
{
vector<XmrAccount> res;
query.storein(res, acc_id);
if (!res.empty())
{
account = res.at(0);
return true;
}
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
}
return false;
}
uint64_t uint64_t
insert(const string& address, const uint64_t& current_blkchain_height = 0) insert(const string& address, const uint64_t& current_blkchain_height = 0);
{
// static shared_ptr<Query> query;
// if (!query)
// {
// Query q = MySqlConnector::getInstance().query(XmrAccount::INSERT_STMT);
// q.parse();
// query = shared_ptr<Query>(new Query(q));
// }
Query query = conn->query(XmrAccount::INSERT_STMT);
query.parse();
// cout << query << endl;
try
{
// scanned_block_height and start_height are
// set to current blockchain height
// when account is created.
SimpleResult sr = query.execute(address,
current_blkchain_height,
current_blkchain_height);
if (sr.rows() == 1)
return sr.insert_id();
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return 0;
}
return 0;
}
uint64_t uint64_t
insert_tx(const XmrTransaction& tx_data) insert_tx(const XmrTransaction& tx_data);
{
return mysql_tx->insert(tx_data);
}
uint64_t uint64_t
insert_output(const XmrOutput& tx_out) insert_output(const XmrOutput& tx_out);
{
return mysql_out->insert(tx_out);
}
uint64_t uint64_t
insert_input(const XmrInput& tx_in) insert_input(const XmrInput& tx_in);
{
return mysql_in->insert(tx_in);
}
bool bool
select_txs(const string& xmr_address, vector<XmrTransaction>& txs) select_txs(const string& xmr_address, vector<XmrTransaction>& txs);
{
// having address first get its address_id
// a placeholder for exciting or new account data
xmreg::XmrAccount acc;
// select this account if its existing one
if (!select(xmr_address, acc))
{
cerr << "Address" << xmr_address << "does not exist in database" << endl;
return false;
}
return mysql_tx->select(acc.id, txs);
}
bool bool
select_txs(const uint64_t& account_id, vector<XmrTransaction>& txs) select_txs(const uint64_t& account_id, vector<XmrTransaction>& txs);
{
return mysql_tx->select(account_id, txs);
}
bool bool
select_txs_with_inputs_and_outputs(const uint64_t& account_id, select_txs_with_inputs_and_outputs(const uint64_t& account_id,
vector<XmrTransactionWithOutsAndIns>& txs) vector<XmrTransactionWithOutsAndIns>& txs);
{
return mysql_tx_inout->select(account_id, txs);
}
bool bool
select_outputs(const uint64_t& account_id, vector<XmrOutput>& outs) select_outputs(const uint64_t& account_id, vector<XmrOutput>& outs);
{
return mysql_out->select(account_id, outs);
}
bool bool
select_outputs_for_tx(const uint64_t& tx_id, vector<XmrOutput>& outs) select_outputs_for_tx(const uint64_t& tx_id, vector<XmrOutput>& outs);
{
return mysql_out->select_for_tx(tx_id, outs);
}
bool bool
select_inputs(const uint64_t& account_id, vector<XmrInput>& ins) select_inputs(const uint64_t& account_id, vector<XmrInput>& ins);
{
return mysql_in->select(account_id, ins);
}
bool bool
select_inputs_for_tx(const uint64_t& tx_id, vector<XmrTransactionWithOutsAndIns>& ins) select_inputs_for_tx(const uint64_t& tx_id, vector<XmrTransactionWithOutsAndIns>& ins);
{
return mysql_tx_inout->select_for_tx(tx_id, ins);
}
bool bool
select_inputs_for_out(const uint64_t& output_id, vector<XmrInput>& ins) select_inputs_for_out(const uint64_t& output_id, vector<XmrInput>& ins);
{
return mysql_in->select_for_out(output_id, ins);
}
bool bool
output_exists(const string& output_public_key_str, XmrOutput& out) output_exists(const string& output_public_key_str, XmrOutput& out);
{
return mysql_out->exist(output_public_key_str, out);
}
bool bool
tx_exists(const uint64_t& account_id, const string& tx_hash_str, XmrTransaction& tx) 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 uint64_t
insert_payment(const XmrPayment& payment) insert_payment(const XmrPayment& payment);
{
return mysql_payment->insert(payment);
}
bool bool
select_payment_by_id(const string& payment_id, vector<XmrPayment>& payments) select_payment_by_id(const string& payment_id, vector<XmrPayment>& payments);
{
return mysql_payment->select_by_payment_id(payment_id, payments);
}
bool bool
select_payment_by_address(const string& address, vector<XmrPayment>& payments) select_payment_by_address(const string& address, vector<XmrPayment>& payments);
{
return mysql_payment->select(address, payments);
}
bool bool
select_payment_by_address(const string& address, XmrPayment& payment) select_payment_by_address(const string& address, XmrPayment& payment);
{
vector<XmrPayment> payments;
bool r = mysql_payment->select(address, payments);
if (!r)
{
return false;
}
if (payments.empty())
{
return false;
}
// always get last payment details.
payment = payments.back();
return r;
}
bool bool
update_payment(XmrPayment& payment_orginal, XmrPayment& payment_new) update_payment(XmrPayment& payment_orginal, XmrPayment& payment_new);
{
return mysql_payment->update(payment_orginal, payment_new);
}
uint64_t uint64_t
get_total_recieved(const uint64_t& account_id) get_total_recieved(const uint64_t& account_id);
{
return mysql_tx->get_total_recieved(account_id);
}
bool bool
update(XmrAccount& acc_orginal, XmrAccount& acc_new) update(XmrAccount& acc_orginal, XmrAccount& acc_new);
{
Query query = conn->query();
try
{
query.update(acc_orginal, acc_new);
SimpleResult sr = query.execute();
if (sr.rows() == 1)
return true;
}
catch (mysqlpp::Exception& e)
{
MYSQL_EXCEPTION_MSG(e);
return false;
}
return false;
}
}; };

@ -0,0 +1,53 @@
//
// Created by mwo on 7/01/17.
//
#include "MySqlConnector.h"
//#include "ssqlses.h"
#include <mysql++/mysql++.h>
#include <mysql++/ssqls.h>
#include <iostream>
#include <memory>
namespace xmreg {
string MySqlConnector::url;
string MySqlConnector::username;
string MySqlConnector::password;
string MySqlConnector::dbname;
MySqlConnector::MySqlConnector() {
if (conn.connected())
return;
if (!conn.connect(dbname.c_str(), url.c_str(),
username.c_str(), password.c_str())) {
cerr << "Connection to Mysql failed!" << endl;
return;
}
}
Query
MySqlConnector::query(const char *qstr)
{
return conn.query(qstr);
}
Query
MySqlConnector::query(const std::string &qstr)
{
return conn.query(qstr);
}
MySqlConnector::~MySqlConnector()
{
conn.disconnect();
};
}

@ -5,23 +5,19 @@
#ifndef RESTBED_XMR_MYSQLCONNECTOR_H #ifndef RESTBED_XMR_MYSQLCONNECTOR_H
#define RESTBED_XMR_MYSQLCONNECTOR_H #define RESTBED_XMR_MYSQLCONNECTOR_H
#include "tools.h" //#include "tools.h"
#include "ssqlses.h"
#include <mysql++/mysql++.h> #include <mysql++/mysql++.h>
#include <mysql++/ssqls.h> #include <mysql++/ssqls.h>
#include <iostream> #include <iostream>
#include <memory>
namespace xmreg namespace xmreg
{ {
using namespace mysqlpp; using namespace mysqlpp;
using namespace std; using namespace std;
using namespace nlohmann;
#define MYSQL_EXCEPTION_MSG(sql_excetption) cerr << "# ERR: SQLException in " << __FILE__ \ #define MYSQL_EXCEPTION_MSG(sql_excetption) cerr << "# ERR: SQLException in " << __FILE__ \
<< "(" << __FUNCTION__ << ") on line " << __LINE__ << endl \ << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl \
@ -50,47 +46,16 @@ public:
static string password; static string password;
static string dbname; static string dbname;
MySqlConnector() MySqlConnector();
{
if (conn.connected())
return;
if (!conn.connect(dbname.c_str(), url.c_str(),
username.c_str(), password.c_str()))
{
cerr << "Connection to Mysql failed!" << endl;
return;
}
}
Query Query
query(const char* qstr = 0) query(const char* qstr = 0);
{
return conn.query(qstr);
}
Query Query
query(const std::string& qstr) query(const std::string& qstr);
{
return conn.query(qstr);
}
virtual ~MySqlConnector()
{
conn.disconnect();
};
};
string MySqlConnector::url;
string MySqlConnector::username;
string MySqlConnector::password;
string MySqlConnector::dbname;
virtual ~MySqlConnector();
};
} }

@ -0,0 +1,557 @@
//
// Created by mwo on 7/01/17.
//
#include "TxSearch.h"
#include "CurrentBlockchainStatus.h"
namespace xmreg
{
TxSearch::TxSearch(XmrAccount& _acc): acc {_acc}
{
xmr_accounts = make_shared<MySqlAccounts>();
bool testnet = CurrentBlockchainStatus::testnet;
if (!xmreg::parse_str_address(acc.address, address, testnet))
{
cerr << "Cant parse string address: " << acc.address << endl;
throw TxSearchException("Cant parse string address: " + acc.address);
}
if (!xmreg::parse_str_secret_key(acc.viewkey, viewkey))
{
cerr << "Cant parse the private key: " << acc.viewkey << endl;
throw TxSearchException("Cant parse private key: " + acc.viewkey);
}
// start searching from last block that we searched for
// this accont
searched_blk_no = acc.scanned_block_height;
ping();
}
void
TxSearch::search()
{
if (searched_blk_no > CurrentBlockchainStatus::current_height)
{
throw TxSearchException("searched_blk_no > CurrentBlockchainStatus::current_height");
}
uint64_t current_timestamp = chrono::duration_cast<chrono::seconds>(
chrono::system_clock::now().time_since_epoch()).count();
uint64_t loop_idx {0};
while(continue_search)
{
++loop_idx;
uint64_t loop_timestamp {current_timestamp};
if (loop_idx % 2 == 0)
{
// get loop time every second iteration. no need to call it
// all the time.
loop_timestamp = chrono::duration_cast<chrono::seconds>(
chrono::system_clock::now().time_since_epoch()).count();
//cout << "loop_timestamp: " << loop_timestamp << endl;
//cout << "last_ping_timestamp: " << last_ping_timestamp << endl;
//cout << "loop_timestamp - last_ping_timestamp: " << (loop_timestamp - last_ping_timestamp) << endl;
if (loop_timestamp - last_ping_timestamp > THREAD_LIFE_DURATION)
{
// also check if we caught up with current blockchain height
if (searched_blk_no == CurrentBlockchainStatus::current_height)
{
stop();
continue;
}
}
}
if (searched_blk_no > CurrentBlockchainStatus::current_height) {
fmt::print("searched_blk_no {:d} and current_height {:d}\n",
searched_blk_no, CurrentBlockchainStatus::current_height);
std::this_thread::sleep_for(
std::chrono::seconds(
CurrentBlockchainStatus::refresh_block_status_every_seconds)
);
continue;
}
//
//cout << " - searching tx of: " << acc << endl;
// get block cointaining this tx
block blk;
if (!CurrentBlockchainStatus::get_block(searched_blk_no, blk)) {
cerr << "Cant get block of height: " + to_string(searched_blk_no) << endl;
//searched_blk_no = -2; // just go back one block, and retry
continue;
}
// for each tx in the given block look, get ouputs
list <cryptonote::transaction> blk_txs;
if (!CurrentBlockchainStatus::get_block_txs(blk, blk_txs)) {
throw TxSearchException("Cant get transactions in block: " + to_string(searched_blk_no));
}
if (searched_blk_no % 100 == 0)
{
// print status every 10th block
fmt::print(" - searching block {:d} of hash {:s} \n",
searched_blk_no, pod_to_hex(get_block_hash(blk)));
}
// searching for our incoming and outgoing xmr has two componotes.
//
// FIRST. to search for the incoming xmr, we use address, viewkey and
// outputs public key. Its stright forward.
// second. searching four our spendings is trickier, as we dont have
//
// SECOND. But what we can do, we can look for condidate spend keys.
// and this can be achieved by checking if any mixin in associated with
// the given image, is our output. If it is our output, than we assume
// its our key image (i.e. we spend this output). Off course this is only
// assumption as our outputs can be used in key images of others for their
// mixin purposes. Thus, we sent to the front end, the list of key images
// that we think are yours, and the frontend, because it has spend key,
// can filter out false positives.
for (transaction& tx: blk_txs)
{
crypto::hash tx_hash = get_transaction_hash(tx);
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
string tx_hash_str = pod_to_hex(tx_hash);
string tx_prefix_hash_str = pod_to_hex(tx_prefix_hash);
bool is_coinbase_tx = is_coinbase(tx);
vector<uint64_t> amount_specific_indices;
// cout << pod_to_hex(tx_hash) << endl;
public_key tx_pub_key = xmreg::get_tx_pub_key_from_received_outs(tx);
// <public_key , amount , out idx>
vector<tuple<txout_to_key, uint64_t, uint64_t>> outputs;
outputs = get_ouputs_tuple(tx);
// for each output, in a tx, check if it belongs
// to the given account of specific address and viewkey
// public transaction key is combined with our viewkey
// to create, so called, derived key.
key_derivation derivation;
if (!generate_key_derivation(tx_pub_key, viewkey, derivation))
{
cerr << "Cant get derived key for: " << "\n"
<< "pub_tx_key: " << tx_pub_key << " and "
<< "prv_view_key" << viewkey << endl;
throw TxSearchException("");
}
uint64_t total_received {0};
// FIRST component: Checking for our outputs.
// <out_pub_key, amount , index in tx>
vector<tuple<string, uint64_t, uint64_t>> found_mine_outputs;
for (auto& out: outputs)
{
txout_to_key txout_k = std::get<0>(out);
uint64_t amount = std::get<1>(out);
uint64_t output_idx_in_tx = std::get<2>(out);
// get the tx output public key
// that normally would be generated for us,
// if someone had sent us some xmr.
public_key generated_tx_pubkey;
derive_public_key(derivation,
output_idx_in_tx,
address.m_spend_public_key,
generated_tx_pubkey);
// check if generated public key matches the current output's key
bool mine_output = (txout_k.key == generated_tx_pubkey);
//cout << "Chekcing output: " << pod_to_hex(txout_k.key) << " "
// << "mine_output: " << mine_output << endl;
// if mine output has RingCT, i.e., tx version is 2
// need to decode its amount. otherwise its zero.
if (mine_output && tx.version == 2)
{
// initialize with regular amount
uint64_t rct_amount = amount;
// cointbase txs have amounts in plain sight.
// so use amount from ringct, only for non-coinbase txs
if (!is_coinbase_tx)
{
bool r;
r = decode_ringct(tx.rct_signatures,
tx_pub_key,
viewkey,
output_idx_in_tx,
tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask,
rct_amount);
if (!r)
{
cerr << "Cant decode ringCT!" << endl;
throw TxSearchException("Cant decode ringCT!");
}
rct_amount = amount;
}
amount = rct_amount;
} // if (mine_output && tx.version == 2)
if (mine_output)
{
string out_key_str = pod_to_hex(txout_k.key);
// found an output associated with the given address and viewkey
string msg = fmt::format("block: {:d}, tx_hash: {:s}, output_pub_key: {:s}\n",
searched_blk_no,
pod_to_hex(tx_hash),
out_key_str);
cout << msg << endl;
total_received += amount;
found_mine_outputs.emplace_back(out_key_str,
amount,
output_idx_in_tx);
}
} // for (const auto& out: outputs)
DateTime blk_timestamp_mysql_format
= XmrTransaction::timestamp_to_DateTime(blk.timestamp);
uint64_t tx_mysql_id {0};
if (!found_mine_outputs.empty())
{
// before adding this tx and its outputs to mysql
// check if it already exists. So that we dont
// do it twice.
XmrTransaction tx_data;
if (xmr_accounts->tx_exists(acc.id, tx_hash_str, tx_data))
{
cout << "\nTransaction " << tx_hash_str
<< " already present in mysql"
<< endl;
continue;
}
tx_data.hash = tx_hash_str;
tx_data.prefix_hash = tx_prefix_hash_str;
tx_data.account_id = acc.id;
tx_data.total_received = total_received;
tx_data.total_sent = 0; // at this stage we don't have any
// info about spendings
tx_data.unlock_time = 0;
tx_data.height = searched_blk_no;
tx_data.coinbase = is_coinbase_tx;
tx_data.payment_id = CurrentBlockchainStatus::get_payment_id_as_string(tx);
tx_data.mixin = get_mixin_no(tx) - 1;
tx_data.timestamp = blk_timestamp_mysql_format;
// insert tx_data into mysql's Transactions table
tx_mysql_id = xmr_accounts->insert_tx(tx_data);
// get amount specific (i.e., global) indices of outputs
if (!CurrentBlockchainStatus::get_amount_specific_indices(tx_hash,
amount_specific_indices))
{
cerr << "cant get_amount_specific_indices!" << endl;
throw TxSearchException("cant get_amount_specific_indices!");
}
if (tx_mysql_id == 0)
{
//cerr << "tx_mysql_id is zero!" << endl;
//throw TxSearchException("tx_mysql_id is zero!");
}
// now add the found outputs into Outputs tables
for (auto &out_k_idx: found_mine_outputs)
{
XmrOutput out_data;
out_data.account_id = acc.id;
out_data.tx_id = tx_mysql_id;
out_data.out_pub_key = std::get<0>(out_k_idx);
out_data.tx_pub_key = pod_to_hex(tx_pub_key);
out_data.amount = std::get<1>(out_k_idx);
out_data.out_index = std::get<2>(out_k_idx);
out_data.global_index = amount_specific_indices.at(out_data.out_index);
out_data.mixin = tx_data.mixin;
out_data.timestamp = tx_data.timestamp;
// insert output into mysql's outputs table
uint64_t out_mysql_id = xmr_accounts->insert_output(out_data);
if (out_mysql_id == 0)
{
//cerr << "out_mysql_id is zero!" << endl;
//throw TxSearchException("out_mysql_id is zero!");
}
} // for (auto &out_k_idx: found_mine_outputs)
// once tx and outputs were added, update Accounts table
XmrAccount updated_acc = acc;
updated_acc.total_received = acc.total_received + tx_data.total_received;
if (xmr_accounts->update(acc, updated_acc))
{
// if success, set acc to updated_acc;
acc = updated_acc;
}
} // if (!found_mine_outputs.empty())
// SECOND component: Checking for our key images, i.e., inputs.
vector<txin_to_key> input_key_imgs = xmreg::get_key_images(tx);
// here we will keep what we find.
vector<XmrInput> inputs_found;
// make timescale maps for mixins in input
for (const txin_to_key& in_key: input_key_imgs)
{
// get absolute offsets of mixins
std::vector<uint64_t> absolute_offsets
= cryptonote::relative_output_offsets_to_absolute(
in_key.key_offsets);
// get public keys of outputs used in the mixins that match to the offests
std::vector<cryptonote::output_data_t> mixin_outputs;
if (!CurrentBlockchainStatus::get_output_keys(in_key.amount,
absolute_offsets,
mixin_outputs))
{
cerr << "Mixins key images not found" << endl;
continue;
}
// for each found output public key find check if its ours or not
for (const cryptonote::output_data_t& output_data: mixin_outputs)
{
string output_public_key_str = pod_to_hex(output_data.pubkey);
XmrOutput out;
if (xmr_accounts->output_exists(output_public_key_str, out))
{
cout << "input uses some mixins which are our outputs"
<< out << endl;
// seems that this key image is ours.
// so save it to database for later use.
XmrInput in_data;
in_data.account_id = acc.id;
in_data.tx_id = 0; // for now zero, later we set it
in_data.output_id = out.id;
in_data.key_image = pod_to_hex(in_key.k_image);
in_data.amount = in_key.amount;
in_data.timestamp = blk_timestamp_mysql_format;
inputs_found.push_back(in_data);
// a key image has only one real mixin. Rest is fake.
// so if we find a candidate, break the search.
// break;
} // if (xmr_accounts->output_exists(output_public_key_str, out))
} // for (const cryptonote::output_data_t& output_data: outputs)
} // for (const txin_to_key& in_key: input_key_imgs)
if (!inputs_found.empty())
{
// seems we have some inputs found. time
// to write it to mysql. But first,
// check if this tx is written in mysql.
// calculate how much we preasumply spent.
uint64_t total_sent {0};
for (const XmrInput& in_data: inputs_found)
{
total_sent += in_data.amount;
}
if (tx_mysql_id == 0)
{
// this txs hasnt been seen in step first.
// it means that it only contains potentially our
// key images. It does not have our outputs.
// so write it to mysql as ours, with
// total received of 0.
XmrTransaction tx_data;
tx_data.hash = tx_hash_str;
tx_data.prefix_hash = tx_prefix_hash_str;
tx_data.account_id = acc.id;
tx_data.total_received = 0;
tx_data.total_sent = total_sent;
tx_data.unlock_time = 0;
tx_data.height = searched_blk_no;
tx_data.coinbase = is_coinbase(tx);
tx_data.payment_id = CurrentBlockchainStatus::get_payment_id_as_string(tx);
tx_data.mixin = get_mixin_no(tx) - 1;
tx_data.timestamp = blk_timestamp_mysql_format;
// insert tx_data into mysql's Transactions table
tx_mysql_id = xmr_accounts->insert_tx(tx_data);
if (tx_mysql_id == 0)
{
//cerr << "tx_mysql_id is zero!" << endl;
//throw TxSearchException("tx_mysql_id is zero!");
}
}
} // if (!inputs_found.empty())
// save all input found into database
for (XmrInput& in_data: inputs_found)
{
in_data.tx_id = tx_mysql_id;
uint64_t in_mysql_id = xmr_accounts->insert_input(in_data);
}
} // for (const transaction& tx: blk_txs)
if ((loop_timestamp - current_timestamp > UPDATE_SCANNED_HEIGHT_INTERVAL)
|| searched_blk_no == CurrentBlockchainStatus::current_height)
{
// update scanned_block_height every given interval
// or when we reached top of the blockchain
XmrAccount updated_acc = acc;
updated_acc.scanned_block_height = searched_blk_no;
if (xmr_accounts->update(acc, updated_acc))
{
// iff success, set acc to updated_acc;
cout << "scanned_block_height updated" << endl;
acc = updated_acc;
}
current_timestamp = loop_timestamp;
}
++searched_blk_no;
} // while(continue_search)
}
void
TxSearch::stop()
{
cout << "Stoping the thread by setting continue_search=false" << endl;
continue_search = false;
}
TxSearch::~TxSearch()
{
cout << "TxSearch destroyed" << endl;
}
void
TxSearch::set_searched_blk_no(uint64_t new_value)
{
searched_blk_no = new_value;
}
void
TxSearch::ping()
{
cout << "new last_ping_timestamp: " << last_ping_timestamp << endl;
last_ping_timestamp = chrono::duration_cast<chrono::seconds>(
chrono::system_clock::now().time_since_epoch()).count();
}
bool
TxSearch::still_searching()
{
return continue_search;
}
}

@ -0,0 +1,82 @@
//
// Created by mwo on 7/01/17.
//
#ifndef RESTBED_XMR_TXSEARCH_H
#define RESTBED_XMR_TXSEARCH_H
#include "cryptonote_core/cryptonote_basic.h"
#include "cryptonote_core/blockchain.h"
#include "wallet/wallet2.h"
#include "MySqlAccounts.h"
#include <atomic>
namespace xmreg
{
class TxSearchException: public std::runtime_error
{
using std::runtime_error::runtime_error;
};
class TxSearch
{
// how frequently update scanned_block_height in Accounts table
static constexpr uint64_t UPDATE_SCANNED_HEIGHT_INTERVAL = 10; // seconds
// how long should the search thread be live after no request
// are coming from the frontend. For example, when a user finishes
// using the service.
static constexpr uint64_t THREAD_LIFE_DURATION = 10 * 60; // in seconds
bool continue_search {true};
uint64_t last_ping_timestamp;
atomic<uint64_t> searched_blk_no;
// represents a row in mysql's Accounts table
XmrAccount acc;
// this manages all mysql queries
// its better to when each thread has its own mysql connection object.
// this way if one thread crashes, it want take down
// connection for the entire service
shared_ptr<MySqlAccounts> xmr_accounts;
// address and viewkey for this search thread.
cryptonote::account_public_address address;
secret_key viewkey;
public:
TxSearch(XmrAccount& _acc);
void
search();
void
stop();
~TxSearch();
void
set_searched_blk_no(uint64_t new_value);
void
ping();
bool
still_searching();
};
}
#endif //RESTBED_XMR_TXSEARCH_H

@ -8,9 +8,10 @@
#include <iostream> #include <iostream>
#include <functional> #include <functional>
#include "MySqlConnector.h" //#include "MySqlConnector.h"
#include "CurrentBlockchainStatus.h" #include "CurrentBlockchainStatus.h"
#include "tools.h" #include "MySqlAccounts.h"
#include "ssqlses.h"
#include "../ext/restbed/source/restbed" #include "../ext/restbed/source/restbed"

File diff suppressed because it is too large Load Diff

@ -7,7 +7,7 @@
#include <mysql++/mysql++.h> #include <mysql++/mysql++.h>
#include <mysql++/ssqls.h>
#include "../ext/json.hpp" #include "../ext/json.hpp"

@ -932,6 +932,15 @@ parse(const std::string& str, string format)
return tp; return tp;
} }
string
xmr_amount_to_str(const uint64_t& xmr_amount, string format)
{
return fmt::format("{:0.12f}", XMR_AMOUNT(xmr_amount));
}
/** /**
* Check if given output (specified by output_index) * Check if given output (specified by output_index)
* belongs is ours based * belongs is ours based

@ -233,12 +233,9 @@ get_tx_pub_key_from_received_outs(const transaction &tx);
date::sys_seconds date::sys_seconds
parse(const std::string& str, string format="%Y-%m-%d %H:%M:%S"); parse(const std::string& str, string format="%Y-%m-%d %H:%M:%S");
static
string string
xmr_amount_to_str(const uint64_t& xmr_amount, string format="{:0.12f}") xmr_amount_to_str(const uint64_t& xmr_amount, string format="{:0.12f}");
{
return fmt::format("{:0.12f}", XMR_AMOUNT(xmr_amount));
}
bool bool
is_output_ours(const size_t& output_index, is_output_ours(const size_t& output_index,

Loading…
Cancel
Save