Merge pull request #75 from moneroexamples/update_to_current_monero

Update to current monero
master
moneroexamples 7 years ago committed by GitHub
commit 7eca176e6a

@ -100,7 +100,7 @@ set(LIBRARIES
cryptonote_protocol
cryptonote_basic
daemonizer
cryptoxmr
cncrypto
blocks
lmdb
ringct

@ -25,8 +25,16 @@ Monero C++ libraries, but also demonstrates how to use:
Tor users:
- [http://libwh5lvouddzei4.onion/] - bleading edge version.
- [http://dvwae436pd7nt4bc.onion](http://dvwae436pd7nt4bc.onion) (Front-end templates are [maintained by @suhz](https://github.com/suhz/onion-monero-blockchain-explorer/tree/moneroexplorer.com/src/templates)).
- [http://libwh5lvouddzei4.onion/] - bleading edge version.
Clearnet versions:
- [http://139.162.32.245:8081/](http://139.162.32.245:8081/) - down for now.
- [https://xmrchain.net/](https://xmrchain.net/) - https enabled, most popular and very stable.
- [https://monerohash.com/explorer/](https://monerohash.com/explorer/) - nice looking one, https enabled.
- [http://explore.MoneroWorld.com](http://explore.moneroworld.com) - same as the second one.
- [https://MoneroExplorer.com/](https://moneroexplorer.com/) - nice looking one, https enabled.
Clearnet versions:
@ -37,18 +45,18 @@ Clearnet versions:
- [https://MoneroExplorer.com/](https://moneroexplorer.com/) - nice looking one, https enabled.
- [https://explorer.monero-otc.com/](https://explorer.monero-otc.com/) - https enabled.
- [http://monerochain.com/](http://monerochain.com/) - JSON API based, multiple nodes.
- [http://66.85.74.134:8081/](http://66.85.74.134:8081/) - fluffynet subnet explorer.
Clearnet testnet Monero version:
- [http://139.162.32.245:8082/](http://139.162.32.245:8082/) - bleeding edge version, no https.
- [https://testnet.xmrchain.com/](https://testnet.xmrchain.com/) - https enabled.
- [https://explorer.monero-otc.com/](https://explorer.monero-otc.com/) - https enabled.
- [https://testnet.MoneroExplorer.com/](https://testnet.moneroexplorer.com/) - https enabled.
i2p users (main Monero network):
i2p users (main Monero network) - down for now:
- [http://monerotools.i2p](http://monerotools.i2p)
- [http://7o4gezpkye6ekibhgpkg7v626ze4idsirapufzrefkdysa6zxhha.b32.i2p/](http://7o4gezpkye6ekibhgpkg7v626ze4idsirapufzrefkdysa6zxhha.b32.i2p/)
Alternative block explorers:
@ -63,26 +71,27 @@ The key features of the Onion Monero Blockchain Explorer are:
- no javascript, no cookies, no web analytics trackers, no images,
- open sourced,
- made fully in C++,
- the only explorer showing encrypted payments ID,
- the only explorer showing ring signatures,
- the only explorer showing transaction extra field,
- the only explorer showing public components of Monero addresses,
- the only explorer that can show which outputs and mixins belong to the given Monero address and viewkey,
- the only explorer that can be used to prove that you send Monero to someone,
- the only explorer showing detailed information about mixins, such as, mixins'
- showing encrypted payments ID,
- showing ring signatures,
- showing transaction extra field,
- showing public components of Monero addresses,
- decoding which outputs and mixins belong to the given Monero address and viewkey,
- can prove that you send Monero to someone,
- detailed information about mixins, such as, mixins'
age, timescale, mixin of mixins,
- the only explorer showing number of amount output indices,
- the only explorer supporting Monero testnet network,
- the only explorer providing tx checker and pusher for online pushing of transactions,
- the only explorer able to estimate possible spendings based on address and viewkey,
- the only explorer that can provide total amount of all miner fees.
- showing number of amount output indices,
- support Monero testnet network,
- tx checker and pusher for online pushing of transactions,
- estimate possible spendings based on address and viewkey,
- can provide total amount of all miner fees.
- decoding encrypted payment id.
## Compilation on Ubuntu 16.04
##### Compile latest Monero
Download and compile recent Monero release into your home folder:
Download and compile recent Monero into your home folder:
```bash
# first install monero dependecines
@ -97,9 +106,6 @@ git clone https://github.com/monero-project/monero
cd monero/
# checkout last monero version
git checkout -b last_release v0.10.3.1
make
```
@ -155,7 +161,6 @@ Go to your browser: http://127.0.0.1:8081
## The explorer's command line options
```
./xmrblocks -h
xmrblocks, Onion Monero Blockchain Explorer:
-h [ --help ] [=arg(=1)] (=0) produce help message
-t [ --testnet ] [=arg(=1)] (=0) use testnet blockchain
@ -168,8 +173,6 @@ xmrblocks, Onion Monero Blockchain Explorer:
enable key images file checker
--enable-output-key-checker [=arg(=1)] (=0)
enable outputs key file checker
--enable-mempool-cache arg (=1) enable caching of transactions from the
mempool
--enable-json-api arg (=1) enable JSON REST api
--enable-tx-cache [=arg(=1)] (=0) enable caching of transaction details
--show-cache-times [=arg(=1)] (=0) show times of getting data from cache
@ -194,6 +197,8 @@ xmrblocks, Onion Monero Blockchain Explorer:
for network info availability
--mempool-info-timeout arg (=5000) maximum time, in milliseconds, to wait
for mempool data for the front page
--mempool-refresh-time arg (=5) time, in seconds, for each refresh of
mempool state
-b [ --bc-path ] arg path to lmdb folder of the blockchain,
e.g., ~/.bitmonero/lmdb
--ssl-crt-file arg path to crt file for ssl (https)
@ -285,7 +290,7 @@ The explorer has JSON api. For the API, it uses conventions defined by [JSend](h
#### api/transaction/<tx_hash>
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/transaction/6093260dbe79fd6277694d14789dc8718f1bd54457df8bab338c2efa3bb0f03d"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/transaction/6093260dbe79fd6277694d14789dc8718f1bd54457df8bab338c2efa3bb0f03d"
```
Partial results shown:
@ -347,7 +352,7 @@ Transactions in last 25 blocks
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/transactions"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/transactions"
```
Partial results shown:
@ -397,7 +402,7 @@ Partial results shown:
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/transactions?page=2&limit=10"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/transactions?page=2&limit=10"
```
Result analogical to the one above.
@ -447,7 +452,7 @@ Partial results shown:
Return all txs in the mempool.
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/mempool"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/mempool"
```
Partial results shown:
@ -490,7 +495,7 @@ if no specific limit given.
Return number of newest mempool txs, e.g., only 10.
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/mempool?limit=10"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/mempool?limit=10"
```
Result analogical to the one above.
@ -498,7 +503,7 @@ Result analogical to the one above.
#### api/search/<block_number|tx_hash|block_hash>
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/search/1293669"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/search/1293669"
```
Partial results shown:
@ -546,7 +551,7 @@ Checking outputs:
```bash
# we use here official Monero project's donation address as an example
curl -w "\n" -X GET "http://139.162.32.245:8081/api/outputs?txhash=17049bc5f2d9fbca1ce8dae443bbbbed2fc02f1ee003ffdd0571996905faa831&address=44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A&viewkey=f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501&txprove=0"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/outputs?txhash=17049bc5f2d9fbca1ce8dae443bbbbed2fc02f1ee003ffdd0571996905faa831&address=44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A&viewkey=f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501&txprove=0"
```
```json
@ -582,7 +587,7 @@ For the viewkey, we use `tx_private_key` (although the GET variable is still cal
```bash
# this is for testnet transaction
curl -w "\n" -X GET "http://139.162.32.245:8082/api/outputs?txhash=94782a8c0aa8d8768afa0c040ef0544b63eb5148ca971a024ac402cad313d3b3&address=9wUf8UcPUtb2huK7RphBw5PFCyKosKxqtGxbcKBDnzTCPrdNfJjLjtuht87zhTgsffCB21qmjxjj18Pw7cBnRctcKHrUB7N&viewkey=e94b5bfc599d2f741d6f07e3ab2a83f915e96fb374dfb2cd3dbe730e34ecb40b&txprove=1"
curl -w "\n" -X GET "http://127.0.0.1:8082/api/outputs?txhash=94782a8c0aa8d8768afa0c040ef0544b63eb5148ca971a024ac402cad313d3b3&address=9wUf8UcPUtb2huK7RphBw5PFCyKosKxqtGxbcKBDnzTCPrdNfJjLjtuht87zhTgsffCB21qmjxjj18Pw7cBnRctcKHrUB7N&viewkey=e94b5bfc599d2f741d6f07e3ab2a83f915e96fb374dfb2cd3dbe730e34ecb40b&txprove=1"
```
```json
@ -617,7 +622,7 @@ Result analogical to the one above.
#### api/networkinfo
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/networkinfo"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/networkinfo"
```
```json
@ -647,10 +652,65 @@ curl -w "\n" -X GET "http://139.162.32.245:8081/api/networkinfo"
}
```
#### api/outputsblocks
Search for our outputs in last few blocks (up to 5 blocks), using provided address and viewkey.
```bash
# testnet address
curl -w "\n" -X GET http://127.0.0.1:8081/api/outputsblocks?address=9sDyNU82ih1gdhDgrqHbEcfSDFASjFgxL9B9v5f1AytFUrYsVEj7bD9Pyx5Sw2qLk8HgGdFM8qj5DNecqGhm24Ce6QwEGDi&viewkey=807079280293998634d66e745562edaaca45c0a75c8290603578b54e9397e90a&limit=5&mempool=1
```
Example result:
```json
{
{
"data": {
"address": "0182d5be0f708cecf2b6f9889738bde5c930fad846d5b530e021afd1ae7e24a687ad50af3a5d38896655669079ad0163b4a369f6c852cc816dace5fc7792b72f",
"height": 960526,
"limit": "5",
"mempool": true,
"outputs": [
{
"amount": 33000000000000,
"block_no": 0,
"in_mempool": true,
"output_idx": 1,
"output_pubkey": "2417b24fc99b2cbd9459278b532b37f15eab6b09bbfc44f9d17e15cd25d5b44f",
"payment_id": "",
"tx_hash": "9233708004c51d15f44e86ac1a3b99582ed2bede4aaac6e2dd71424a9147b06f"
},
{
"amount": 2000000000000,
"block_no": 960525,
"in_mempool": false,
"output_idx": 0,
"output_pubkey": "9984101f5471dda461f091962f1f970b122d4469077aed6b978a910dc3ed4576",
"payment_id": "0000000000000055",
"tx_hash": "37825d0feb2e96cd10fa9ec0b990ac2e97d2648c0f23e4f7d68d2298996acefd"
},
{
"amount": 96947454120000,
"block_no": 960525,
"in_mempool": false,
"output_idx": 1,
"output_pubkey": "e4bded8e2a9ec4d41682a34d0a37596ec62742b28e74b897fcc00a47fcaa8629",
"payment_id": "0000000000000000000000000000000000000000000000000000000000001234",
"tx_hash": "4fad5f2bdb6dbd7efc2ce7efa3dd20edbd2a91640ce35e54c6887f0ee5a1a679"
}
],
"viewkey": "807079280293998634d66e745562edaaca45c0a75c8290603578b54e9397e90a"
},
"status": "success"
}
```
#### api/emission
```bash
curl -w "\n" -X GET "http://139.162.32.245:8081/api/emission"
curl -w "\n" -X GET "http://127.0.0.1:8081/api/emission"
```
```json
@ -666,6 +726,34 @@ curl -w "\n" -X GET "http://139.162.32.245:8081/api/emission"
Emission only works when the emission monitoring thread is enabled.
#### api/version
```bash
curl -w "\n" -X GET "http://127.0.0.1:8081/api/version"
```
```json
{
"data": {
"api": 65536,
"blockchain_height": 1357031,
"git_branch_name": "update_to_current_monero",
"last_git_commit_date": "2017-07-25",
"last_git_commit_hash": "a549f25",
"monero_version_full": "0.10.3.1-ab594cfe"
},
"status": "success"
}
```
api number is store as `uint32_t`. In this case `65536` represents
major version 1 and minor version 0.
In JavaScript to get these numbers, one can do as follows:
```javascript
var api_major = response.data.api >> 16;
var api_minor = response.data.api & 0xffff;
```
#### api/rawblock/<block_number|block_hash>

@ -30,7 +30,7 @@
set(LIBS common;blocks;cryptonote_basic;cryptonote_core;
cryptonote_protocol;daemonizer;mnemonics;epee;lmdb;
blockchain_db;ringct;wallet)
blockchain_db;ringct;wallet;cncrypto)
set(Xmr_INCLUDE_DIRS "${CPP_MONERO_DIR}")
@ -57,13 +57,6 @@ foreach (l ${LIBS})
endforeach()
if (EXISTS ${MONERO_BUILD_DIR}/src/crypto/libcncrypto.a)
add_library(cryptoxmr STATIC IMPORTED)
set_property(TARGET cryptoxmr
PROPERTY IMPORTED_LOCATION ${MONERO_BUILD_DIR}/src/crypto/libcncrypto.a)
endif()
if (EXISTS ${MONERO_BUILD_DIR}/external/easylogging++/libeasylogging.a)
add_library(easylogging STATIC IMPORTED)
set_property(TARGET easylogging

@ -156,7 +156,7 @@ namespace crow
struct Wrapped
{
template <typename ... Args>
void set(Func f, typename std::enable_if<
void set2(Func f, typename std::enable_if<
!std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value
, int>::type = 0)
{
@ -190,7 +190,7 @@ namespace crow
};
template <typename ... Args>
void set(Func f, typename std::enable_if<
void set2(Func f, typename std::enable_if<
std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
!std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
, int>::type = 0)
@ -205,7 +205,7 @@ namespace crow
}
template <typename ... Args>
void set(Func f, typename std::enable_if<
void set2(Func f, typename std::enable_if<
std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
, int>::type = 0)
@ -410,9 +410,7 @@ namespace crow
throw std::runtime_error("route_dynamic: Handler type is mismatched with URL parameters: " + rule_);
}
auto ret = detail::routing_handler_call_helper::Wrapped<Func, typename function_t::template arg<Indices>...>();
ret.template set<
typename function_t::template arg<Indices>...
>(std::move(f));
ret.template set2<typename function_t::template arg<Indices>...>(std::move(f));
return ret;
}

@ -1,57 +0,0 @@
//
// Created by mwo on 24/05/15.
//
// source: http://codereview.stackexchange.com/questions/13176/infix-iterator-code
// infix_iterator.h
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
#include <string>
template <class T, class charT=char, class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag, void, void, void, void>
{
std::basic_ostream<charT,traits> *os;
std::basic_string<charT> delimiter;
std::basic_string<charT> real_delim;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT, traits> ostream_type;
infix_ostream_iterator(ostream_type &s)
: os(&s)
{}
infix_ostream_iterator(ostream_type &s, charT const *d)
: os(&s),
real_delim(d)
{}
infix_ostream_iterator<T, charT, traits> &operator=(T const &item)
{
*os << delimiter << item;
delimiter = real_delim;
return *this;
}
infix_ostream_iterator<T, charT, traits> &operator*() {
return *this;
}
infix_ostream_iterator<T, charT, traits> &operator++() {
return *this;
}
infix_ostream_iterator<T, charT, traits> &operator++(int) {
return *this;
}
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,36 +0,0 @@
#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

@ -1,10 +1,11 @@
#define CROW_ENABLE_SSL
#include "ext/crow/crow.h"
#include "src/page.h"
#include "ext/crow/crow.h"
#include "src/CmdLineOptions.h"
#include "src/MicroCore.h"
#include "src/page.h"
#include <fstream>
#include <regex>
@ -49,15 +50,14 @@ main(int ac, const char* av[])
auto no_blocks_on_index_opt = opts.get_option<string>("no-blocks-on-index");
auto testnet_url = opts.get_option<string>("testnet-url");
auto mainnet_url = opts.get_option<string>("mainnet-url");
auto network_info_timeout_opt = opts.get_option<string>("network-info-timeout");
auto mempool_info_timeout_opt = opts.get_option<string>("mempool-info-timeout");
auto mempool_refresh_time_opt = opts.get_option<string>("mempool-refresh-time");
auto testnet_opt = opts.get_option<bool>("testnet");
auto enable_key_image_checker_opt = opts.get_option<bool>("enable-key-image-checker");
auto enable_output_key_checker_opt = opts.get_option<bool>("enable-output-key-checker");
auto enable_autorefresh_option_opt = opts.get_option<bool>("enable-autorefresh-option");
auto enable_pusher_opt = opts.get_option<bool>("enable-pusher");
auto enable_mixin_details_opt = opts.get_option<bool>("enable-mixin-details");
auto enable_mempool_cache_opt = opts.get_option<bool>("enable-mempool-cache");
auto enable_json_api_opt = opts.get_option<bool>("enable-json-api");
auto enable_tx_cache_opt = opts.get_option<bool>("enable-tx-cache");
auto enable_block_cache_opt = opts.get_option<bool>("enable-block-cache");
@ -72,7 +72,6 @@ main(int ac, const char* av[])
bool enable_autorefresh_option {*enable_autorefresh_option_opt};
bool enable_output_key_checker {*enable_output_key_checker_opt};
bool enable_mixin_details {*enable_mixin_details_opt};
bool enable_mempool_cache {*enable_mempool_cache_opt};
bool enable_json_api {*enable_json_api_opt};
bool enable_tx_cache {*enable_tx_cache_opt};
bool enable_block_cache {*enable_block_cache_opt};
@ -155,22 +154,20 @@ main(int ac, const char* av[])
deamon_url = "http:://127.0.0.1:28081";
}
uint64_t network_info_timeout {1000};
uint64_t mempool_info_timeout {5000};
try
{
network_info_timeout = boost::lexical_cast<uint64_t>(*network_info_timeout_opt);
mempool_info_timeout = boost::lexical_cast<uint64_t>(*mempool_info_timeout_opt);
}
catch (boost::bad_lexical_cast &e)
{
cout << "Cant cast " << (*network_info_timeout_opt)
<< " or/and " << (*mempool_info_timeout_opt) <<" into numbers. Using default values."
cout << "Cant cast " << (*mempool_info_timeout_opt) <<" into numbers. Using default values."
<< endl;
}
uint64_t mempool_refresh_time {10};
if (enable_emission_monitor == true)
@ -204,6 +201,36 @@ main(int ac, const char* av[])
xmreg::CurrentBlockchainStatus::start_monitor_blockchain_thread();
}
xmreg::MempoolStatus::blockchain_path
= blockchain_path;
xmreg::MempoolStatus::testnet
= testnet;
xmreg::MempoolStatus::deamon_url
= deamon_url;
xmreg::MempoolStatus::set_blockchain_variables(
&mcore, core_storage);
try
{
mempool_refresh_time = boost::lexical_cast<uint64_t>(*mempool_refresh_time_opt);
}
catch (boost::bad_lexical_cast &e)
{
cout << "Cant cast " << (*mempool_refresh_time_opt)
<<" into number. Using default value."
<< endl;
}
// launch the status monitoring thread so that it keeps track of blockchain
// info, e.g., current height. Information from this thread is used
// by tx searching threads that are launched for each user independently,
// when they log back or create new account.
xmreg::MempoolStatus::mempool_refresh_time = mempool_refresh_time;
xmreg::MempoolStatus::start_mempool_status_thread();
// create instance of page class which
// contains logic for the website
xmreg::page xmrblocks(&mcore,
@ -215,12 +242,10 @@ main(int ac, const char* av[])
enable_output_key_checker,
enable_autorefresh_option,
enable_mixin_details,
enable_mempool_cache,
enable_tx_cache,
enable_block_cache,
show_cache_times,
no_blocks_on_index,
network_info_timeout,
mempool_info_timeout,
*testnet_url,
*mainnet_url);
@ -406,6 +431,17 @@ main(int ac, const char* av[])
return xmrblocks.mempool(true);
});
// alias to "/mempool"
CROW_ROUTE(app, "/txpool")
([&](const crow::request& req) {
return xmrblocks.mempool(true);
});
// CROW_ROUTE(app, "/altblocks")
// ([&](const crow::request& req) {
// return xmrblocks.altblocks();
// });
CROW_ROUTE(app, "/robots.txt")
([&]() {
string text = "User-agent: *\n"
@ -531,6 +567,45 @@ main(int ac, const char* av[])
return r;
});
CROW_ROUTE(app, "/api/outputsblocks").methods("GET"_method)
([&](const crow::request &req) {
string limit = regex_search(req.raw_url, regex {"limit=\\d+"}) ?
req.url_params.get("limit") : "3";
string address = regex_search(req.raw_url, regex {"address=\\w+"}) ?
req.url_params.get("address") : "";
string viewkey = regex_search(req.raw_url, regex {"viewkey=\\w+"}) ?
req.url_params.get("viewkey") : "";
bool in_mempool_aswell {false};
try
{
in_mempool_aswell = regex_search(req.raw_url, regex {"mempool=[01]"}) ?
boost::lexical_cast<bool>(req.url_params.get("mempool")) :
false;
}
catch (const boost::bad_lexical_cast &e)
{
cerr << "Cant parse tx_prove as bool. Using default value" << endl;
}
myxmr::jsonresponse r{xmrblocks.json_outputsblocks(limit, address, viewkey, in_mempool_aswell)};
return r;
});
CROW_ROUTE(app, "/api/version")
([&](const crow::request &req) {
myxmr::jsonresponse r{xmrblocks.json_version()};
return r;
});
}
if (enable_autorefresh_option)
@ -561,12 +636,24 @@ main(int ac, const char* av[])
if (enable_emission_monitor == true)
{
// finish Emission monitoring thread in a cotrolled manner.
cout << "Waiting for emission monitoring thread to finish." << endl;
xmreg::CurrentBlockchainStatus::m_thread.interrupt();
xmreg::CurrentBlockchainStatus::m_thread.join();
cout << "Emission monitoring thread joined." << endl;
cout << "Emission monitoring thread finished." << endl;
}
// finish mempool thread
cout << "Waiting for mempool monitoring thread to finish." << endl;
xmreg::MempoolStatus::m_thread.interrupt();
xmreg::MempoolStatus::m_thread.join();
cout << "Mempool monitoring thread finished." << endl;
cout << "The explorer is terminating." << endl;
return EXIT_SUCCESS;

@ -14,7 +14,7 @@ set(SOURCE_FILES
CmdLineOptions.cpp
page.h
rpccalls.cpp rpccalls.h
version.h.in CurrentBlockchainStatus.cpp)
version.h.in CurrentBlockchainStatus.cpp MempoolStatus.cpp MempoolStatus.h)
# make static library called libmyxrm
# that we are going to link to

@ -33,8 +33,6 @@ namespace xmreg
"enable key images file checker")
("enable-output-key-checker", value<bool>()->default_value(false)->implicit_value(true),
"enable outputs key file checker")
("enable-mempool-cache", value<bool>()->default_value(true),
"enable caching of transactions from the mempool")
("enable-json-api", value<bool>()->default_value(true),
"enable JSON REST api")
("enable-tx-cache", value<bool>()->default_value(false)->implicit_value(true),
@ -55,10 +53,10 @@ namespace xmreg
"you can specify mainnet url, if you run it on testnet. link will show on front page to mainnet explorer")
("no-blocks-on-index", value<string>()->default_value("10"),
"number of last blocks to be shown on index page")
("network-info-timeout", value<string>()->default_value("1000"),
"maximum time, in milliseconds, to wait for network info availability")
("mempool-info-timeout", value<string>()->default_value("5000"),
"maximum time, in milliseconds, to wait for mempool data for the front page")
("mempool-refresh-time", value<string>()->default_value("5"),
"time, in seconds, for each refresh of mempool state")
("bc-path,b", value<string>(),
"path to lmdb folder of the blockchain, e.g., ~/.bitmonero/lmdb")
("ssl-crt-file", value<string>(),

@ -0,0 +1,299 @@
//
// Created by mwo on 28/05/17.
//
#include "MempoolStatus.h"
#include "rpccalls.h"
namespace xmreg
{
using namespace std;
void
MempoolStatus::set_blockchain_variables(MicroCore *_mcore,
Blockchain *_core_storage)
{
mcore = _mcore;
core_storage = _core_storage;
}
void
MempoolStatus::start_mempool_status_thread()
{
// to protect from deviation by zero below.
mempool_refresh_time = std::max<uint64_t>(1, mempool_refresh_time);
if (!is_running)
{
m_thread = boost::thread{[]()
{
try
{
uint64_t loop_index {0};
// so that network status is checked every minute
uint64_t loop_index_divider = std::max<uint64_t>(1, 60 / mempool_refresh_time);
while (true)
{
// we just query network status every minute. No sense
// to do it as frequently as getting mempool data.
if (loop_index % loop_index_divider == 0)
{
if (!MempoolStatus::read_network_info())
{
network_info local_copy = current_network_info;
cerr << " Cant read network info "<< endl;
local_copy.current = false;
current_network_info = local_copy;
}
else
{
cout << "Current network info read, ";
loop_index == 0;
}
}
if (MempoolStatus::read_mempool())
{
vector<mempool_tx> current_mempool_txs = get_mempool_txs();
cout << "mempool status txs: "
<< current_mempool_txs.size()
<< endl;
}
// when we reach top of the blockchain, update
// the emission amount every minute.
boost::this_thread::sleep_for(
boost::chrono::seconds(mempool_refresh_time));
++loop_index;
} // while (true)
}
catch (boost::thread_interrupted&)
{
cout << "Mempool status thread interrupted." << endl;
return;
}
}}; // m_thread = boost::thread{[]()
is_running = true;
} // if (!is_running)
}
bool
MempoolStatus::read_mempool()
{
rpccalls rpc {deamon_url};
string error_msg;
// we populate this variable instead of global mempool_txs
// mempool_txs will be changed only when this function completes.
// this ensures that we don't sent out partial mempool txs to
// other places.
vector<mempool_tx> local_copy_of_mempool_txs;
// get txs in the mempool
std::vector<tx_info> mempool_tx_info;
if (!rpc.get_mempool(mempool_tx_info))
{
cerr << "Getting mempool failed " << endl;
return false;
}
// if dont have tx_blob member, construct tx
// from json obtained from the rpc call
uint64_t mempool_size_kB {0};
for (size_t i = 0; i < mempool_tx_info.size(); ++i)
{
// get transaction info of the tx in the mempool
const tx_info& _tx_info = mempool_tx_info.at(i);
crypto::hash mem_tx_hash = null_hash;
if (epee::string_tools::hex_to_pod(_tx_info.id_hash, mem_tx_hash))
{
transaction tx;
if (!xmreg::make_tx_from_json(_tx_info.tx_json, tx))
{
cerr << "Cant make tx from _tx_info.tx_json" << endl;
return false;
}
crypto::hash tx_hash_reconstructed = get_transaction_hash(tx);
if (mem_tx_hash != tx_hash_reconstructed)
{
cerr << "Hash of reconstructed tx from json does not match "
"what we should get!"
<< endl;
return false;
}
mempool_size_kB += _tx_info.blob_size;
local_copy_of_mempool_txs.push_back(mempool_tx {tx_hash_reconstructed, tx});
mempool_tx& last_tx = local_copy_of_mempool_txs.back();
// key images of inputs
vector<txin_to_key> input_key_imgs;
// public keys and xmr amount of outputs
vector<pair<txout_to_key, uint64_t>> output_pub_keys;
// sum xmr in inputs and ouputs in the given tx
const array<uint64_t, 4>& sum_data = summary_of_in_out_rct(
tx, output_pub_keys, input_key_imgs);
last_tx.receive_time = _tx_info.receive_time;
last_tx.sum_outputs = sum_data[0];
last_tx.sum_inputs = sum_data[1];
last_tx.no_outputs = output_pub_keys.size();
last_tx.no_inputs = input_key_imgs.size();
last_tx.mixin_no = sum_data[2];
last_tx.num_nonrct_inputs = sum_data[3];
last_tx.fee_str = xmreg::xmr_amount_to_str(_tx_info.fee, "{:0.3f}");
last_tx.xmr_inputs_str = xmreg::xmr_amount_to_str(last_tx.sum_inputs , "{:0.3f}");
last_tx.xmr_outputs_str = xmreg::xmr_amount_to_str(last_tx.sum_outputs, "{:0.3f}");
last_tx.timestamp_str = xmreg::timestamp_to_str_gm(_tx_info.receive_time);
last_tx.txsize = fmt::format("{:0.2f}",
static_cast<double>(_tx_info.blob_size)/1024.0);
} // if (hex_to_pod(_tx_info.id_hash, mem_tx_hash))
} // for (size_t i = 0; i < mempool_tx_info.size(); ++i)
Guard lck (mempool_mutx);
// clear current mempool txs vector
// repopulate it with each execution of read_mempool()
// not very efficient but good enough for now.
mempool_no = local_copy_of_mempool_txs.size();
mempool_size = mempool_size_kB;
mempool_txs = std::move(local_copy_of_mempool_txs);
return true;
}
bool
MempoolStatus::read_network_info()
{
rpccalls rpc {deamon_url};
COMMAND_RPC_GET_INFO::response rpc_network_info;
if (!rpc.get_network_info(rpc_network_info))
{
return false;
}
uint64_t fee_estimated;
string error_msg;
if (!rpc.get_dynamic_per_kb_fee_estimate(
FEE_ESTIMATE_GRACE_BLOCKS,
fee_estimated, error_msg))
{
cerr << "rpc.get_dynamic_per_kb_fee_estimate failed" << endl;
return false;
}
(void) error_msg;
network_info local_copy;
local_copy.status = network_info::get_status_uint(rpc_network_info.status);
local_copy.height = rpc_network_info.height;
local_copy.target_height = rpc_network_info.target_height;
local_copy.difficulty = rpc_network_info.difficulty;
local_copy.target = rpc_network_info.target;
local_copy.hash_rate = (rpc_network_info.difficulty/rpc_network_info.target);
local_copy.tx_count = rpc_network_info.tx_count;
local_copy.tx_pool_size = rpc_network_info.tx_pool_size;
local_copy.alt_blocks_count = rpc_network_info.alt_blocks_count;
local_copy.outgoing_connections_count = rpc_network_info.outgoing_connections_count;
local_copy.incoming_connections_count = rpc_network_info.incoming_connections_count;
local_copy.white_peerlist_size = rpc_network_info.white_peerlist_size;
local_copy.testnet = rpc_network_info.testnet;
local_copy.cumulative_difficulty = rpc_network_info.cumulative_difficulty;
local_copy.block_size_limit = rpc_network_info.block_size_limit;
local_copy.start_time = rpc_network_info.start_time;
epee::string_tools::hex_to_pod(rpc_network_info.top_block_hash, local_copy.top_block_hash);
local_copy.fee_per_kb = fee_estimated;
local_copy.info_timestamp = static_cast<uint64_t>(std::time(nullptr));
local_copy.current = true;
current_network_info = local_copy;
return true;
}
vector<MempoolStatus::mempool_tx>
MempoolStatus::get_mempool_txs()
{
Guard lck (mempool_mutx);
return mempool_txs;
}
vector<MempoolStatus::mempool_tx>
MempoolStatus::get_mempool_txs(uint64_t no_of_tx)
{
Guard lck (mempool_mutx);
no_of_tx = std::min<uint64_t>(no_of_tx, mempool_txs.size());
return vector<mempool_tx>(mempool_txs.begin(), mempool_txs.begin() + no_of_tx);
}
bool
MempoolStatus::is_thread_running()
{
return is_running;
}
bf::path MempoolStatus::blockchain_path {"/home/mwo/.bitmonero/lmdb"};
string MempoolStatus::deamon_url {"http:://127.0.0.1:18081"};
bool MempoolStatus::testnet {false};
atomic<bool> MempoolStatus::is_running {false};
boost::thread MempoolStatus::m_thread;
Blockchain* MempoolStatus::core_storage {nullptr};
xmreg::MicroCore* MempoolStatus::mcore {nullptr};
vector<MempoolStatus::mempool_tx> MempoolStatus::mempool_txs;
atomic<MempoolStatus::network_info> MempoolStatus::current_network_info;
atomic<uint64_t> MempoolStatus::mempool_no {0}; // no of txs
atomic<uint64_t> MempoolStatus::mempool_size {0}; // size in bytes.
uint64_t MempoolStatus::mempool_refresh_time {10};
mutex MempoolStatus::mempool_mutx;
}

@ -0,0 +1,155 @@
//
// Created by mwo on 28/05/17.
//
#ifndef XMRBLOCKS_MEMPOOLSTATUS_H
#define XMRBLOCKS_MEMPOOLSTATUS_H
#include "MicroCore.h"
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <memory>
#include <thread>
#include <mutex>
#include <atomic>
namespace xmreg
{
struct MempoolStatus
{
using Guard = std::lock_guard<std::mutex>;
struct mempool_tx
{
crypto::hash tx_hash;
transaction tx;
uint64_t receive_time {0};
uint64_t sum_inputs {0};
uint64_t sum_outputs {0};
uint64_t no_inputs {0};
uint64_t no_outputs {0};
uint64_t num_nonrct_inputs {0};
uint64_t mixin_no {0};
string fee_str;
string xmr_inputs_str;
string xmr_outputs_str;
string timestamp_str;
string txsize;
};
// to keep network_info in cache
// and to show previous info in case current querry for
// the current info timesout.
struct network_info
{
uint64_t status {0};
uint64_t height {0};
uint64_t target_height {0};
uint64_t difficulty {0};
uint64_t target {0};
uint64_t tx_count {0};
uint64_t tx_pool_size {0};
uint64_t alt_blocks_count {0};
uint64_t outgoing_connections_count {0};
uint64_t incoming_connections_count {0};
uint64_t white_peerlist_size {0};
uint64_t grey_peerlist_size {0};
bool testnet {false};
crypto::hash top_block_hash;
uint64_t cumulative_difficulty {0};
uint64_t block_size_limit {0};
uint64_t start_time {0};
uint64_t hash_rate {0};
uint64_t fee_per_kb {0};
uint64_t info_timestamp {0};
bool current {false};
static uint64_t
get_status_uint(const string& status)
{
if (status == CORE_RPC_STATUS_OK)
return 1;
if (status == CORE_RPC_STATUS_BUSY)
return 2;
// default
return 0;
}
static string
get_status_string(const uint64_t& status)
{
if (status == 1)
return CORE_RPC_STATUS_OK;
if (status == 2)
return CORE_RPC_STATUS_BUSY;
// default
return 0;
}
};
static boost::thread m_thread;
static mutex mempool_mutx;
static atomic<bool> is_running;
static uint64_t mempool_refresh_time;
static atomic<uint64_t> mempool_no; // no of txs
static atomic<uint64_t> mempool_size; // size in bytes.
static bf::path blockchain_path;
static string deamon_url;
static bool testnet;
// make object for accessing the blockchain here
static MicroCore* mcore;
static Blockchain* core_storage;
// vector of mempool transactions that all threads
// can refer to
// <recieved_time, transaction>
static vector<mempool_tx> mempool_txs;
static atomic<network_info> current_network_info;
static void
set_blockchain_variables(MicroCore* _mcore,
Blockchain* _core_storage);
static void
start_mempool_status_thread();
static bool
read_mempool();
static bool
read_network_info();
static vector<mempool_tx>
get_mempool_txs();
// get first no_of_tx from the vector
static vector<mempool_tx>
get_mempool_txs(uint64_t no_of_tx);
static bool
is_thread_running();
};
}
#endif //XMRBLOCKS_MEMPOOLSTATUS_H

File diff suppressed because it is too large Load Diff

@ -61,10 +61,6 @@ rpccalls::get_current_height()
<< deamon_url << endl;
return 0;
}
else
{
cout << "rpc call /getheight OK: " << endl;
}
return res.height;
}
@ -76,6 +72,9 @@ rpccalls::get_mempool(vector<tx_info>& mempool_txs)
COMMAND_RPC_GET_TRANSACTION_POOL::request req;
COMMAND_RPC_GET_TRANSACTION_POOL::response res;
bool r;
{
std::lock_guard<std::mutex> guard(m_daemon_rpc_mutex);
if (!connect_to_monero_deamon())
@ -84,18 +83,18 @@ rpccalls::get_mempool(vector<tx_info>& mempool_txs)
return false;
}
bool r = epee::net_utils::invoke_http_json(
r = epee::net_utils::invoke_http_json(
"/get_transaction_pool",
req, res, m_http_client, timeout_time_ms);
}
if (!r)
if (!r || res.status != CORE_RPC_STATUS_OK)
{
cerr << "Error connecting to Monero deamon at "
<< deamon_url << endl;
return false;
}
mempool_txs = res.transactions;
// mempool txs are not sorted base on their arival time,
@ -107,7 +106,6 @@ rpccalls::get_mempool(vector<tx_info>& mempool_txs)
return t1.receive_time > t2.receive_time;
});
return true;
}
@ -151,8 +149,10 @@ bool
rpccalls::get_network_info(COMMAND_RPC_GET_INFO::response& response)
{
epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_INFO::request> req_t = AUTO_VAL_INIT(req_t);
epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_INFO::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_INFO::request>
req_t = AUTO_VAL_INIT(req_t);
epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_INFO::response, std::string>
resp_t = AUTO_VAL_INIT(resp_t);
bool r {false};
@ -165,7 +165,7 @@ rpccalls::get_network_info(COMMAND_RPC_GET_INFO::response& response)
if (!connect_to_monero_deamon())
{
cerr << "get_mempool: not connected to deamon" << endl;
cerr << "get_network_info: not connected to deamon" << endl;
return false;
}
@ -226,12 +226,12 @@ rpccalls::get_dynamic_per_kb_fee_estimate(
bool r {false};
{
std::lock_guard<std::mutex> guard(m_daemon_rpc_mutex);
{
if (!connect_to_monero_deamon())
{
cerr << "get_current_height: not connected to deamon" << endl;
cerr << "get_dynamic_per_kb_fee_estimate: not connected to deamon" << endl;
return false;
}
@ -271,6 +271,74 @@ rpccalls::get_dynamic_per_kb_fee_estimate(
fee = resp_t.result.fee;
return true;
}
bool
rpccalls::get_block(string const& blk_hash, block& blk, string& error_msg)
{
epee::json_rpc::request<COMMAND_RPC_GET_BLOCK::request> req_t;
epee::json_rpc::response<COMMAND_RPC_GET_BLOCK::response, std::string> resp_t;
req_t.jsonrpc = "2.0";
req_t.id = epee::serialization::storage_entry(0);
req_t.method = "getblock";
req_t.params.hash = blk_hash;
bool r {false};
{
std::lock_guard<std::mutex> guard(m_daemon_rpc_mutex);
if (!connect_to_monero_deamon())
{
cerr << "get_block: not connected to deamon" << endl;
return false;
}
r = epee::net_utils::invoke_http_json("/json_rpc",
req_t, resp_t,
m_http_client);
}
string err;
if (r)
{
if (resp_t.result.status == CORE_RPC_STATUS_BUSY)
{
err = "daemon is busy. Please try again later.";
}
else if (resp_t.result.status != CORE_RPC_STATUS_OK)
{
err = resp_t.result.status;
}
if (!err.empty())
{
cerr << "Error connecting to Monero deamon due to "
<< err << endl;
return false;
}
}
else
{
cerr << "get_block: error connecting to Monero deamon at "
<< deamon_url << endl;
return false;
}
std::string block_bin_blob;
if(!epee::string_tools::parse_hexstr_to_binbuff(resp_t.result.blob, block_bin_blob))
return false;
return parse_and_validate_block_from_blob(block_bin_blob, blk);
}
}

@ -10,6 +10,51 @@
#include <mutex>
namespace
{
// can be used to check if given class/struct exist
// from: https://stackoverflow.com/a/10722840/248823
template <typename T>
struct has_destructor
{
// has destructor
template <typename A>
static std::true_type test(decltype(declval<A>().~A()) *)
{
return std::true_type();
}
// no constructor
template <typename A>
static std::false_type test(...)
{
return std::false_type();
}
/* This will be either `std::true_type` or `std::false_type` */
typedef decltype(test<T>(0)) type;
static const bool value = type::value;
};
}
namespace cryptonote
{
// declare struct in monero's cryptonote namespace.
// monero should provide definition for this,
// but we need to have it declared as we are going to
// check if its definition exist or not. depending on this
// we decide what gets to be defined as
// get_alt_blocks(vector<string>& alt_blocks_hashes);
struct COMMAND_RPC_GET_ALT_BLOCKS_HASHES;
}
namespace xmreg
{
@ -18,6 +63,7 @@ using namespace crypto;
using namespace std;
class rpccalls
{
string deamon_url ;
@ -58,6 +104,84 @@ public:
uint64_t& fee,
string& error_msg);
/**
* This must be in the header for now, as it will be tempalte function
*
* @param alt_blocks_hashes
* @return bool
*/
template<typename T = COMMAND_RPC_GET_ALT_BLOCKS_HASHES>
typename enable_if<has_destructor<T>::value, bool>::type
get_alt_blocks(vector<string>& alt_blocks_hashes)
{
// definition of COMMAND_RPC_GET_ALT_BLOCKS_HASHES exist
// so perform rpc call to get this information
bool r {false};
typename T::request req;
typename T::response resp;
{
std::lock_guard<std::mutex> guard(m_daemon_rpc_mutex);
if (!connect_to_monero_deamon())
{
cerr << "get_alt_blocks: not connected to deamon" << endl;
return false;
}
r = epee::net_utils::invoke_http_json("/get_alt_blocks_hashes",
req, resp,
m_http_client);
}
string err;
if (r)
{
if (resp.status == CORE_RPC_STATUS_BUSY)
{
err = "daemon is busy. Please try again later.";
}
else if (resp.status != CORE_RPC_STATUS_OK)
{
err = "daemon rpc failed. Please try again later.";
}
if (!err.empty())
{
cerr << "Error connecting to Monero deamon due to "
<< err << endl;
return false;
}
}
else
{
cerr << "Error connecting to Monero deamon at "
<< deamon_url << endl;
return false;
}
alt_blocks_hashes = resp.blks_hashes;
return true;
}
template<typename T = COMMAND_RPC_GET_ALT_BLOCKS_HASHES>
typename enable_if<!has_destructor<T>::value, bool>::type
get_alt_blocks(vector<string>& alt_blocks_hashes)
{
cerr << "COMMAND_RPC_GET_ALT_BLOCKS_HASHES does not exist!" << endl;
// definition of COMMAND_RPC_GET_ALT_BLOCKS_HASHES does NOT exist
// so dont do anything
return false;
}
bool
get_block(string const& blk_hash, block& blk, string& error_msg);
};

@ -0,0 +1,25 @@
<h2 style="margin-bottom: 0px">
Alternative blocks
</h2>
<h4 style="font-size: 14px; margin-top: 0px">(no of alt blocks: {{no_alt_blocks}})</h4>
<div class="center">
<table class="center" style="width:80%">
<tr>
<td>height</td>
<td>age</td>
<td>hash</td>
<td>txs no</td>
</tr>
{{#blocks}}
<tr>
<td>{{height}}</td>
<td>{{age}}</td>
<td>{{hash}}</td>
<td>{{no_of_txs}}</td>
</tr>
{{/blocks}}
</table>
</div>

@ -1,7 +1,7 @@
<div class="center">
<h6 style="margin-top:10px">
<a href="https://github.com/moneroexamples/onion-monero-blockchain-explorer">source code</a>
| explorer version: {{git_branch_name}}-{{last_git_commit_date}}-{{last_git_commit_hash}}
| explorer version (api): {{git_branch_name}}-{{last_git_commit_date}}-{{last_git_commit_hash}} ({{api}})
| monero version: {{monero_version_full}}
</h6>
</div>

@ -2,9 +2,9 @@
<div class="center">
<h3 style="font-size: 12px; margin-top: 20px">
Server time: {{server_timestamp}} | <a href="/mempool">Memory pool</a>
Server time: {{server_timestamp}} | <a href="/txpool">Transaction pool</a>
{{#enable_pusher}}
| <a href="/rawtx">Tx pusher </a>
| <a href="/rawtx">Transaction pusher </a>
{{/enable_pusher}}
{{#enable_key_image_checker}}
| <a href="/rawkeyimgs">Key images checker</a>
@ -39,7 +39,7 @@
Network difficulty: {{difficulty}}
| Hash rate: {{hash_rate}}
| Fee per kb: {{fee_per_kb}}
| Alternative blocks no: {{alt_blocks_no}}
| Median block size limit: {{block_size_limit}} kB
{{^is_current_info}}
| Data from {{age}} {{age_format}} ago
{{/is_current_info}}
@ -66,8 +66,6 @@
<h4 style="font-size: 14px; margin-top: 0px">(Median size of these blocks: {{blk_size_median}} kB)</h4>
<div class="center">
<table class="center">

@ -1,7 +1,7 @@
<h2 style="margin-bottom: 0px">
Memory pool
Transaction pool
</h2>
<h4 style="font-size: 14px; margin-top: 0px">(no of txs: {{mempool_size}}, size: {{mempool_size_kB}} kB)</h4>
<h4 style="font-size: 12px; margin-top: 0px">(no of txs: {{mempool_size}}, size: {{mempool_size_kB}} kB, updated every {{ mempool_refresh_time }} seconds)</h4>
<div class="center">
<table class="center" style="width:80%">
@ -30,24 +30,11 @@
{{^mempool_fits_on_front_page}}
{{#partial_mempool_shown}}
<div class="center" style="text-align: center; margin-bottom: 10px">
<a href="/mempool">Only {{no_of_mempool_tx_of_frontpage}} txs shown. Click here to see all of them</a>
<a href="/txpool">Only {{no_of_mempool_tx_of_frontpage}} txs shown. Click here to see all of them</a>
</div>
{{/partial_mempool_shown}}
{{/mempool_fits_on_front_page}}
{{#show_cache_times}}
<div class="center">
<h6 style="margin-top: 1px;color:#949490">
Mempoool tx details construction time: {{construction_time_total}} s
<br/>
includes {{construction_time_cached}} s from mempool cache ({{cache_hits}} hits)
and {{construction_time_non_cached}} s from non cache ({{cache_misses}} misses)
</h6>
</div>
{{/show_cache_times}}
</div>

@ -1,15 +1,15 @@
<h2 style="margin-bottom: 0px">
Memory pool
Transaction pool
</h2>
<h4 style="font-size: 14px; margin-top: 0px"></h4>
<div class="center info" style="text-align: center;width:80%;color:#949490">
<p>Mempool data preparation for the front page failed.
<p>Txpool data preparation for the front page failed.
Its processing
{{#network_info}}{{^is_pool_size_zero}}({{tx_pool_size}} txs){{/is_pool_size_zero}}{{/network_info}}
took longer than expected and it timed out.
To view the mempool without time constrain,
go to dedicated mempool page: <a href="/mempool">memory pool</a>
To view the txpool without time constrain,
go to dedicated txpool page: <a href="/txpool">memory pool</a>
</p>

@ -151,7 +151,7 @@
{{#show_part_of_inputs}}
<h5 style="margin-top: 2px">
Only {{max_no_of_inputs_to_show}} are inputs shown. To see all,
Only {{max_no_of_inputs_to_show}} inputs are shown. To see all,
click "<a href="/tx/{{tx_hash}}/1">more details</a>"
</h5>
{{/show_part_of_inputs}}

@ -18,7 +18,7 @@
{{^has_error}}
<h4 style="color:green">Success</h4>
<h4>
Your tx should be already in the mempool waiting to be included
Your tx should be already in the txpool waiting to be included
in an upcoming block.
</h4>

@ -3,7 +3,7 @@
{{#no_results}}
<h4 style="margin-bottom:2px">Nothing in the blockchain has been found that matches the search term :-(</h4>
<h5 style="margin:2px">Note: there might be 10 block delay between what can be searchable (e.g., key images)</h5>
<h5 style="margin:2px">Note: there might be some delay when newest txs become searchable</h5>
{{/no_results}}
{{#to_many_results}}

@ -1,8 +1,22 @@
<div>
{{#has_error}}
<h4 style="color:red">Attempt failed</h4>
{{#error_tx_not_found}}
<h4>Tx {{tx_hash}} not found. </h4>
<div class="center" style="text-align: center;width:80%">
<p> If this is newly made tx, it can take some time (up to minute)
for it to get propagated to all nodes' txpools.
<br/><br/>
Please refresh in 10-20 seconds to check if its here then.
</p>
</div>
{{/error_tx_not_found}}
{{/has_error}}
{{^has_error}}
{{#txs}}
{{>tx_details}}
{{/txs}}
{{/has_error}}
</div>

@ -894,16 +894,6 @@ namespace xmreg
return make_pair(empty_time, scale);
}
// useful reference to get epoch time in correct timezon
// http://www.boost.org/doc/libs/1_41_0/doc/html/date_time/examples.html#date_time.examples.seconds_since_epoch
time_t
ptime_to_time_t(const pt::ptime& in_ptime)
{
static pt::ptime epoch(gt::date(1970, 1, 1));
pt::time_duration::sec_type no_seconds = (in_ptime - epoch).total_seconds();
return time_t(no_seconds);
}
bool
decode_ringct(const rct::rctSig& rv,
const crypto::public_key pub,

@ -13,9 +13,10 @@
#define REMOVE_HASH_BRAKETS(a_hash) \
a_hash.substr(1, a_hash.size()-2)
#include "monero_headers.h"
#include "../ext/infix_iterator.h"
#include "../ext/fmt/ostream.h"
#include "../ext/fmt/format.h"
#include "../ext/json.hpp"
@ -23,14 +24,14 @@
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <string>
#include <vector>
#include <array>
#include <iterator>
#include <algorithm>
#include <type_traits>
/**
* Some helper functions used in the example.
@ -45,9 +46,6 @@ namespace xmreg
using namespace std;
namespace bf = boost::filesystem;
namespace pt = boost::posix_time;
namespace gt = boost::gregorian;
namespace lt = boost::local_time;
using json = nlohmann::json;
@ -216,30 +214,11 @@ namespace xmreg
read(string filename);
/**
* prints an iterable such as vector
*/
template<typename T>
void print_iterable(const T & elems) {
infix_ostream_iterator<typename T::value_type>
oiter(std::cout, ",");
std::cout << "[";
std::copy(elems.begin(), elems.end(),oiter);
std::cout << "]" << std::endl;
}
pair<string, double>
timestamps_time_scale(const vector<uint64_t>& timestamps,
uint64_t timeN, uint64_t resolution = 80,
uint64_t time0 = 1397818193 /* timestamp of the second block */);
time_t
ptime_to_time_t(const pt::ptime& in_ptime);
bool
decode_ringct(const rct::rctSig & rv,
const crypto::public_key pub,

Loading…
Cancel
Save