Merge pull request #149 from moneroexamples/devel

For Monero version 0.13
master
moneroexamples 6 years ago committed by GitHub
commit e6006acf48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,9 +6,7 @@ set(PROJECT_NAME
project(${PROJECT_NAME}) project(${PROJECT_NAME})
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_STANDARD 11)
"${CMAKE_CXX_FLAGS} -std=c++14")
if (WIN32) if (WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj -O3") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj -O3")
@ -119,7 +117,7 @@ set(LIBRARIES
checkpoints checkpoints
version version
epee epee
pcsclite sodium
${Boost_LIBRARIES} ${Boost_LIBRARIES}
pthread pthread
unbound unbound
@ -130,7 +128,7 @@ set(LIBRARIES
if(APPLE) if(APPLE)
set(LIBRARIES ${LIBRARIES} "-framework IOKit -framework PCSC") set(LIBRARIES ${LIBRARIES} "-framework IOKit -framework PCSC")
else() else()
set(LIBRARIES ${LIBRARIES} atomic) set(LIBRARIES ${LIBRARIES} atomic pcsclite)
endif() endif()
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT WIN32) if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT WIN32)

@ -28,24 +28,22 @@ Tor users:
- [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://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)).
Clearnet versions: Clearnet versions:
- [https://labor.serveo.net/](https://labor.serveo.net/) - temprorary link (slow), bleading edge version.
- [https://xmrchain.net/](https://xmrchain.net/) - https enabled, most popular and very stable. - [https://xmrchain.net/](https://xmrchain.net/) - https enabled, most popular and very stable.
- [https://MoneroExplorer.com/](https://moneroexplorer.com/) - nice looking one, https enabled. - [https://MoneroExplorer.com/](https://moneroexplorer.com/) - nice looking one, https enabled.
- [https://monerohash.com/explorer/](https://monerohash.com/explorer/) - nice looking one, https enabled. - [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. - [http://explore.MoneroWorld.com](http://explore.moneroworld.com) - same as the second one.
- [https://moneroexplorer.pro/](https://moneroexplorer.pro/) - nice looking one, https enabled.
- [http://monerochain.com/](http://monerochain.com/) - JSON API based, multiple nodes. - [http://monerochain.com/](http://monerochain.com/) - JSON API based, multiple nodes.
- [https://blox.minexmr.com/](https://blox.minexmr.com/) - - https enabled. - [https://blox.minexmr.com/](https://blox.minexmr.com/) - - https enabled.
Testnet version: Testnet version:
- [http://nimis.serveo.net/](http://nimis.serveo.net/) - bleeding edge version (down currently).
- [https://testnet.xmrchain.com/](https://testnet.xmrchain.com/) - https enabled. - [https://testnet.xmrchain.com/](https://testnet.xmrchain.com/) - https enabled.
- [https://explorer.monero-otc.com/](https://explorer.monero-otc.com/) - https enabled. - [https://explorer.monero-otc.com/](https://explorer.monero-otc.com/) - https enabled.
Stagenet version: Stagenet version:
- [http://162.210.173.150:8083/](http://162.210.173.150:8083/) - recent version. - [https://stagenet.xmrchain.net/](https://stagenet.xmrchain.net/)
- [http://162.210.173.150:8083/](http://162.210.173.150:8083/)
i2p users (main Monero network): i2p users (main Monero network):
@ -54,7 +52,6 @@ i2p users (main Monero network):
Alternative block explorers: Alternative block explorers:
- [http://moneroblocks.info](http://moneroblocks.info/) - [http://moneroblocks.info](http://moneroblocks.info/)
- [https://monerobase.com](https://monerobase.com/)
- [https://monerovision.com](https://monerovision.com) - [https://monerovision.com](https://monerovision.com)
- [http://chainradar.com](http://chainradar.com/xmr/blocks) - [http://chainradar.com](http://chainradar.com/xmr/blocks)
@ -93,7 +90,7 @@ Current development branch:
## Compilation on Ubuntu 16.04/18.04 ## Compilation on Ubuntu 16.04/18.04
##### Compile latest Monero development version ##### Compile latest Monero version (0.13)
Download and compile recent Monero into your home folder: Download and compile recent Monero into your home folder:
@ -110,10 +107,8 @@ git clone --recursive https://github.com/monero-project/monero
cd monero/ cd monero/
# checkout last monero version
git checkout -b last_release v0.12.1.0
make USE_SINGLE_BUILDDIR=1 make
``` ```
##### Compile and run the explorer ##### Compile and run the explorer
@ -697,7 +692,6 @@ curl -w "\n" -X GET http://127.0.0.1:8081/api/outputsblocks?address=9sDyNU82ih1
Example result: Example result:
```json ```json
{
{ {
"data": { "data": {
"address": "0182d5be0f708cecf2b6f9889738bde5c930fad846d5b530e021afd1ae7e24a687ad50af3a5d38896655669079ad0163b4a369f6c852cc816dace5fc7792b72f", "address": "0182d5be0f708cecf2b6f9889738bde5c930fad846d5b530e021afd1ae7e24a687ad50af3a5d38896655669079ad0163b4a369f6c852cc816dace5fc7792b72f",

File diff suppressed because it is too large Load Diff

@ -44,6 +44,7 @@ main(int ac, const char* av[])
} }
auto port_opt = opts.get_option<string>("port"); auto port_opt = opts.get_option<string>("port");
auto bindaddr_opt = opts.get_option<string>("bindaddr");
auto bc_path_opt = opts.get_option<string>("bc-path"); auto bc_path_opt = opts.get_option<string>("bc-path");
auto deamon_url_opt = opts.get_option<string>("deamon-url"); auto deamon_url_opt = opts.get_option<string>("deamon-url");
auto ssl_crt_file_opt = opts.get_option<string>("ssl-crt-file"); auto ssl_crt_file_opt = opts.get_option<string>("ssl-crt-file");
@ -63,6 +64,7 @@ main(int ac, const char* av[])
auto enable_js_opt = opts.get_option<bool>("enable-js"); auto enable_js_opt = opts.get_option<bool>("enable-js");
auto enable_mixin_details_opt = opts.get_option<bool>("enable-mixin-details"); auto enable_mixin_details_opt = opts.get_option<bool>("enable-mixin-details");
auto enable_json_api_opt = opts.get_option<bool>("enable-json-api"); auto enable_json_api_opt = opts.get_option<bool>("enable-json-api");
auto enable_as_hex_opt = opts.get_option<bool>("enable-as-hex");
auto enable_tx_cache_opt = opts.get_option<bool>("enable-tx-cache"); auto enable_tx_cache_opt = opts.get_option<bool>("enable-tx-cache");
auto enable_block_cache_opt = opts.get_option<bool>("enable-block-cache"); auto enable_block_cache_opt = opts.get_option<bool>("enable-block-cache");
auto show_cache_times_opt = opts.get_option<bool>("show-cache-times"); auto show_cache_times_opt = opts.get_option<bool>("show-cache-times");
@ -90,6 +92,7 @@ main(int ac, const char* av[])
bool enable_output_key_checker {*enable_output_key_checker_opt}; bool enable_output_key_checker {*enable_output_key_checker_opt};
bool enable_mixin_details {*enable_mixin_details_opt}; bool enable_mixin_details {*enable_mixin_details_opt};
bool enable_json_api {*enable_json_api_opt}; bool enable_json_api {*enable_json_api_opt};
bool enable_as_hex {*enable_as_hex_opt};
bool enable_tx_cache {*enable_tx_cache_opt}; bool enable_tx_cache {*enable_tx_cache_opt};
bool enable_block_cache {*enable_block_cache_opt}; bool enable_block_cache {*enable_block_cache_opt};
bool enable_emission_monitor {*enable_emission_monitor_opt}; bool enable_emission_monitor {*enable_emission_monitor_opt};
@ -100,9 +103,13 @@ main(int ac, const char* av[])
uint32_t log_level = 0; uint32_t log_level = 0;
mlog_configure("", true); mlog_configure("", true);
(void) log_level;
//cast port number in string to uint //cast port number in string to uint
uint16_t app_port = boost::lexical_cast<uint16_t>(*port_opt); uint16_t app_port = boost::lexical_cast<uint16_t>(*port_opt);
string bindaddr = *bindaddr_opt;
// cast no_blocks_on_index_opt to uint // cast no_blocks_on_index_opt to uint
uint64_t no_blocks_on_index = boost::lexical_cast<uint64_t>(*no_blocks_on_index_opt); uint64_t no_blocks_on_index = boost::lexical_cast<uint64_t>(*no_blocks_on_index_opt);
@ -259,6 +266,7 @@ main(int ac, const char* av[])
nettype, nettype,
enable_pusher, enable_pusher,
enable_js, enable_js,
enable_as_hex,
enable_key_image_checker, enable_key_image_checker,
enable_output_key_checker, enable_output_key_checker,
enable_autorefresh_option, enable_autorefresh_option,
@ -282,7 +290,7 @@ main(int ac, const char* av[])
}; };
CROW_ROUTE(app, "/") CROW_ROUTE(app, "/")
([&](const crow::request& req) { ([&]() {
return crow::response(xmrblocks.index2()); return crow::response(xmrblocks.index2());
}); });
@ -292,20 +300,43 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/block/<uint>") CROW_ROUTE(app, "/block/<uint>")
([&](const crow::request& req, size_t block_height) { ([&](size_t block_height) {
return crow::response(xmrblocks.show_block(block_height)); return crow::response(xmrblocks.show_block(block_height));
}); });
CROW_ROUTE(app, "/block/<string>") CROW_ROUTE(app, "/block/<string>")
([&](const crow::request& req, string block_hash) { ([&](string block_hash) {
return crow::response(xmrblocks.show_block(remove_bad_chars(block_hash))); return crow::response(xmrblocks.show_block(remove_bad_chars(block_hash)));
}); });
CROW_ROUTE(app, "/tx/<string>") CROW_ROUTE(app, "/tx/<string>")
([&](const crow::request& req, string tx_hash) { ([&](string tx_hash) {
return crow::response(xmrblocks.show_tx(remove_bad_chars(tx_hash))); return crow::response(xmrblocks.show_tx(remove_bad_chars(tx_hash)));
}); });
if (enable_as_hex)
{
CROW_ROUTE(app, "/txhex/<string>")
([&](string tx_hash) {
return crow::response(xmrblocks.show_tx_hex(remove_bad_chars(tx_hash)));
});
CROW_ROUTE(app, "/ringmembershex/<string>")
([&](string tx_hash) {
return crow::response(xmrblocks.show_ringmembers_hex(remove_bad_chars(tx_hash)));
});
CROW_ROUTE(app, "/blockhex/<uint>")
([&](size_t block_height) {
return crow::response(xmrblocks.show_block_hex(block_height, false));
});
CROW_ROUTE(app, "/blockhexcomplete/<uint>")
([&](size_t block_height) {
return crow::response(xmrblocks.show_block_hex(block_height, true));
});
}
CROW_ROUTE(app, "/tx/<string>/<uint>") CROW_ROUTE(app, "/tx/<string>/<uint>")
([&](string tx_hash, uint16_t with_ring_signatures) ([&](string tx_hash, uint16_t with_ring_signatures)
{ {
@ -403,7 +434,7 @@ main(int ac, const char* av[])
if (enable_pusher) if (enable_pusher)
{ {
CROW_ROUTE(app, "/rawtx") CROW_ROUTE(app, "/rawtx")
([&](const crow::request& req) { ([&]() {
return xmrblocks.show_rawtx(); return xmrblocks.show_rawtx();
}); });
@ -433,7 +464,7 @@ main(int ac, const char* av[])
if (enable_key_image_checker) if (enable_key_image_checker)
{ {
CROW_ROUTE(app, "/rawkeyimgs") CROW_ROUTE(app, "/rawkeyimgs")
([&](const crow::request& req) { ([&]() {
return xmrblocks.show_rawkeyimgs(); return xmrblocks.show_rawkeyimgs();
}); });
@ -464,7 +495,7 @@ main(int ac, const char* av[])
if (enable_output_key_checker) if (enable_output_key_checker)
{ {
CROW_ROUTE(app, "/rawoutputkeys") CROW_ROUTE(app, "/rawoutputkeys")
([&](const crow::request& req) { ([&]() {
return xmrblocks.show_rawoutputkeys(); return xmrblocks.show_rawoutputkeys();
}); });
@ -499,13 +530,13 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/mempool") CROW_ROUTE(app, "/mempool")
([&](const crow::request& req) { ([&]() {
return xmrblocks.mempool(true); return xmrblocks.mempool(true);
}); });
// alias to "/mempool" // alias to "/mempool"
CROW_ROUTE(app, "/txpool") CROW_ROUTE(app, "/txpool")
([&](const crow::request& req) { ([&]() {
return xmrblocks.mempool(true); return xmrblocks.mempool(true);
}); });
@ -526,52 +557,52 @@ main(int ac, const char* av[])
cout << "Enable JavaScript checking of outputs and proving txs\n"; cout << "Enable JavaScript checking of outputs and proving txs\n";
CROW_ROUTE(app, "/js/jquery.min.js") CROW_ROUTE(app, "/js/jquery.min.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("jquery.min.js"); return xmrblocks.get_js_file("jquery.min.js");
}); });
CROW_ROUTE(app, "/js/crc32.js") CROW_ROUTE(app, "/js/crc32.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("crc32.js"); return xmrblocks.get_js_file("crc32.js");
}); });
CROW_ROUTE(app, "/js/biginteger.js") CROW_ROUTE(app, "/js/biginteger.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("biginteger.js"); return xmrblocks.get_js_file("biginteger.js");
}); });
CROW_ROUTE(app, "/js/crypto.js") CROW_ROUTE(app, "/js/crypto.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("crypto.js"); return xmrblocks.get_js_file("crypto.js");
}); });
CROW_ROUTE(app, "/js/config.js") CROW_ROUTE(app, "/js/config.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("config.js"); return xmrblocks.get_js_file("config.js");
}); });
CROW_ROUTE(app, "/js/nacl-fast-cn.js") CROW_ROUTE(app, "/js/nacl-fast-cn.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("nacl-fast-cn.js"); return xmrblocks.get_js_file("nacl-fast-cn.js");
}); });
CROW_ROUTE(app, "/js/base58.js") CROW_ROUTE(app, "/js/base58.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("base58.js"); return xmrblocks.get_js_file("base58.js");
}); });
CROW_ROUTE(app, "/js/cn_util.js") CROW_ROUTE(app, "/js/cn_util.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("cn_util.js"); return xmrblocks.get_js_file("cn_util.js");
}); });
CROW_ROUTE(app, "/js/sha3.js") CROW_ROUTE(app, "/js/sha3.js")
([&](const crow::request& req) { ([&]() {
return xmrblocks.get_js_file("sha3.js"); return xmrblocks.get_js_file("sha3.js");
}); });
CROW_ROUTE(app, "/js/all_in_one.js") CROW_ROUTE(app, "/js/all_in_one.js")
([&](const crow::request& req) { ([&]() {
// /js/all_in_one.js file does not exist. it is generated on the fly // /js/all_in_one.js file does not exist. it is generated on the fly
// from the above real files. // from the above real files.
return xmrblocks.get_js_file("all_in_one.js"); return xmrblocks.get_js_file("all_in_one.js");
@ -585,7 +616,7 @@ main(int ac, const char* av[])
cout << "Enable JSON API\n"; cout << "Enable JSON API\n";
CROW_ROUTE(app, "/api/transaction/<string>") CROW_ROUTE(app, "/api/transaction/<string>")
([&](const crow::request &req, string tx_hash) { ([&](string tx_hash) {
myxmr::jsonresponse r{xmrblocks.json_transaction(remove_bad_chars(tx_hash))}; myxmr::jsonresponse r{xmrblocks.json_transaction(remove_bad_chars(tx_hash))};
@ -593,15 +624,23 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/api/rawtransaction/<string>") CROW_ROUTE(app, "/api/rawtransaction/<string>")
([&](const crow::request &req, string tx_hash) { ([&](string tx_hash) {
myxmr::jsonresponse r{xmrblocks.json_rawtransaction(remove_bad_chars(tx_hash))}; myxmr::jsonresponse r{xmrblocks.json_rawtransaction(remove_bad_chars(tx_hash))};
return r; return r;
}); });
CROW_ROUTE(app, "/api/detailedtransaction/<string>")
([&](string tx_hash) {
myxmr::jsonresponse r{xmrblocks.json_detailedtransaction(remove_bad_chars(tx_hash))};
return r;
});
CROW_ROUTE(app, "/api/block/<string>") CROW_ROUTE(app, "/api/block/<string>")
([&](const crow::request &req, string block_no_or_hash) { ([&](string block_no_or_hash) {
myxmr::jsonresponse r{xmrblocks.json_block(remove_bad_chars(block_no_or_hash))}; myxmr::jsonresponse r{xmrblocks.json_block(remove_bad_chars(block_no_or_hash))};
@ -609,7 +648,7 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/api/rawblock/<string>") CROW_ROUTE(app, "/api/rawblock/<string>")
([&](const crow::request &req, string block_no_or_hash) { ([&](string block_no_or_hash) {
myxmr::jsonresponse r{xmrblocks.json_rawblock(remove_bad_chars(block_no_or_hash))}; myxmr::jsonresponse r{xmrblocks.json_rawblock(remove_bad_chars(block_no_or_hash))};
@ -650,7 +689,7 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/api/search/<string>") CROW_ROUTE(app, "/api/search/<string>")
([&](const crow::request &req, string search_value) { ([&](string search_value) {
myxmr::jsonresponse r{xmrblocks.json_search(remove_bad_chars(search_value))}; myxmr::jsonresponse r{xmrblocks.json_search(remove_bad_chars(search_value))};
@ -658,7 +697,7 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/api/networkinfo") CROW_ROUTE(app, "/api/networkinfo")
([&](const crow::request &req) { ([&]() {
myxmr::jsonresponse r{xmrblocks.json_networkinfo()}; myxmr::jsonresponse r{xmrblocks.json_networkinfo()};
@ -666,7 +705,7 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/api/emission") CROW_ROUTE(app, "/api/emission")
([&](const crow::request &req) { ([&]() {
myxmr::jsonresponse r{xmrblocks.json_emission()}; myxmr::jsonresponse r{xmrblocks.json_emission()};
@ -742,7 +781,7 @@ main(int ac, const char* av[])
}); });
CROW_ROUTE(app, "/api/version") CROW_ROUTE(app, "/api/version")
([&](const crow::request &req) { ([&]() {
myxmr::jsonresponse r{xmrblocks.json_version()}; myxmr::jsonresponse r{xmrblocks.json_version()};
@ -766,13 +805,13 @@ main(int ac, const char* av[])
if (use_ssl) if (use_ssl)
{ {
cout << "Staring in ssl mode" << endl; cout << "Staring in ssl mode" << endl;
app.port(app_port).ssl_file(ssl_crt_file, ssl_key_file) app.bindaddr(bindaddr).port(app_port).ssl_file(ssl_crt_file, ssl_key_file)
.multithreaded().run(); .multithreaded().run();
} }
else else
{ {
cout << "Staring in non-ssl mode" << endl; cout << "Staring in non-ssl mode" << endl;
app.port(app_port).multithreaded().run(); app.bindaddr(bindaddr).port(app_port).multithreaded().run();
} }

@ -45,12 +45,16 @@ namespace xmreg
"enable caching of block details") "enable caching of block details")
("enable-js", value<bool>()->default_value(false)->implicit_value(true), ("enable-js", value<bool>()->default_value(false)->implicit_value(true),
"enable checking outputs and proving txs using JavaScript on client side") "enable checking outputs and proving txs using JavaScript on client side")
("enable-as-hex", value<bool>()->default_value(false)->implicit_value(true),
"enable links to provide hex represtations of a tx and a block")
("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true), ("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true),
"enable users to have the index page on autorefresh") "enable users to have the index page on autorefresh")
("enable-emission-monitor", value<bool>()->default_value(false)->implicit_value(true), ("enable-emission-monitor", value<bool>()->default_value(false)->implicit_value(true),
"enable Monero total emission monitoring thread") "enable Monero total emission monitoring thread")
("port,p", value<string>()->default_value("8081"), ("port,p", value<string>()->default_value("8081"),
"default explorer port") "default explorer port")
("bindaddr,x", value<string>()->default_value("0.0.0.0"),
"default bind address for the explorer")
("testnet-url", value<string>()->default_value(""), ("testnet-url", value<string>()->default_value(""),
"you can specify testnet url, if you run it on mainnet or stagenet. link will show on front page to testnet explorer") "you can specify testnet url, if you run it on mainnet or stagenet. link will show on front page to testnet explorer")
("stagenet-url", value<string>()->default_value(""), ("stagenet-url", value<string>()->default_value(""),

@ -137,8 +137,8 @@ CurrentBlockchainStatus::calculate_emission_in_blocks(
uint64_t coinbase_amount = get_outs_money_amount(blk.miner_tx); uint64_t coinbase_amount = get_outs_money_amount(blk.miner_tx);
std::list<transaction> txs; vector<transaction> txs;
std::list<crypto::hash> missed_txs; vector<crypto::hash> missed_txs;
uint64_t tx_fee_amount = 0; uint64_t tx_fee_amount = 0;

@ -139,10 +139,13 @@ MempoolStatus::read_mempool()
mempool_size_kB += _tx_info.blob_size; mempool_size_kB += _tx_info.blob_size;
local_copy_of_mempool_txs.push_back(mempool_tx {tx_hash, tx}); local_copy_of_mempool_txs.push_back(mempool_tx{});
mempool_tx& last_tx = local_copy_of_mempool_txs.back(); mempool_tx& last_tx = local_copy_of_mempool_txs.back();
last_tx.tx_hash = tx_hash;
last_tx.tx = tx;
// key images of inputs // key images of inputs
vector<txin_to_key> input_key_imgs; vector<txin_to_key> input_key_imgs;
@ -168,7 +171,7 @@ MempoolStatus::read_mempool()
last_tx.mixin_no = sum_data[2]; last_tx.mixin_no = sum_data[2];
last_tx.num_nonrct_inputs = sum_data[3]; last_tx.num_nonrct_inputs = sum_data[3];
last_tx.fee_str = xmreg::xmr_amount_to_str(_tx_info.fee, "{:0.3f}", false); last_tx.fee_str = xmreg::xmr_amount_to_str(_tx_info.fee, "{:0.4f}", false);
last_tx.payed_for_kB_str = fmt::format("{:0.4f}", payed_for_kB); last_tx.payed_for_kB_str = fmt::format("{:0.4f}", payed_for_kB);
last_tx.xmr_inputs_str = xmreg::xmr_amount_to_str(last_tx.sum_inputs , "{: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.xmr_outputs_str = xmreg::xmr_amount_to_str(last_tx.sum_outputs, "{:0.3f}");
@ -264,6 +267,7 @@ MempoolStatus::read_network_info()
local_copy.cumulative_difficulty = rpc_network_info.cumulative_difficulty; local_copy.cumulative_difficulty = rpc_network_info.cumulative_difficulty;
local_copy.block_size_limit = rpc_network_info.block_size_limit; local_copy.block_size_limit = rpc_network_info.block_size_limit;
local_copy.block_size_median = rpc_network_info.block_size_median; local_copy.block_size_median = rpc_network_info.block_size_median;
local_copy.block_weight_limit = rpc_network_info.block_weight_limit;
local_copy.start_time = rpc_network_info.start_time; local_copy.start_time = rpc_network_info.start_time;

@ -72,6 +72,7 @@ struct MempoolStatus
uint64_t cumulative_difficulty {0}; uint64_t cumulative_difficulty {0};
uint64_t block_size_limit {0}; uint64_t block_size_limit {0};
uint64_t block_size_median {0}; uint64_t block_size_median {0};
uint64_t block_weight_limit {0};
char block_size_limit_str[10]; // needs to be trivially copyable char block_size_limit_str[10]; // needs to be trivially copyable
char block_size_median_str[10]; // std::string is not trivially copyable char block_size_median_str[10]; // std::string is not trivially copyable
uint64_t start_time {0}; uint64_t start_time {0};

@ -80,6 +80,12 @@ MicroCore::get_core()
return m_blockchain_storage; return m_blockchain_storage;
} }
tx_memory_pool&
MicroCore::get_mempool()
{
return m_mempool;
}
/** /**
* Get block by its height * Get block by its height
* *
@ -210,78 +216,6 @@ MicroCore::find_output_in_tx(const transaction& tx,
} }
/**
* Returns tx hash in a given block which
* contains given output's public key
*/
bool
MicroCore::get_tx_hash_from_output_pubkey(const public_key& output_pubkey,
const uint64_t& block_height,
crypto::hash& tx_hash,
cryptonote::transaction& tx_found)
{
tx_hash = null_hash;
// get block of given height
block blk;
if (!get_block_by_height(block_height, blk))
{
cerr << "Cant get block of height: " << block_height << endl;
return false;
}
// get all transactions in the block found
// initialize the first list with transaction for solving
// the block i.e. coinbase.
list<transaction> txs {blk.miner_tx};
list<crypto::hash> missed_txs;
if (!m_blockchain_storage.get_transactions(blk.tx_hashes, txs, missed_txs))
{
cerr << "Cant find transcations in block: " << block_height << endl;
return false;
}
if (!missed_txs.empty())
{
cerr << "Transactions not found in blk: " << block_height << endl;
for (const crypto::hash& h : missed_txs)
{
cerr << " - tx hash: " << h << endl;
}
return false;
}
// search outputs in each transactions
// until output with pubkey of interest is found
for (const transaction& tx : txs)
{
tx_out found_out;
// we dont need here output_index
size_t output_index;
if (find_output_in_tx(tx, output_pubkey, found_out, output_index))
{
// we found the desired public key
tx_hash = get_transaction_hash(tx);
tx_found = tx;
return true;
}
}
return false;
}
uint64_t uint64_t
MicroCore::get_blk_timestamp(uint64_t blk_height) MicroCore::get_blk_timestamp(uint64_t blk_height)
{ {
@ -332,6 +266,28 @@ init_blockchain(const string& path,
return true; return true;
} }
bool
MicroCore::get_block_complete_entry(block const& b, block_complete_entry& bce)
{
bce.block = cryptonote::block_to_blob(b);
for (const auto &tx_hash: b.tx_hashes)
{
transaction tx;
if (!get_tx(tx_hash, tx))
return false;
cryptonote::blobdata txblob = tx_to_blob(tx);
bce.txs.push_back(txblob);
}
return true;
}
string string
MicroCore::get_blkchain_path() MicroCore::get_blkchain_path()
{ {

@ -44,6 +44,9 @@ namespace xmreg
Blockchain& Blockchain&
get_core(); get_core();
tx_memory_pool&
get_mempool();
bool bool
get_block_by_height(const uint64_t& height, block& blk); get_block_by_height(const uint64_t& height, block& blk);
@ -59,15 +62,12 @@ namespace xmreg
tx_out& out, tx_out& out,
size_t& output_index); size_t& output_index);
bool
get_tx_hash_from_output_pubkey(const public_key& output_pubkey,
const uint64_t& block_height,
crypto::hash& tx_hash,
transaction& tx_found);
uint64_t uint64_t
get_blk_timestamp(uint64_t blk_height); get_blk_timestamp(uint64_t blk_height);
bool
get_block_complete_entry(block const& b, block_complete_entry& bce);
string string
get_blkchain_path(); get_blkchain_path();

@ -30,6 +30,7 @@
#include <limits> #include <limits>
#include <ctime> #include <ctime>
#include <future> #include <future>
#include <visitor/render_node.hpp>
#define TMPL_DIR "./templates" #define TMPL_DIR "./templates"
@ -66,7 +67,7 @@
#define JS_SHA3 TMPL_DIR "/js/sha3.js" #define JS_SHA3 TMPL_DIR "/js/sha3.js"
#define ONIONEXPLORER_RPC_VERSION_MAJOR 1 #define ONIONEXPLORER_RPC_VERSION_MAJOR 1
#define ONIONEXPLORER_RPC_VERSION_MINOR 0 #define ONIONEXPLORER_RPC_VERSION_MINOR 1
#define MAKE_ONIONEXPLORER_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define MAKE_ONIONEXPLORER_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define ONIONEXPLORER_RPC_VERSION \ #define ONIONEXPLORER_RPC_VERSION \
MAKE_ONIONEXPLORER_RPC_VERSION(ONIONEXPLORER_RPC_VERSION_MAJOR, ONIONEXPLORER_RPC_VERSION_MINOR) MAKE_ONIONEXPLORER_RPC_VERSION(ONIONEXPLORER_RPC_VERSION_MAJOR, ONIONEXPLORER_RPC_VERSION_MINOR)
@ -113,6 +114,71 @@ namespace std
} }
/**
* visitor to produce json representations of
* values stored in mstch::node
*/
class mstch_node_to_json: public boost::static_visitor<nlohmann::json>
{
public:
// enabled for numeric types
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, nlohmann::json>::type
operator()(T const& value) const {
return nlohmann::json {value};
}
nlohmann::json operator()(std::string const& value) const {
return nlohmann::json {value};
}
nlohmann::json operator()(mstch::map const& n_map) const
{
nlohmann::json j;
for (auto const& kv: n_map)
j[kv.first] = boost::apply_visitor(mstch_node_to_json(), kv.second);
return j;
}
nlohmann::json operator()(mstch::array const& n_array) const
{
nlohmann::json j;
for (auto const& v: n_array)
j.push_back(boost::apply_visitor(mstch_node_to_json(), v));
return j;
}
// catch other types that are non-numeric and not listed above
template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value, nlohmann::json>::type
operator()(const T&) const {
return nlohmann::json {};
}
};
namespace mstch
{
namespace internal
{
// add conversion from mstch::map to nlohmann::json
void
to_json(nlohmann::json& j, mstch::map const &m)
{
for (auto const& kv: m)
j[kv.first] = boost::apply_visitor(mstch_node_to_json(), kv.second);
}
}
}
namespace xmreg namespace xmreg
{ {
@ -124,6 +190,8 @@ using namespace std;
using epee::string_tools::pod_to_hex; using epee::string_tools::pod_to_hex;
using epee::string_tools::hex_to_pod; using epee::string_tools::hex_to_pod;
/** /**
* @brief The tx_details struct * @brief The tx_details struct
* *
@ -189,8 +257,8 @@ struct tx_details
mixin_str = std::to_string(mixin_no); mixin_str = std::to_string(mixin_no);
fee_str = fmt::format("{:0.6f}", xmr_amount); fee_str = fmt::format("{:0.6f}", xmr_amount);
fee_short_str = fmt::format("{:0.3f}", xmr_amount); fee_short_str = fmt::format("{:0.4f}", xmr_amount);
payed_for_kB_str = fmt::format("{:0.3f}", payed_for_kB); payed_for_kB_str = fmt::format("{:0.4f}", payed_for_kB);
} }
@ -298,6 +366,7 @@ class page
bool enable_mixins_details; bool enable_mixins_details;
bool enable_tx_cache; bool enable_tx_cache;
bool enable_block_cache; bool enable_block_cache;
bool enable_as_hex;
bool show_cache_times; bool show_cache_times;
@ -348,6 +417,7 @@ public:
cryptonote::network_type _nettype, cryptonote::network_type _nettype,
bool _enable_pusher, bool _enable_pusher,
bool _enable_js, bool _enable_js,
bool _enable_as_hex,
bool _enable_key_image_checker, bool _enable_key_image_checker,
bool _enable_output_key_checker, bool _enable_output_key_checker,
bool _enable_autorefresh_option, bool _enable_autorefresh_option,
@ -367,6 +437,7 @@ public:
nettype {_nettype}, nettype {_nettype},
enable_pusher {_enable_pusher}, enable_pusher {_enable_pusher},
enable_js {_enable_js}, enable_js {_enable_js},
enable_as_hex {_enable_as_hex},
enable_key_image_checker {_enable_key_image_checker}, enable_key_image_checker {_enable_key_image_checker},
enable_output_key_checker {_enable_output_key_checker}, enable_output_key_checker {_enable_output_key_checker},
enable_autorefresh_option {_enable_autorefresh_option}, enable_autorefresh_option {_enable_autorefresh_option},
@ -512,12 +583,12 @@ public:
uint64_t local_copy_server_timestamp = server_timestamp; uint64_t local_copy_server_timestamp = server_timestamp;
// number of last blocks to show
uint64_t no_of_last_blocks {no_blocks_on_index + 1};
// get the current blockchain height. Just to check // get the current blockchain height. Just to check
uint64_t height = core_storage->get_current_blockchain_height(); uint64_t height = core_storage->get_current_blockchain_height();
// number of last blocks to show
uint64_t no_of_last_blocks = std::min(no_blocks_on_index + 1, height);
// initalise page tempate map with basic info about blockchain // initalise page tempate map with basic info about blockchain
mstch::map context { mstch::map context {
{"testnet" , testnet}, {"testnet" , testnet},
@ -583,7 +654,7 @@ public:
crypto::hash blk_hash = core_storage->get_block_id_by_height(i); crypto::hash blk_hash = core_storage->get_block_id_by_height(i);
// get block size in kB // get block size in kB
double blk_size = static_cast<double>(core_storage->get_db().get_block_size(i))/1024.0; double blk_size = static_cast<double>(core_storage->get_db().get_block_weight(i))/1024.0;
string blk_size_str = fmt::format("{:0.2f}", blk_size); string blk_size_str = fmt::format("{:0.2f}", blk_size);
@ -716,8 +787,8 @@ public:
// get all transactions in the block found // get all transactions in the block found
// initialize the first list with transaction for solving // initialize the first list with transaction for solving
// the block i.e. coinbase. // the block i.e. coinbase.
list<cryptonote::transaction> blk_txs {blk.miner_tx}; vector<cryptonote::transaction> blk_txs {blk.miner_tx};
list<crypto::hash> missed_txs; vector<crypto::hash> missed_txs;
if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs)) if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs))
{ {
@ -814,14 +885,12 @@ public:
// perapre network info mstch::map for the front page // perapre network info mstch::map for the front page
string hash_rate; string hash_rate;
if (testnet || stagenet) if (current_network_info.hash_rate > 1e6)
{
hash_rate = std::to_string(current_network_info.hash_rate) + " H/s";
}
else
{
hash_rate = fmt::format("{:0.3f} MH/s", current_network_info.hash_rate/1.0e6); hash_rate = fmt::format("{:0.3f} MH/s", current_network_info.hash_rate/1.0e6);
} else if (current_network_info.hash_rate > 1e3)
hash_rate = fmt::format("{:0.3f} kH/s", current_network_info.hash_rate/1.0e3);
else
hash_rate = fmt::format("{:d} H/s", current_network_info.hash_rate);
pair<string, string> network_info_age = get_age(local_copy_server_timestamp, pair<string, string> network_info_age = get_age(local_copy_server_timestamp,
current_network_info.info_timestamp); current_network_info.info_timestamp);
@ -1157,7 +1226,7 @@ public:
} }
// get block size in bytes // get block size in bytes
uint64_t blk_size = core_storage->get_db().get_block_size(_blk_height); uint64_t blk_size = core_storage->get_db().get_block_weight(_blk_height);
// miner reward tx // miner reward tx
transaction coinbase_tx = blk.miner_tx; transaction coinbase_tx = blk.miner_tx;
@ -1175,6 +1244,10 @@ public:
_blk_height, current_blockchain_height); _blk_height, current_blockchain_height);
// initalise page tempate map with basic info about blockchain // initalise page tempate map with basic info about blockchain
string blk_pow_hash_str = pod_to_hex(get_block_longhash(blk, _blk_height));
uint64_t blk_difficulty = core_storage->get_db().get_block_difficulty(_blk_height);
mstch::map context { mstch::map context {
{"testnet" , testnet}, {"testnet" , testnet},
{"stagenet" , stagenet}, {"stagenet" , stagenet},
@ -1184,6 +1257,7 @@ public:
{"blk_timestamp_epoch" , blk.timestamp}, {"blk_timestamp_epoch" , blk.timestamp},
{"prev_hash" , prev_hash_str}, {"prev_hash" , prev_hash_str},
{"next_hash" , next_hash_str}, {"next_hash" , next_hash_str},
{"enable_as_hex" , enable_as_hex},
{"have_next_hash" , have_next_hash}, {"have_next_hash" , have_next_hash},
{"have_prev_hash" , have_prev_hash}, {"have_prev_hash" , have_prev_hash},
{"have_txs" , have_txs}, {"have_txs" , have_txs},
@ -1192,6 +1266,8 @@ public:
{"blk_age" , age.first}, {"blk_age" , age.first},
{"delta_time" , delta_time}, {"delta_time" , delta_time},
{"blk_nonce" , blk.nonce}, {"blk_nonce" , blk.nonce},
{"blk_pow_hash" , blk_pow_hash_str},
{"blk_difficulty" , blk_difficulty},
{"age_format" , age.second}, {"age_format" , age.second},
{"major_ver" , std::to_string(blk.major_version)}, {"major_ver" , std::to_string(blk.major_version)},
{"minor_ver" , std::to_string(blk.minor_version)}, {"minor_ver" , std::to_string(blk.minor_version)},
@ -1524,6 +1600,152 @@ public:
return mstch::render(template_file["tx"], context, partials); return mstch::render(template_file["tx"], context, partials);
} }
string
show_tx_hex(string tx_hash_str)
{
transaction tx;
crypto::hash tx_hash;
if (!get_tx(tx_hash_str, tx, tx_hash))
return string {"Cant get tx: "} + tx_hash_str;
try
{
return tx_to_hex(tx);
}
catch (std::exception const& e)
{
cerr << e.what() << endl;
return string {"Failed to obtain hex of tx due to: "} + e.what();
}
}
string
show_block_hex(size_t block_height, bool complete_blk)
{
// get transaction
block blk;
if (!mcore->get_block_by_height(block_height, blk))
{
cerr << "Cant get block in blockchain: " << block_height
<< ". \n Check mempool now\n";
}
try
{
if (complete_blk == false)
{
// get only block data as hex
return epee::string_tools::buff_to_hex_nodelimer(
t_serializable_object_to_blob(blk));
}
else
{
// get block_complete_entry (block and its txs) as hex
block_complete_entry complete_block_data;
if (!mcore->get_block_complete_entry(blk, complete_block_data))
{
cerr << "Failed to obtain complete block data " << endl;
return string {"Failed to obtain complete block data "};
}
std::string complete_block_data_str;
if(!epee::serialization::store_t_to_binary(
complete_block_data, complete_block_data_str))
{
cerr << "Failed to serialize complete_block_data\n";
return string {"Failed to obtain complete block data"};
}
return epee::string_tools
::buff_to_hex_nodelimer(complete_block_data_str);
}
}
catch (std::exception const& e)
{
cerr << e.what() << endl;
return string {"Failed to obtain hex of a block due to: "} + e.what();
}
}
string
show_ringmembers_hex(string const& tx_hash_str)
{
transaction tx;
crypto::hash tx_hash;
if (!get_tx(tx_hash_str, tx, tx_hash))
return string {"Cant get tx: "} + tx_hash_str;
vector<txin_to_key> input_key_imgs = xmreg::get_key_images(tx);
// key: vector of absolute_offsets and associated amount (last value),
// value: vector of output_info_of_mixins
std::map<vector<uint64_t>, vector<string>> all_mixin_outputs;
// make timescale maps for mixins in input
for (txin_to_key const& in_key: input_key_imgs)
{
// get absolute offsets of mixins
std::vector<uint64_t> absolute_offsets
= cryptonote::relative_output_offsets_to_absolute(
in_key.key_offsets);
// get public keys of outputs used in the mixins that
// match to the offests
std::vector<cryptonote::output_data_t> mixin_outputs;
try
{
// before proceeding with geting the outputs based on
// the amount and absolute offset
// check how many outputs there are for that amount
// go to next input if a too large offset was found
if (are_absolute_offsets_good(absolute_offsets, in_key)
== false)
continue;
core_storage->get_db().get_output_key(in_key.amount,
absolute_offsets,
mixin_outputs);
}
catch (OUTPUT_DNE const& e)
{
cerr << "get_output_keys: " << e.what() << endl;
continue;
}
// add accociated amount to these offsets so that we can differentiate
// between same offsets, but for different amounts
absolute_offsets.push_back(in_key.amount);
for (auto const& mo: mixin_outputs)
all_mixin_outputs[absolute_offsets].emplace_back(pod_to_hex(mo));
} // for (txin_to_key const& in_key: input_key_imgs)
if (all_mixin_outputs.empty())
return string {"No ring members to serialize"};
// archive all_mixin_outputs vector
std::ostringstream oss;
boost::archive::portable_binary_oarchive archive(oss);
archive << all_mixin_outputs;
// return as all_mixin_outputs vector hex
return epee::string_tools
::buff_to_hex_nodelimer(oss.str());
}
string string
show_my_outputs(string tx_hash_str, show_my_outputs(string tx_hash_str,
string xmr_address_str, string xmr_address_str,
@ -1726,9 +1948,9 @@ public:
string shortcut_url = domain string shortcut_url = domain
+ (tx_prove ? "/prove" : "/myoutputs") + (tx_prove ? "/prove" : "/myoutputs")
+ "/" + tx_hash_str + '/' + tx_hash_str
+ "/" + xmr_address_str + '/' + xmr_address_str
+ "/" + viewkey_str; + '/' + viewkey_str;
string viewkey_str_partial = viewkey_str; string viewkey_str_partial = viewkey_str;
@ -1771,9 +1993,8 @@ public:
key_derivation derivation; key_derivation derivation;
std::vector<key_derivation> additional_derivations(txd.additional_pks.size()); std::vector<key_derivation> additional_derivations(txd.additional_pks.size());
//cout << multiple_tx_secret_keys.size() << " " << txd.additional_pks.size() + 1 << '\n'; if (tx_prove && multiple_tx_secret_keys.size()
!= txd.additional_pks.size() + 1)
if (tx_prove && multiple_tx_secret_keys.size() != txd.additional_pks.size() + 1)
{ {
return string("This transaction includes additional tx pubkeys whose " return string("This transaction includes additional tx pubkeys whose "
"size doesn't match with the provided tx secret keys"); "size doesn't match with the provided tx secret keys");
@ -1813,7 +2034,8 @@ public:
if (decrypted_payment_id8 != null_hash8) if (decrypted_payment_id8 != null_hash8)
{ {
if (mcore->get_device()->decrypt_payment_id(decrypted_payment_id8, pub_key, prv_view_key)) if (mcore->get_device()->decrypt_payment_id(
decrypted_payment_id8, pub_key, prv_view_key))
{ {
context["decrypted_payment_id8"] = pod_to_hex(decrypted_payment_id8); context["decrypted_payment_id8"] = pod_to_hex(decrypted_payment_id8);
} }
@ -1850,7 +2072,8 @@ public:
bool with_additional = false; bool with_additional = false;
if (!mine_output && txd.additional_pks.size() == txd.output_pub_keys.size()) if (!mine_output && txd.additional_pks.size()
== txd.output_pub_keys.size())
{ {
derive_public_key(additional_derivations[output_idx], derive_public_key(additional_derivations[output_idx],
output_idx, output_idx,
@ -1875,15 +2098,17 @@ public:
bool r; bool r;
r = decode_ringct(tx.rct_signatures, r = decode_ringct(
with_additional ? additional_derivations[output_idx] : derivation, tx.rct_signatures,
with_additional
? additional_derivations[output_idx] : derivation,
output_idx, output_idx,
tx.rct_signatures.ecdhInfo[output_idx].mask, tx.rct_signatures.ecdhInfo[output_idx].mask,
rct_amount); rct_amount);
if (!r) if (!r)
{ {
cerr << "\nshow_my_outputs: Cant decode ringCT! " << endl; cerr << "\nshow_my_outputs: Cant decode RingCT!\n";
} }
outp.second = rct_amount; outp.second = rct_amount;
@ -1927,9 +2152,14 @@ public:
// parefct matches must be equal to number of inputs in a tx. // parefct matches must be equal to number of inputs in a tx.
uint64_t no_of_matched_mixins {0}; uint64_t no_of_matched_mixins {0};
// Hold all possible mixins that we found. This is only used so that
// we get number of all posibilities, and their total xmr amount
// (useful for unit testing)
// public_key , amount
std::vector<std::pair<crypto::public_key, uint64_t>> all_possible_mixins;
for (const txin_to_key& in_key: input_key_imgs) for (const txin_to_key& in_key: input_key_imgs)
{ {
// get absolute offsets of mixins // get absolute offsets of mixins
std::vector<uint64_t> absolute_offsets std::vector<uint64_t> absolute_offsets
= cryptonote::relative_output_offsets_to_absolute( = cryptonote::relative_output_offsets_to_absolute(
@ -1941,7 +2171,8 @@ public:
try try
{ {
// before proceeding with geting the outputs based on the amount and absolute offset // before proceeding with geting the outputs based on
// the amount and absolute offset
// check how many outputs there are for that amount // check how many outputs there are for that amount
// go to next input if a too large offset was found // go to next input if a too large offset was found
if (are_absolute_offsets_good(absolute_offsets, in_key) == false) if (are_absolute_offsets_good(absolute_offsets, in_key) == false)
@ -2009,10 +2240,9 @@ public:
string out_msg = fmt::format( string out_msg = fmt::format(
"Output with amount {:d} and index {:d} does not exist!", "Output with amount {:d} and index {:d} does not exist!",
in_key.amount, abs_offset in_key.amount, abs_offset);
);
cerr << out_msg << endl; cerr << out_msg << '\n';
break; break;
} }
@ -2028,7 +2258,6 @@ public:
if (!mcore->get_tx(tx_out_idx.first, mixin_tx)) if (!mcore->get_tx(tx_out_idx.first, mixin_tx))
{ {
cerr << "Cant get tx: " << tx_out_idx.first << endl; cerr << "Cant get tx: " << tx_out_idx.first << endl;
break; break;
} }
@ -2036,33 +2265,35 @@ public:
mixins.push_back(mstch::map{ mixins.push_back(mstch::map{
{"mixin_pub_key" , out_pub_key_str}, {"mixin_pub_key" , out_pub_key_str},
make_pair<string, mstch::array>("mixin_outputs" , mstch::array{}), make_pair<string, mstch::array>("mixin_outputs"
{"has_mixin_outputs" , false} , mstch::array{}),
}); {"has_mixin_outputs" , false}});
mstch::array& mixin_outputs = boost::get<mstch::array>( mstch::array& mixin_outputs = boost::get<mstch::array>(
boost::get<mstch::map>(mixins.back())["mixin_outputs"] boost::get<mstch::map>(mixins.back())["mixin_outputs"]);
);
mstch::node& has_mixin_outputs mstch::node& has_mixin_outputs
= boost::get<mstch::map>(mixins.back())["has_mixin_outputs"]; = boost::get<mstch::map>(mixins.back())["has_mixin_outputs"];
bool found_something {false}; bool found_something {false};
public_key mixin_tx_pub_key public_key mixin_tx_pub_key
= xmreg::get_tx_pub_key_from_received_outs(mixin_tx); = xmreg::get_tx_pub_key_from_received_outs(mixin_tx);
std::vector<public_key> mixin_additional_tx_pub_keys = cryptonote::get_additional_tx_pub_keys_from_extra(mixin_tx);
std::vector<public_key> mixin_additional_tx_pub_keys
= cryptonote::get_additional_tx_pub_keys_from_extra(mixin_tx);
string mixin_tx_pub_key_str = pod_to_hex(mixin_tx_pub_key); string mixin_tx_pub_key_str = pod_to_hex(mixin_tx_pub_key);
// public transaction key is combined with our viewkey // public transaction key is combined with our viewkey
// to create, so called, derived key. // to create, so called, derived key.
key_derivation derivation; key_derivation derivation;
std::vector<key_derivation> additional_derivations(mixin_additional_tx_pub_keys.size());
if (!generate_key_derivation(mixin_tx_pub_key, prv_view_key, derivation)) std::vector<key_derivation> additional_derivations(
mixin_additional_tx_pub_keys.size());
if (!generate_key_derivation(mixin_tx_pub_key,
prv_view_key, derivation))
{ {
cerr << "Cant get derived key for: " << "\n" cerr << "Cant get derived key for: " << "\n"
<< "pub_tx_key: " << mixin_tx_pub_key << " and " << "pub_tx_key: " << mixin_tx_pub_key << " and "
@ -2072,11 +2303,13 @@ public:
} }
for (size_t i = 0; i < mixin_additional_tx_pub_keys.size(); ++i) for (size_t i = 0; i < mixin_additional_tx_pub_keys.size(); ++i)
{ {
if (!generate_key_derivation(mixin_additional_tx_pub_keys[i], prv_view_key, additional_derivations[i])) if (!generate_key_derivation(mixin_additional_tx_pub_keys[i],
prv_view_key,
additional_derivations[i]))
{ {
cerr << "Cant get derived key for: " << "\n" cerr << "Cant get derived key for: " << "\n"
<< "pub_tx_key: " << mixin_additional_tx_pub_keys[i] << " and " << "pub_tx_key: " << mixin_additional_tx_pub_keys[i]
<< "prv_view_key" << prv_view_key << endl; << " and prv_view_key" << prv_view_key << endl;
continue; continue;
} }
@ -2090,23 +2323,28 @@ public:
mixin_outputs.push_back(mstch::map{ mixin_outputs.push_back(mstch::map{
{"mix_tx_hash" , mixin_tx_hash_str}, {"mix_tx_hash" , mixin_tx_hash_str},
{"mix_tx_pub_key" , mixin_tx_pub_key_str}, {"mix_tx_pub_key" , mixin_tx_pub_key_str},
make_pair<string, mstch::array>("found_outputs" , mstch::array{}), make_pair<string, mstch::array>("found_outputs"
, mstch::array{}),
{"has_found_outputs", false} {"has_found_outputs", false}
}); });
mstch::array& found_outputs = boost::get<mstch::array>( mstch::array& found_outputs = boost::get<mstch::array>(
boost::get<mstch::map>(mixin_outputs.back())["found_outputs"] boost::get<mstch::map>(
mixin_outputs.back())["found_outputs"]
); );
mstch::node& has_found_outputs mstch::node& has_found_outputs
= boost::get<mstch::map>(mixin_outputs.back())["has_found_outputs"]; = boost::get<mstch::map>(
mixin_outputs.back())["has_found_outputs"];
uint64_t ringct_amount {0};
// for each output in mixin tx, find the one from key_image // for each output in mixin tx, find the one from key_image
// and check if its ours. // and check if its ours.
for (const auto& mix_out: output_pub_keys) for (const auto& mix_out: output_pub_keys)
{ {
txout_to_key txout_k = std::get<0>(mix_out); txout_to_key const& txout_k = std::get<0>(mix_out);
uint64_t amount = std::get<1>(mix_out); uint64_t amount = std::get<1>(mix_out);
uint64_t output_idx_in_tx = std::get<2>(mix_out); uint64_t output_idx_in_tx = std::get<2>(mix_out);
@ -2131,14 +2369,19 @@ public:
// check if generated public key matches the current output's key // check if generated public key matches the current output's key
bool mine_output = (txout_k.key == tx_pubkey_generated); bool mine_output = (txout_k.key == tx_pubkey_generated);
bool with_additional = false; bool with_additional = false;
if (!mine_output && mixin_additional_tx_pub_keys.size() == output_pub_keys.size())
if (!mine_output && mixin_additional_tx_pub_keys.size()
== output_pub_keys.size())
{ {
derive_public_key(additional_derivations[output_idx_in_tx], derive_public_key(additional_derivations[output_idx_in_tx],
output_idx_in_tx, output_idx_in_tx,
address_info.address.m_spend_public_key, address_info.address.m_spend_public_key,
tx_pubkey_generated); tx_pubkey_generated);
mine_output = (txout_k.key == tx_pubkey_generated); mine_output = (txout_k.key == tx_pubkey_generated);
with_additional = true; with_additional = true;
} }
@ -2154,16 +2397,17 @@ public:
bool r; bool r;
r = decode_ringct(mixin_tx.rct_signatures, r = decode_ringct(
with_additional ? additional_derivations[output_idx_in_tx] : derivation, mixin_tx.rct_signatures,
with_additional
? additional_derivations[output_idx_in_tx] : derivation,
output_idx_in_tx, output_idx_in_tx,
mixin_tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask, mixin_tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask,
rct_amount); rct_amount);
if (!r) if (!r)
{ cerr << "show_my_outputs: key images: "
cerr << "show_my_outputs: key images: Cant decode ringCT!" << endl; "Cant decode RingCT!\n";
}
amount = rct_amount; amount = rct_amount;
@ -2190,11 +2434,9 @@ public:
}); });
//cout << "txout_k.key == output_data.pubkey" << endl; //cout << "txout_k.key == output_data.pubkey" << endl;
//cout << pod_to_hex(txout_k.key) << " == " << pod_to_hex(output_data.pubkey) << endl;
if (mine_output) if (mine_output)
{ {
found_something = true; found_something = true;
show_key_images = true; show_key_images = true;
@ -2202,9 +2444,7 @@ public:
// public key of an outputs used in ring signature, // public key of an outputs used in ring signature,
// matches a public key in a mixin_tx // matches a public key in a mixin_tx
if (txout_k.key != output_data.pubkey) if (txout_k.key != output_data.pubkey)
{
continue; continue;
}
// sum up only first output matched found in each input // sum up only first output matched found in each input
if (no_of_output_matches_found == 0) if (no_of_output_matches_found == 0)
@ -2222,6 +2462,7 @@ public:
else if (mixin_tx.version == 2) // ringct else if (mixin_tx.version == 2) // ringct
{ {
sum_mixin_xmr += amount; sum_mixin_xmr += amount;
ringct_amount += amount;
} }
no_of_matched_mixins++; no_of_matched_mixins++;
@ -2247,11 +2488,9 @@ public:
// << ", key_img == input_key: " << (key_img == in_key.k_image) // << ", key_img == input_key: " << (key_img == in_key.k_image)
// << endl; // << endl;
no_of_output_matches_found++; no_of_output_matches_found++;
} } // if (mine_output)
} // for (const pair<txout_to_key, uint64_t>& mix_out: txd.output_pub_keys) } // for (const pair<txout_to_key, uint64_t>& mix_out: txd.output_pub_keys)
@ -2259,11 +2498,16 @@ public:
has_mixin_outputs = found_something; has_mixin_outputs = found_something;
++count; // all_possible_mixins_amount += amount;
} // for (const cryptonote::output_data_t& output_data: mixin_outputs) if (found_something)
all_possible_mixins.push_back(
{mixin_tx_pub_key,
in_key.amount == 0 ? ringct_amount : in_key.amount});
++count;
} // for (const cryptonote::output_data_t& output_data: mixin_outputs)
} // for (const txin_to_key& in_key: input_key_imgs) } // for (const txin_to_key& in_key: input_key_imgs)
@ -2283,6 +2527,23 @@ public:
uint64_t possible_spending {0}; uint64_t possible_spending {0};
//cout << "\nall_possible_mixins: " << all_possible_mixins.size() << '\n';
// useful for unit testing as it provides total xmr sum
// of possible mixins
uint64_t all_possible_mixins_amount1 {0};
for (auto& p: all_possible_mixins)
all_possible_mixins_amount1 += p.second;
//cout << "\all_possible_mixins_amount: " << all_possible_mixins_amount1 << '\n';
//cout << "\nmixins: " << mix << '\n';
context["no_all_possible_mixins"] = static_cast<uint64_t>(all_possible_mixins.size());
context["all_possible_mixins_amount"] = all_possible_mixins_amount1;
// show spending only if sum of mixins is more than // show spending only if sum of mixins is more than
// what we get + fee, and number of perferctly matched // what we get + fee, and number of perferctly matched
// mixis is equal to number of inputs // mixis is equal to number of inputs
@ -2657,7 +2918,7 @@ public:
"Its prefix is: {:s}", "Its prefix is: {:s}",
data_prefix); data_prefix);
cout << msg << endl; cerr << msg << endl;
return string(msg); return string(msg);
} }
@ -2666,6 +2927,11 @@ public:
crypto::hash tx_prefix_hash_from_blob; crypto::hash tx_prefix_hash_from_blob;
cryptonote::transaction tx_from_blob; cryptonote::transaction tx_from_blob;
// std::stringstream ss;
// ss << tx_data_blob;
// binary_archive<false> ba(ss);
// serialization::serialize(ba, tx_from_blob);
if (!cryptonote::parse_and_validate_tx_from_blob(tx_data_blob, if (!cryptonote::parse_and_validate_tx_from_blob(tx_data_blob,
tx_from_blob, tx_from_blob,
tx_hash_from_blob, tx_hash_from_blob,
@ -3965,6 +4231,8 @@ public:
} }
/* /*
* Lets use this json api convention for success and error * Lets use this json api convention for success and error
* https://labs.omniti.com/labs/jsend * https://labs.omniti.com/labs/jsend
@ -4214,6 +4482,56 @@ public:
return j_response; return j_response;
} }
json
json_detailedtransaction(string tx_hash_str)
{
json j_response {
{"status", "fail"},
{"data" , json {}}
};
json& j_data = j_response["data"];
transaction tx;
bool found_in_mempool {false};
uint64_t tx_timestamp {0};
string error_message;
if (!find_tx_for_json(tx_hash_str, tx, found_in_mempool, tx_timestamp, error_message))
{
j_data["title"] = error_message;
return j_response;
}
// get detailed tx information
mstch::map tx_context = construct_tx_context(tx, 1 /*full detailed */);
// remove some page specific and html stuff
tx_context.erase("timescales");
tx_context.erase("tx_json");
tx_context.erase("tx_json_raw");
tx_context.erase("enable_mixins_details");
tx_context.erase("with_ring_signatures");
tx_context.erase("show_part_of_inputs");
tx_context.erase("show_more_details_link");
tx_context.erase("max_no_of_inputs_to_show");
tx_context.erase("inputs_xmr_sum_not_zero");
tx_context.erase("have_raw_tx");
tx_context.erase("have_any_unknown_amount");
tx_context.erase("has_error");
tx_context.erase("error_msg");
tx_context.erase("server_time");
tx_context.erase("construction_time");
j_data = tx_context;
j_response["status"] = "success";
return j_response;
}
/* /*
* Lets use this json api convention for success and error * Lets use this json api convention for success and error
* https://labs.omniti.com/labs/jsend * https://labs.omniti.com/labs/jsend
@ -4293,7 +4611,7 @@ public:
// get block size in bytes // get block size in bytes
uint64_t blk_size = core_storage->get_db().get_block_size(block_height); uint64_t blk_size = core_storage->get_db().get_block_weight(block_height);
// miner reward tx // miner reward tx
transaction coinbase_tx = blk.miner_tx; transaction coinbase_tx = blk.miner_tx;
@ -4522,7 +4840,7 @@ public:
} }
// get block size in bytes // get block size in bytes
double blk_size = core_storage->get_db().get_block_size(i); double blk_size = core_storage->get_db().get_block_weight(i);
crypto::hash blk_hash = core_storage->get_block_id_by_height(i); crypto::hash blk_hash = core_storage->get_block_id_by_height(i);
@ -4541,8 +4859,8 @@ public:
json& j_txs = j_blocks.back()["txs"]; json& j_txs = j_blocks.back()["txs"];
list<cryptonote::transaction> blk_txs {blk.miner_tx}; vector<cryptonote::transaction> blk_txs {blk.miner_tx};
list<crypto::hash> missed_txs; vector<crypto::hash> missed_txs;
if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs)) if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs))
{ {
@ -5107,8 +5425,8 @@ public:
} }
// get transactions in the given block // get transactions in the given block
list <cryptonote::transaction> blk_txs{blk.miner_tx}; vector<cryptonote::transaction> blk_txs{blk.miner_tx};
list <crypto::hash> missed_txs; vector<crypto::hash> missed_txs;
if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs)) if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs))
{ {
@ -5225,7 +5543,7 @@ public:
string emission_blk_no = std::to_string(current_values.blk_no - 1); string emission_blk_no = std::to_string(current_values.blk_no - 1);
string emission_coinbase = xmr_amount_to_str(current_values.coinbase, "{:0.3f}"); string emission_coinbase = xmr_amount_to_str(current_values.coinbase, "{:0.3f}");
string emission_fee = xmr_amount_to_str(current_values.fee, "{:0.3f}", false); string emission_fee = xmr_amount_to_str(current_values.fee, "{:0.4f}", false);
j_data = json { j_data = json {
{"blk_no" , current_values.blk_no - 1}, {"blk_no" , current_values.blk_no - 1},
@ -5893,6 +6211,7 @@ private:
context["inputs_xmr_sum"] = xmreg::xmr_amount_to_str(inputs_xmr_sum); context["inputs_xmr_sum"] = xmreg::xmr_amount_to_str(inputs_xmr_sum);
context["server_time"] = server_time_str; context["server_time"] = server_time_str;
context["enable_mixins_details"] = detailed_view; context["enable_mixins_details"] = detailed_view;
context["enable_as_hex"] = enable_as_hex;
context["show_part_of_inputs"] = show_part_of_inputs; context["show_part_of_inputs"] = show_part_of_inputs;
context["max_no_of_inputs_to_show"] = max_no_of_inputs_to_show; context["max_no_of_inputs_to_show"] = max_no_of_inputs_to_show;
@ -6140,6 +6459,32 @@ private:
} }
bool
find_tx_for_json(
string const& tx_hash_str,
transaction& tx,
bool& found_in_mempool,
uint64_t& tx_timestamp,
string& error_message)
{
// parse tx hash string to hash object
crypto::hash tx_hash;
if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash))
{
error_message = fmt::format("Cant parse tx hash: {:s}", tx_hash_str);
return false;
}
if (!find_tx(tx_hash, tx, found_in_mempool, tx_timestamp))
{
error_message = fmt::format("Cant find tx hash: {:s}", tx_hash_str);
return false;
}
return true;
}
bool bool
search_mempool(crypto::hash tx_hash, search_mempool(crypto::hash tx_hash,
vector<MempoolStatus::mempool_tx>& found_txs) vector<MempoolStatus::mempool_tx>& found_txs)
@ -6344,6 +6689,41 @@ private:
}}; }};
} }
bool
get_tx(string const& tx_hash_str,
transaction& tx,
crypto::hash& tx_hash)
{
if (!epee::string_tools::hex_to_pod(tx_hash_str, tx_hash))
{
string msg = fmt::format("Cant parse {:s} as tx hash!", tx_hash_str);
cerr << msg << endl;
return false;
}
// get transaction
if (!mcore->get_tx(tx_hash, tx))
{
cerr << "Cant get tx in blockchain: " << tx_hash
<< ". \n Check mempool now\n";
vector<MempoolStatus::mempool_tx> found_txs;
search_mempool(tx_hash, found_txs);
if (found_txs.empty())
{
// tx is nowhere to be found :-(
return false;
}
tx = found_txs.at(0).tx;
}
return true;
}
void void
add_js_files(mstch::map& context) add_js_files(mstch::map& context)
{ {

@ -275,9 +275,9 @@ rpccalls::get_dynamic_per_kb_fee_estimate(
uint64_t& fee, uint64_t& fee,
string& error_msg) string& error_msg)
{ {
epee::json_rpc::request<COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request> epee::json_rpc::request<COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request>
req_t = AUTO_VAL_INIT(req_t); req_t = AUTO_VAL_INIT(req_t);
epee::json_rpc::response<COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response, std::string> epee::json_rpc::response<COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response, std::string>
resp_t = AUTO_VAL_INIT(resp_t); resp_t = AUTO_VAL_INIT(resp_t);

@ -30,6 +30,11 @@
<td>Total fees:</td><td>{{sum_fees}}</td> <td>Total fees:</td><td>{{sum_fees}}</td>
<td>No of txs:</td><td>{{no_txs}}</td> <td>No of txs:</td><td>{{no_txs}}</td>
</tr> </tr>
<tr>
<td>PoW hash:</td><td>{{blk_pow_hash}}</td>
<td>Difficulty:</td><td>{{blk_difficulty}}</td>
<td></td>
</tr>
</table> </table>
<h3>Miner reward transaction</h3> <h3>Miner reward transaction</h3>
@ -79,4 +84,12 @@
</table> </table>
{{/have_txs}} {{/have_txs}}
{{#enable_as_hex}}
<h5 style="margin-top:1px">
<a href="/blockhex/{{blk_height}}">Block as hex</a>
| <a href="/blockhexcomplete/{{blk_height}}">Complete block as hex</a>
</h5>
{{/enable_as_hex}}
</div> </div>

@ -152,6 +152,12 @@
it is impossible to know whether this is your real spending. <br/> it is impossible to know whether this is your real spending. <br/>
So do not take this number seriously. So do not take this number seriously.
It is probably totally wrong anyway.</span> It is probably totally wrong anyway.</span>
<br/>
<span style="font-size: 14px">
Number of possible our mixins is {{no_all_possible_mixins}}
for {{all_possible_mixins_amount}} xmr
(amount as uint64).
</span>
</h3> </h3>
</div> </div>

@ -531,7 +531,13 @@
{{^have_raw_tx}} {{^have_raw_tx}}
{{^with_ring_signatures}} {{^with_ring_signatures}}
{{#show_more_details_link}} {{#show_more_details_link}}
<h5 style="margin-top:1px"><a href="/tx/{{tx_hash}}/1">More details</a></h5> <h5 style="margin-top:1px">
<a href="/tx/{{tx_hash}}/1">More details</a>
{{#enable_as_hex}}
| <a href="/txhex/{{tx_hash}}">Tx as hex</a>
| <a href="/ringmembershex/{{tx_hash}}">Tx ring members as hex</a>
{{/enable_as_hex}}
</h5>
{{/show_more_details_link}} {{/show_more_details_link}}
{{/with_ring_signatures}} {{/with_ring_signatures}}
{{#with_ring_signatures}} {{#with_ring_signatures}}

@ -935,7 +935,7 @@ decode_ringct(rct::rctSig const& rv,
switch (rv.type) switch (rv.type)
{ {
case rct::RCTTypeSimple: case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof: case rct::RCTTypeBulletproof:
amount = rct::decodeRctSimple(rv, amount = rct::decodeRctSimple(rv,
rct::sk2rct(scalar1), rct::sk2rct(scalar1),
i, i,
@ -943,7 +943,6 @@ decode_ringct(rct::rctSig const& rv,
hw::get_device("default")); hw::get_device("default"));
break; break;
case rct::RCTTypeFull: case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
amount = rct::decodeRct(rv, amount = rct::decodeRct(rv,
rct::sk2rct(scalar1), rct::sk2rct(scalar1),
i, i,
@ -1048,7 +1047,7 @@ decrypt(const std::string &ciphertext,
} }
crypto::chacha_key key; crypto::chacha_key key;
crypto::generate_chacha_key(&skey, sizeof(skey), key); crypto::generate_chacha_key(&skey, sizeof(skey), key, 1);
const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0]; const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0];
@ -1266,4 +1265,10 @@ pause_execution(uint64_t no_seconds, const string& text)
cout << endl; cout << endl;
} }
string
tx_to_hex(transaction const& tx)
{
return epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx));
}
} }

@ -370,6 +370,9 @@ calc_median(It it_begin, It it_end)
void void
pause_execution(uint64_t no_seconds, const string& text = "now"); pause_execution(uint64_t no_seconds, const string& text = "now");
string
tx_to_hex(transaction const& tx);
} }
#endif //XMREG01_TOOLS_H #endif //XMREG01_TOOLS_H
Loading…
Cancel
Save