mirror of
https://git.wownero.com/wownero/onion-wownero-blockchain-explorer.git
synced 2024-08-15 00:33:12 +00:00
Merge pull request #75 from moneroexamples/update_to_current_monero
Update to current monero
This commit is contained in:
commit
7eca176e6a
27 changed files with 8502 additions and 5896 deletions
|
@ -100,7 +100,7 @@ set(LIBRARIES
|
|||
cryptonote_protocol
|
||||
cryptonote_basic
|
||||
daemonizer
|
||||
cryptoxmr
|
||||
cncrypto
|
||||
blocks
|
||||
lmdb
|
||||
ringct
|
||||
|
|
156
README.md
156
README.md
|
@ -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)
|
||||
|
@ -394,7 +394,7 @@ namespace crow
|
|||
#else
|
||||
template <typename Func, unsigned ... Indices>
|
||||
#endif
|
||||
std::function<void(const request&, response&, const routing_params&)>
|
||||
std::function<void(const request&, response&, const routing_params&)>
|
||||
wrap(Func f, black_magic::seq<Indices...>)
|
||||
{
|
||||
#ifdef CROW_MSVC_WORKAROUND
|
||||
|
@ -403,16 +403,14 @@ namespace crow
|
|||
using function_t = utility::function_traits<Func>;
|
||||
#endif
|
||||
if (!black_magic::is_parameter_tag_compatible(
|
||||
black_magic::get_parameter_tag_runtime(rule_.c_str()),
|
||||
black_magic::get_parameter_tag_runtime(rule_.c_str()),
|
||||
black_magic::compute_parameter_tag_from_args_list<
|
||||
typename function_t::template arg<Indices>...>::value))
|
||||
{
|
||||
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
|
||||
|
10308
ext/json.hpp
10308
ext/json.hpp
File diff suppressed because it is too large
Load diff
1913
ext/lmdb++.h
1913
ext/lmdb++.h
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
|
113
main.cpp
113
main.cpp
|
@ -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>(),
|
||||
|
|
299
src/MempoolStatus.cpp
Normal file
299
src/MempoolStatus.cpp
Normal file
|
@ -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;
|
||||
}
|
155
src/MempoolStatus.h
Normal file
155
src/MempoolStatus.h
Normal file
|
@ -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
|
961
src/page.h
961
src/page.h
File diff suppressed because it is too large
Load diff
112
src/rpccalls.cpp
112
src/rpccalls.cpp
|
@ -61,10 +61,6 @@ rpccalls::get_current_height()
|
|||
<< deamon_url << endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "rpc call /getheight OK: " << endl;
|
||||
}
|
||||
|
||||
return res.height;
|
||||
}
|
||||
|
@ -76,26 +72,29 @@ rpccalls::get_mempool(vector<tx_info>& mempool_txs)
|
|||
COMMAND_RPC_GET_TRANSACTION_POOL::request req;
|
||||
COMMAND_RPC_GET_TRANSACTION_POOL::response res;
|
||||
|
||||
std::lock_guard<std::mutex> guard(m_daemon_rpc_mutex);
|
||||
bool r;
|
||||
|
||||
if (!connect_to_monero_deamon())
|
||||
{
|
||||
cerr << "get_mempool: not connected to deamon" << endl;
|
||||
return false;
|
||||
std::lock_guard<std::mutex> guard(m_daemon_rpc_mutex);
|
||||
|
||||
if (!connect_to_monero_deamon())
|
||||
{
|
||||
cerr << "get_mempool: not connected to deamon" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
r = epee::net_utils::invoke_http_json(
|
||||
"/get_transaction_pool",
|
||||
req, res, m_http_client, timeout_time_ms);
|
||||
}
|
||||
|
||||
bool 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);
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
124
src/rpccalls.h
124
src/rpccalls.h
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
25
src/templates/altblocks.html
Normal file
25
src/templates/altblocks.html
Normal file
|
@ -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>
|
||||
|
||||
{{#txs}}
|
||||
{{>tx_details}}
|
||||
{{/txs}}
|
||||
|
||||
{{#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,
|
||||
|
|
31
src/tools.h
31
src/tools.h
|
@ -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;
|
||||
|
||||
|
@ -139,7 +137,7 @@ namespace xmreg
|
|||
vector<pair<txout_to_key, uint64_t>>& output_pub_keys,
|
||||
vector<txin_to_key>& input_key_imgs);
|
||||
|
||||
// this version for mempool txs from json
|
||||
// this version for mempool txs from json
|
||||
array<uint64_t, 6>
|
||||
summary_of_in_out_rct(const json& _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…
Reference in a new issue