search for tx in mempool added

This commit is contained in:
moneroexamples 2016-04-24 09:11:08 +08:00
parent e376b87cfb
commit 9e102ad401
3 changed files with 189 additions and 32 deletions

36
ext/member_checker.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef MEMBER_CHECKER_H
#define MEMBER_CHECKER_H
#define DEFINE_MEMBER_CHECKER(member) \
template<typename T, typename V = bool> \
struct has_ ## member : false_type { }; \
\
template<typename T> \
struct has_ ## member<T, \
typename enable_if< \
!is_same<decltype(declval<T>().member), void>::value, \
bool \
>::type \
> : true_type { };
#define HAS_MEMBER(C, member) \
has_ ## member<C>::value
// first getter if the member veriable is present, so we return its value
// second getter, when the member is not present, so we return empty value, e.g., empty string
#define DEFINE_MEMBER_GETTER(member, ret_value) \
template<typename T> \
typename enable_if<HAS_MEMBER(T, member), ret_value>::type \
get_ ## member (T t){ \
return t.member; \
} \
\
template<typename T> \
typename enable_if<!HAS_MEMBER(T, member), ret_value>::type \
get_ ## member (T t){ \
return ret_value(); \
}
#endif // MEMBER_CHECKER_H

View File

@ -4,6 +4,7 @@
#include "src/page.h" #include "src/page.h"
#include "ext/crow/crow.h" #include "ext/crow/crow.h"
#include "ext/member_checker.h"
#include <fstream> #include <fstream>
@ -16,7 +17,6 @@ namespace epee {
unsigned int g_test_dbg_lock_sleep = 0; unsigned int g_test_dbg_lock_sleep = 0;
} }
int main(int ac, const char* av[]) { int main(int ac, const char* av[]) {
// get command line options // get command line options

View File

@ -10,6 +10,7 @@
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
#include "rapidjson/document.h" #include "rapidjson/document.h"
#include "../ext/format.h" #include "../ext/format.h"
#include "../ext/member_checker.h"
#include "monero_headers.h" #include "monero_headers.h"
@ -33,10 +34,25 @@
namespace xmreg { namespace xmreg {
using namespace cryptonote; using namespace cryptonote;
using namespace crypto; using namespace crypto;
using namespace std; using namespace std;
// define a checker to test if a structure has "tx_blob"
// member variable. I use modified daemon with few extra
// bits and pieces here and there. One of them is
// tx_blob in cryptonote::tx_info structure
// thus I check if I run my version, or just
// generic one
DEFINE_MEMBER_CHECKER(tx_blob)
// define getter to get tx_blob, i.e., get_tx_blob function
// as string if exists. the getter return empty string if
// tx_blob does not exist
DEFINE_MEMBER_GETTER(tx_blob, string)
/** /**
* @brief The tx_details struct * @brief The tx_details struct
* *
@ -101,9 +117,10 @@ namespace xmreg {
} }
for (const crypto::signature &sig: signatures.at(in_i)) for (const crypto::signature &sig: signatures.at(in_i))
{ {
cout << print_sig(sig) << endl; ring_sigs.push_back(mstch::map{
ring_sigs.push_back(mstch::map{{"ring_sig", print_signature(sig)}}); {"ring_sig", print_signature(sig)}
});
} }
return ring_sigs; return ring_sigs;
@ -123,6 +140,11 @@ namespace xmreg {
class page { class page {
// check if we have tx_blob member in tx_info structure
static const bool HAVE_TX_BLOB {
HAS_MEMBER(cryptonote::tx_info, tx_blob)
};
static const bool FULL_AGE_FORMAT {true}; static const bool FULL_AGE_FORMAT {true};
MicroCore* mcore; MicroCore* mcore;
@ -130,6 +152,7 @@ namespace xmreg {
rpccalls rpc; rpccalls rpc;
time_t server_timestamp; time_t server_timestamp;
public: public:
page(MicroCore* _mcore, Blockchain* _core_storage, string deamon_url) page(MicroCore* _mcore, Blockchain* _core_storage, string deamon_url)
@ -138,6 +161,7 @@ namespace xmreg {
rpc {deamon_url}, rpc {deamon_url},
server_timestamp {std::time(nullptr)} server_timestamp {std::time(nullptr)}
{ {
} }
string string
@ -594,13 +618,43 @@ namespace xmreg {
return string("Cant parse tx hash: " + tx_hash_str); return string("Cant parse tx hash: " + tx_hash_str);
} }
// tx age
pair<string, string> age;
string blk_timestamp {"N/A"};
// get transaction // get transaction
transaction tx; transaction tx;
if (!mcore->get_tx(tx_hash, tx)) if (!mcore->get_tx(tx_hash, tx))
{ {
cerr << "Cant get tx: " << tx_hash << endl; cerr << "Cant find tx ib blockchain: " << tx_hash
return string("Cant get tx: " + tx_hash_str); << ". Check mempool now" << endl;
vector<pair<tx_info, transaction>> found_txs
= search_mempool(tx_hash);
if (!found_txs.empty())
{
// there should be only one tx found
tx = found_txs.at(0).second;
// since its tx in mempool, it has no blk yet
// so use its recive_time as timestamp to show
uint64_t tx_recieve_timestamp
= found_txs.at(0).first.receive_time;
blk_timestamp = xmreg::timestamp_to_str(tx_recieve_timestamp);
age = get_age(server_timestamp, tx_recieve_timestamp,
FULL_AGE_FORMAT);
}
else
{
// tx is nowhere to be found :-(
return string("Cant find tx: " + tx_hash_str);
}
} }
tx_details txd = get_tx_details(tx); tx_details txd = get_tx_details(tx);
@ -614,46 +668,54 @@ namespace xmreg {
tx_blk_height = core_storage->get_db().get_tx_block_height(tx_hash); tx_blk_height = core_storage->get_db().get_tx_block_height(tx_hash);
tx_blk_found = true; tx_blk_found = true;
} }
catch (BLOCK_DNE & e) catch (exception& e)
{ {
cerr << "Cant get block height: " << tx_hash << endl; cerr << "Cant get block height: " << tx_hash
<< e.what() << endl;
} }
// get block cointaining this tx // get block cointaining this tx
block blk; block blk;
if (!mcore->get_block_by_height(tx_blk_height, blk)) if (tx_blk_found && !mcore->get_block_by_height(tx_blk_height, blk))
{ {
cerr << "Cant get block: " << tx_blk_height << endl; cerr << "Cant get block: " << tx_blk_height << endl;
} }
string tx_blk_height_str {"N/A"};
// calculate difference between tx and server timestamps if (tx_blk_found)
pair<string, string> age = get_age(server_timestamp, {
blk.timestamp, FULL_AGE_FORMAT); // calculate difference between tx and server timestamps
age = get_age(server_timestamp, blk.timestamp, FULL_AGE_FORMAT);
blk_timestamp = xmreg::timestamp_to_str(blk.timestamp);
tx_blk_height_str = std::to_string(tx_blk_height);
}
// initalise page tempate map with basic info about blockchain // initalise page tempate map with basic info about blockchain
mstch::map context { mstch::map context {
{"tx_hash" , tx_hash_str}, {"tx_hash" , tx_hash_str},
{"tx_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.pk))}, {"tx_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.pk))},
{"blk_height" , tx_blk_height}, {"blk_height" , tx_blk_height_str},
{"tx_size" , fmt::format("{:0.2f}", {"tx_size" , fmt::format("{:0.4f}",
static_cast<double>(txd.size) / 1024.0)}, static_cast<double>(txd.size) / 1024.0)},
{"tx_fee" , fmt::format("{:0.12f}", XMR_AMOUNT(txd.fee))}, {"tx_fee" , fmt::format("{:0.12f}", XMR_AMOUNT(txd.fee))},
{"blk_timestamp" , xmreg::timestamp_to_str(blk.timestamp)}, {"blk_timestamp" , blk_timestamp},
{"delta_time" , age.first}, {"delta_time" , age.first},
{"inputs_no" , txd.input_key_imgs.size()}, {"inputs_no" , txd.input_key_imgs.size()},
{"outputs_no" , txd.output_pub_keys.size()} {"outputs_no" , txd.output_pub_keys.size()}
}; };
string server_time_str = xmreg::timestamp_to_str(server_timestamp, string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F");
"%F");
mstch::array inputs = mstch::array{}; mstch::array inputs = mstch::array{};
mstch::array mixins_timescales; mstch::array mixins_timescales;
double timescale_scale {0.0}; // size of one '_' in days double timescale_scale {0.0}; // size of one '_' in days
uint64_t input_idx {0}; uint64_t input_idx {0};
@ -683,11 +745,11 @@ namespace xmreg {
}); });
// get reference to mixins array created above // get reference to mixins array created above
mstch::array& mixins = boost::get<mstch::array>( mstch::array& mixins = boost::get<mstch::array>(
boost::get<mstch::map>(inputs.back())["mixins"]); boost::get<mstch::map>(inputs.back())["mixins"]);
// mixin counter
size_t count = 0; size_t count = 0;
// for each found output public key find its block to get timestamp // for each found output public key find its block to get timestamp
@ -714,19 +776,19 @@ namespace xmreg {
pair<string, string> mixin_age = get_age(server_timestamp, pair<string, string> mixin_age = get_age(server_timestamp,
blk.timestamp, blk.timestamp,
FULL_AGE_FORMAT); FULL_AGE_FORMAT);
// get mixin transaction // get mixin transaction
transaction mixin_tx; transaction mixin_tx;
if (!mcore->get_tx(tx_out_idx.first, mixin_tx)) if (!mcore->get_tx(tx_out_idx.first, mixin_tx))
{ {
cerr << "Cant get tx: " << tx_out_idx.first << endl; cerr << "Cant get tx: " << tx_out_idx.first << endl;
return fmt::format("Cant get tx: {:s}", tx_out_idx.first); return fmt::format("Cant get tx: {:s}", tx_out_idx.first);
} }
// mixin tx details // mixin tx details
tx_details mixin_txd = get_tx_details(mixin_tx, true); tx_details mixin_txd = get_tx_details(mixin_tx, true);
mixins.push_back(mstch::map { mixins.push_back(mstch::map {
{"mix_blk" , fmt::format("{:08d}", output_data.height)}, {"mix_blk" , fmt::format("{:08d}", output_data.height)},
{"mix_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", {"mix_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}",
output_data.pubkey))}, output_data.pubkey))},
@ -740,12 +802,12 @@ namespace xmreg {
{"mix_outputs_no" , mixin_txd.output_pub_keys.size()}, {"mix_outputs_no" , mixin_txd.output_pub_keys.size()},
{"mix_age_format" , mixin_age.second}, {"mix_age_format" , mixin_age.second},
{"mix_idx" , fmt::format("{:02d}", count)}, {"mix_idx" , fmt::format("{:02d}", count)},
}); });
// get mixin timestamp from its orginal block // get mixin timestamp from its orginal block
mixin_timestamps.push_back(blk.timestamp); mixin_timestamps.push_back(blk.timestamp);
++count; ++count;
} // for (const uint64_t &i: absolute_offsets) } // for (const uint64_t &i: absolute_offsets)
@ -786,7 +848,6 @@ namespace xmreg {
context["outputs"] = outputs; context["outputs"] = outputs;
// read tx.html // read tx.html
string tx_html = xmreg::read(TMPL_TX); string tx_html = xmreg::read(TMPL_TX);
@ -843,6 +904,66 @@ namespace xmreg {
return txd; return txd;
} }
vector<pair<tx_info, transaction>>
search_mempool(crypto::hash tx_hash)
{
vector<pair<tx_info, transaction>> found_txs;
// get txs in the mempool
std::vector<tx_info> mempool_txs;
if (!rpc.get_mempool(mempool_txs))
{
cerr << "Getting mempool failed " << endl;
return found_txs;
}
// if we have tx blob disply more.
// this info can also be obtained from json that is
// normally returned by the RCP call (see below in detailed view)
if (HAVE_TX_BLOB)
{
// get tx_blob if exists
//string tx_blob = get_tx_blob(_tx_info);
for (size_t i = 0; i < mempool_txs.size(); ++i)
{
// get transaction info of the tx in the mempool
tx_info _tx_info = mempool_txs.at(i);
// get tx_blob if exists
string tx_blob = get_tx_blob(_tx_info);
if (tx_blob.empty())
{
cerr << "tx_blob is empty. Probably its not a custom deamon." << endl;
continue;
}
// pare tx_blob into tx class
transaction tx;
if (!parse_and_validate_tx_from_blob(
tx_blob, tx))
{
cerr << "Cant parse tx from blob" << endl;
continue;
}
// check if tx hash matches, and if yes, save it for return
if (tx_hash == get_transaction_hash(tx))
{
found_txs.push_back(make_pair(_tx_info, tx));
break;
}
}
}
return found_txs;
}
pair<string, string> pair<string, string>
get_age(uint64_t timestamp1, uint64_t timestamp2, bool full_format = 0) get_age(uint64_t timestamp1, uint64_t timestamp2, bool full_format = 0)
{ {