search for tx in mempool added
This commit is contained in:
parent
e376b87cfb
commit
9e102ad401
|
@ -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
|
2
main.cpp
2
main.cpp
|
@ -4,6 +4,7 @@
|
|||
#include "src/page.h"
|
||||
|
||||
#include "ext/crow/crow.h"
|
||||
#include "ext/member_checker.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
@ -16,7 +17,6 @@ namespace epee {
|
|||
unsigned int g_test_dbg_lock_sleep = 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int ac, const char* av[]) {
|
||||
|
||||
// get command line options
|
||||
|
|
183
src/page.h
183
src/page.h
|
@ -10,6 +10,7 @@
|
|||
#include "mstch/mstch.hpp"
|
||||
#include "rapidjson/document.h"
|
||||
#include "../ext/format.h"
|
||||
#include "../ext/member_checker.h"
|
||||
|
||||
|
||||
#include "monero_headers.h"
|
||||
|
@ -33,10 +34,25 @@
|
|||
|
||||
namespace xmreg {
|
||||
|
||||
|
||||
using namespace cryptonote;
|
||||
using namespace crypto;
|
||||
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
|
||||
*
|
||||
|
@ -101,9 +117,10 @@ namespace xmreg {
|
|||
}
|
||||
|
||||
for (const crypto::signature &sig: signatures.at(in_i))
|
||||
{
|
||||
cout << print_sig(sig) << endl;
|
||||
ring_sigs.push_back(mstch::map{{"ring_sig", print_signature(sig)}});
|
||||
{
|
||||
ring_sigs.push_back(mstch::map{
|
||||
{"ring_sig", print_signature(sig)}
|
||||
});
|
||||
}
|
||||
|
||||
return ring_sigs;
|
||||
|
@ -123,6 +140,11 @@ namespace xmreg {
|
|||
|
||||
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};
|
||||
|
||||
MicroCore* mcore;
|
||||
|
@ -130,6 +152,7 @@ namespace xmreg {
|
|||
rpccalls rpc;
|
||||
time_t server_timestamp;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
page(MicroCore* _mcore, Blockchain* _core_storage, string deamon_url)
|
||||
|
@ -138,6 +161,7 @@ namespace xmreg {
|
|||
rpc {deamon_url},
|
||||
server_timestamp {std::time(nullptr)}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string
|
||||
|
@ -594,13 +618,43 @@ namespace xmreg {
|
|||
return string("Cant parse tx hash: " + tx_hash_str);
|
||||
}
|
||||
|
||||
// tx age
|
||||
pair<string, string> age;
|
||||
|
||||
string blk_timestamp {"N/A"};
|
||||
|
||||
// get transaction
|
||||
transaction tx;
|
||||
|
||||
if (!mcore->get_tx(tx_hash, tx))
|
||||
{
|
||||
cerr << "Cant get tx: " << tx_hash << endl;
|
||||
return string("Cant get tx: " + tx_hash_str);
|
||||
cerr << "Cant find tx ib blockchain: " << tx_hash
|
||||
<< ". 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);
|
||||
|
@ -614,46 +668,54 @@ namespace xmreg {
|
|||
tx_blk_height = core_storage->get_db().get_tx_block_height(tx_hash);
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
string tx_blk_height_str {"N/A"};
|
||||
|
||||
// calculate difference between tx and server timestamps
|
||||
pair<string, string> age = get_age(server_timestamp,
|
||||
blk.timestamp, FULL_AGE_FORMAT);
|
||||
if (tx_blk_found)
|
||||
{
|
||||
// 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
|
||||
mstch::map context {
|
||||
{"tx_hash" , tx_hash_str},
|
||||
{"tx_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.pk))},
|
||||
{"blk_height" , tx_blk_height},
|
||||
{"tx_size" , fmt::format("{:0.2f}",
|
||||
{"blk_height" , tx_blk_height_str},
|
||||
{"tx_size" , fmt::format("{:0.4f}",
|
||||
static_cast<double>(txd.size) / 1024.0)},
|
||||
{"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},
|
||||
{"inputs_no" , txd.input_key_imgs.size()},
|
||||
{"outputs_no" , txd.output_pub_keys.size()}
|
||||
};
|
||||
|
||||
string server_time_str = xmreg::timestamp_to_str(server_timestamp,
|
||||
"%F");
|
||||
string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F");
|
||||
|
||||
mstch::array inputs = mstch::array{};
|
||||
|
||||
mstch::array mixins_timescales;
|
||||
|
||||
double timescale_scale {0.0}; // size of one '_' in days
|
||||
|
||||
uint64_t input_idx {0};
|
||||
|
@ -683,11 +745,11 @@ namespace xmreg {
|
|||
});
|
||||
|
||||
|
||||
|
||||
// get reference to mixins array created above
|
||||
mstch::array& mixins = boost::get<mstch::array>(
|
||||
boost::get<mstch::map>(inputs.back())["mixins"]);
|
||||
|
||||
// mixin counter
|
||||
size_t count = 0;
|
||||
|
||||
// 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,
|
||||
blk.timestamp,
|
||||
FULL_AGE_FORMAT);
|
||||
// get mixin transaction
|
||||
transaction mixin_tx;
|
||||
// get mixin transaction
|
||||
transaction mixin_tx;
|
||||
|
||||
if (!mcore->get_tx(tx_out_idx.first, mixin_tx))
|
||||
{
|
||||
cerr << "Cant get tx: " << tx_out_idx.first << endl;
|
||||
return fmt::format("Cant get tx: {:s}", tx_out_idx.first);
|
||||
}
|
||||
if (!mcore->get_tx(tx_out_idx.first, mixin_tx))
|
||||
{
|
||||
cerr << "Cant get tx: " << tx_out_idx.first << endl;
|
||||
return fmt::format("Cant get tx: {:s}", tx_out_idx.first);
|
||||
}
|
||||
|
||||
// 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_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}",
|
||||
output_data.pubkey))},
|
||||
|
@ -740,12 +802,12 @@ namespace xmreg {
|
|||
{"mix_outputs_no" , mixin_txd.output_pub_keys.size()},
|
||||
{"mix_age_format" , mixin_age.second},
|
||||
{"mix_idx" , fmt::format("{:02d}", count)},
|
||||
});
|
||||
});
|
||||
|
||||
// get mixin timestamp from its orginal block
|
||||
mixin_timestamps.push_back(blk.timestamp);
|
||||
// get mixin timestamp from its orginal block
|
||||
mixin_timestamps.push_back(blk.timestamp);
|
||||
|
||||
++count;
|
||||
++count;
|
||||
|
||||
} // for (const uint64_t &i: absolute_offsets)
|
||||
|
||||
|
@ -786,7 +848,6 @@ namespace xmreg {
|
|||
|
||||
context["outputs"] = outputs;
|
||||
|
||||
|
||||
// read tx.html
|
||||
string tx_html = xmreg::read(TMPL_TX);
|
||||
|
||||
|
@ -843,6 +904,66 @@ namespace xmreg {
|
|||
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>
|
||||
get_age(uint64_t timestamp1, uint64_t timestamp2, bool full_format = 0)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue