mirror of
https://git.wownero.com/wownero/onion-wownero-blockchain-explorer.git
synced 2024-08-15 00:33:12 +00:00
Merge pull request #149 from moneroexamples/devel
For Monero version 0.13
This commit is contained in:
commit
e6006acf48
17 changed files with 17728 additions and 13310 deletions
|
@ -6,9 +6,7 @@ set(PROJECT_NAME
|
|||
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++14")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
if (WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj -O3")
|
||||
|
@ -119,7 +117,7 @@ set(LIBRARIES
|
|||
checkpoints
|
||||
version
|
||||
epee
|
||||
pcsclite
|
||||
sodium
|
||||
${Boost_LIBRARIES}
|
||||
pthread
|
||||
unbound
|
||||
|
@ -130,7 +128,7 @@ set(LIBRARIES
|
|||
if(APPLE)
|
||||
set(LIBRARIES ${LIBRARIES} "-framework IOKit -framework PCSC")
|
||||
else()
|
||||
set(LIBRARIES ${LIBRARIES} atomic)
|
||||
set(LIBRARIES ${LIBRARIES} atomic pcsclite)
|
||||
endif()
|
||||
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT WIN32)
|
||||
|
|
14
README.md
14
README.md
|
@ -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)).
|
||||
|
||||
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://MoneroExplorer.com/](https://moneroexplorer.com/) - 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.
|
||||
- [https://moneroexplorer.pro/](https://moneroexplorer.pro/) - nice looking one, https enabled.
|
||||
- [http://monerochain.com/](http://monerochain.com/) - JSON API based, multiple nodes.
|
||||
- [https://blox.minexmr.com/](https://blox.minexmr.com/) - - https enabled.
|
||||
|
||||
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://explorer.monero-otc.com/](https://explorer.monero-otc.com/) - https enabled.
|
||||
|
||||
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):
|
||||
|
||||
|
@ -54,7 +52,6 @@ i2p users (main Monero network):
|
|||
Alternative block explorers:
|
||||
|
||||
- [http://moneroblocks.info](http://moneroblocks.info/)
|
||||
- [https://monerobase.com](https://monerobase.com/)
|
||||
- [https://monerovision.com](https://monerovision.com)
|
||||
- [http://chainradar.com](http://chainradar.com/xmr/blocks)
|
||||
|
||||
|
@ -93,7 +90,7 @@ Current development branch:
|
|||
|
||||
## 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:
|
||||
|
||||
|
@ -110,10 +107,8 @@ git clone --recursive https://github.com/monero-project/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
|
||||
|
@ -697,7 +692,6 @@ curl -w "\n" -X GET http://127.0.0.1:8081/api/outputsblocks?address=9sDyNU82ih1
|
|||
Example result:
|
||||
|
||||
```json
|
||||
{
|
||||
{
|
||||
"data": {
|
||||
"address": "0182d5be0f708cecf2b6f9889738bde5c930fad846d5b530e021afd1ae7e24a687ad50af3a5d38896655669079ad0163b4a369f6c852cc816dace5fc7792b72f",
|
||||
|
|
19421
ext/json.hpp
19421
ext/json.hpp
File diff suppressed because it is too large
Load diff
97
main.cpp
97
main.cpp
|
@ -44,6 +44,7 @@ main(int ac, const char* av[])
|
|||
}
|
||||
|
||||
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 deamon_url_opt = opts.get_option<string>("deamon-url");
|
||||
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_mixin_details_opt = opts.get_option<bool>("enable-mixin-details");
|
||||
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_block_cache_opt = opts.get_option<bool>("enable-block-cache");
|
||||
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_mixin_details {*enable_mixin_details_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_block_cache {*enable_block_cache_opt};
|
||||
bool enable_emission_monitor {*enable_emission_monitor_opt};
|
||||
|
@ -100,9 +103,13 @@ main(int ac, const char* av[])
|
|||
uint32_t log_level = 0;
|
||||
mlog_configure("", true);
|
||||
|
||||
(void) log_level;
|
||||
|
||||
//cast port number in string to uint
|
||||
uint16_t app_port = boost::lexical_cast<uint16_t>(*port_opt);
|
||||
|
||||
string bindaddr = *bindaddr_opt;
|
||||
|
||||
// cast no_blocks_on_index_opt to uint
|
||||
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,
|
||||
enable_pusher,
|
||||
enable_js,
|
||||
enable_as_hex,
|
||||
enable_key_image_checker,
|
||||
enable_output_key_checker,
|
||||
enable_autorefresh_option,
|
||||
|
@ -282,7 +290,7 @@ main(int ac, const char* av[])
|
|||
};
|
||||
|
||||
CROW_ROUTE(app, "/")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return crow::response(xmrblocks.index2());
|
||||
});
|
||||
|
||||
|
@ -292,20 +300,43 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
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));
|
||||
});
|
||||
|
||||
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)));
|
||||
});
|
||||
|
||||
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)));
|
||||
});
|
||||
|
||||
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>")
|
||||
([&](string tx_hash, uint16_t with_ring_signatures)
|
||||
{
|
||||
|
@ -403,7 +434,7 @@ main(int ac, const char* av[])
|
|||
if (enable_pusher)
|
||||
{
|
||||
CROW_ROUTE(app, "/rawtx")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.show_rawtx();
|
||||
});
|
||||
|
||||
|
@ -433,7 +464,7 @@ main(int ac, const char* av[])
|
|||
if (enable_key_image_checker)
|
||||
{
|
||||
CROW_ROUTE(app, "/rawkeyimgs")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.show_rawkeyimgs();
|
||||
});
|
||||
|
||||
|
@ -464,7 +495,7 @@ main(int ac, const char* av[])
|
|||
if (enable_output_key_checker)
|
||||
{
|
||||
CROW_ROUTE(app, "/rawoutputkeys")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.show_rawoutputkeys();
|
||||
});
|
||||
|
||||
|
@ -499,13 +530,13 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
CROW_ROUTE(app, "/mempool")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.mempool(true);
|
||||
});
|
||||
|
||||
// alias to "/mempool"
|
||||
CROW_ROUTE(app, "/txpool")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.mempool(true);
|
||||
});
|
||||
|
||||
|
@ -526,52 +557,52 @@ main(int ac, const char* av[])
|
|||
cout << "Enable JavaScript checking of outputs and proving txs\n";
|
||||
|
||||
CROW_ROUTE(app, "/js/jquery.min.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("jquery.min.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/crc32.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("crc32.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/biginteger.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("biginteger.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/crypto.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("crypto.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/config.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("config.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/nacl-fast-cn.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("nacl-fast-cn.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/base58.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("base58.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/cn_util.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("cn_util.js");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/js/sha3.js")
|
||||
([&](const crow::request& req) {
|
||||
([&]() {
|
||||
return xmrblocks.get_js_file("sha3.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
|
||||
// from the above real files.
|
||||
return xmrblocks.get_js_file("all_in_one.js");
|
||||
|
@ -585,7 +616,7 @@ main(int ac, const char* av[])
|
|||
cout << "Enable JSON API\n";
|
||||
|
||||
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))};
|
||||
|
||||
|
@ -593,15 +624,23 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
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))};
|
||||
|
||||
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>")
|
||||
([&](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))};
|
||||
|
||||
|
@ -609,7 +648,7 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
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))};
|
||||
|
||||
|
@ -650,7 +689,7 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
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))};
|
||||
|
||||
|
@ -658,7 +697,7 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/networkinfo")
|
||||
([&](const crow::request &req) {
|
||||
([&]() {
|
||||
|
||||
myxmr::jsonresponse r{xmrblocks.json_networkinfo()};
|
||||
|
||||
|
@ -666,7 +705,7 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/emission")
|
||||
([&](const crow::request &req) {
|
||||
([&]() {
|
||||
|
||||
myxmr::jsonresponse r{xmrblocks.json_emission()};
|
||||
|
||||
|
@ -742,7 +781,7 @@ main(int ac, const char* av[])
|
|||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/version")
|
||||
([&](const crow::request &req) {
|
||||
([&]() {
|
||||
|
||||
myxmr::jsonresponse r{xmrblocks.json_version()};
|
||||
|
||||
|
@ -766,13 +805,13 @@ main(int ac, const char* av[])
|
|||
if (use_ssl)
|
||||
{
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
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-js", value<bool>()->default_value(false)->implicit_value(true),
|
||||
"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 users to have the index page on autorefresh")
|
||||
("enable-emission-monitor", value<bool>()->default_value(false)->implicit_value(true),
|
||||
"enable Monero total emission monitoring thread")
|
||||
("port,p", value<string>()->default_value("8081"),
|
||||
"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(""),
|
||||
"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(""),
|
||||
|
|
|
@ -137,8 +137,8 @@ CurrentBlockchainStatus::calculate_emission_in_blocks(
|
|||
|
||||
uint64_t coinbase_amount = get_outs_money_amount(blk.miner_tx);
|
||||
|
||||
std::list<transaction> txs;
|
||||
std::list<crypto::hash> missed_txs;
|
||||
vector<transaction> txs;
|
||||
vector<crypto::hash> missed_txs;
|
||||
|
||||
uint64_t tx_fee_amount = 0;
|
||||
|
||||
|
|
|
@ -139,10 +139,13 @@ MempoolStatus::read_mempool()
|
|||
|
||||
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();
|
||||
|
||||
last_tx.tx_hash = tx_hash;
|
||||
last_tx.tx = tx;
|
||||
|
||||
// key images of inputs
|
||||
vector<txin_to_key> input_key_imgs;
|
||||
|
||||
|
@ -168,7 +171,7 @@ MempoolStatus::read_mempool()
|
|||
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}", 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.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}");
|
||||
|
@ -264,6 +267,7 @@ MempoolStatus::read_network_info()
|
|||
local_copy.cumulative_difficulty = rpc_network_info.cumulative_difficulty;
|
||||
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_weight_limit = rpc_network_info.block_weight_limit;
|
||||
local_copy.start_time = rpc_network_info.start_time;
|
||||
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ struct MempoolStatus
|
|||
uint64_t cumulative_difficulty {0};
|
||||
uint64_t block_size_limit {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_median_str[10]; // std::string is not trivially copyable
|
||||
uint64_t start_time {0};
|
||||
|
|
|
@ -80,6 +80,12 @@ MicroCore::get_core()
|
|||
return m_blockchain_storage;
|
||||
}
|
||||
|
||||
tx_memory_pool&
|
||||
MicroCore::get_mempool()
|
||||
{
|
||||
return m_mempool;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
MicroCore::get_blk_timestamp(uint64_t blk_height)
|
||||
{
|
||||
|
@ -332,6 +266,28 @@ init_blockchain(const string& path,
|
|||
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
|
||||
MicroCore::get_blkchain_path()
|
||||
{
|
||||
|
|
|
@ -44,6 +44,9 @@ namespace xmreg
|
|||
Blockchain&
|
||||
get_core();
|
||||
|
||||
tx_memory_pool&
|
||||
get_mempool();
|
||||
|
||||
bool
|
||||
get_block_by_height(const uint64_t& height, block& blk);
|
||||
|
||||
|
@ -59,15 +62,12 @@ namespace xmreg
|
|||
tx_out& out,
|
||||
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
|
||||
get_blk_timestamp(uint64_t blk_height);
|
||||
|
||||
bool
|
||||
get_block_complete_entry(block const& b, block_complete_entry& bce);
|
||||
|
||||
string
|
||||
get_blkchain_path();
|
||||
|
||||
|
|
528
src/page.h
528
src/page.h
|
@ -30,6 +30,7 @@
|
|||
#include <limits>
|
||||
#include <ctime>
|
||||
#include <future>
|
||||
#include <visitor/render_node.hpp>
|
||||
|
||||
|
||||
#define TMPL_DIR "./templates"
|
||||
|
@ -66,7 +67,7 @@
|
|||
#define JS_SHA3 TMPL_DIR "/js/sha3.js"
|
||||
|
||||
#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 ONIONEXPLORER_RPC_VERSION \
|
||||
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
|
||||
{
|
||||
|
||||
|
@ -124,6 +190,8 @@ using namespace std;
|
|||
using epee::string_tools::pod_to_hex;
|
||||
using epee::string_tools::hex_to_pod;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief The tx_details struct
|
||||
*
|
||||
|
@ -189,8 +257,8 @@ struct tx_details
|
|||
|
||||
mixin_str = std::to_string(mixin_no);
|
||||
fee_str = fmt::format("{:0.6f}", xmr_amount);
|
||||
fee_short_str = fmt::format("{:0.3f}", xmr_amount);
|
||||
payed_for_kB_str = fmt::format("{:0.3f}", payed_for_kB);
|
||||
fee_short_str = fmt::format("{:0.4f}", xmr_amount);
|
||||
payed_for_kB_str = fmt::format("{:0.4f}", payed_for_kB);
|
||||
}
|
||||
|
||||
|
||||
|
@ -298,6 +366,7 @@ class page
|
|||
bool enable_mixins_details;
|
||||
bool enable_tx_cache;
|
||||
bool enable_block_cache;
|
||||
bool enable_as_hex;
|
||||
bool show_cache_times;
|
||||
|
||||
|
||||
|
@ -348,6 +417,7 @@ public:
|
|||
cryptonote::network_type _nettype,
|
||||
bool _enable_pusher,
|
||||
bool _enable_js,
|
||||
bool _enable_as_hex,
|
||||
bool _enable_key_image_checker,
|
||||
bool _enable_output_key_checker,
|
||||
bool _enable_autorefresh_option,
|
||||
|
@ -367,6 +437,7 @@ public:
|
|||
nettype {_nettype},
|
||||
enable_pusher {_enable_pusher},
|
||||
enable_js {_enable_js},
|
||||
enable_as_hex {_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},
|
||||
|
@ -512,12 +583,12 @@ public:
|
|||
|
||||
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
|
||||
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
|
||||
mstch::map context {
|
||||
{"testnet" , testnet},
|
||||
|
@ -583,7 +654,7 @@ public:
|
|||
crypto::hash blk_hash = core_storage->get_block_id_by_height(i);
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -716,8 +787,8 @@ public:
|
|||
// get all transactions in the block found
|
||||
// initialize the first list with transaction for solving
|
||||
// the block i.e. coinbase.
|
||||
list<cryptonote::transaction> blk_txs {blk.miner_tx};
|
||||
list<crypto::hash> missed_txs;
|
||||
vector<cryptonote::transaction> blk_txs {blk.miner_tx};
|
||||
vector<crypto::hash> 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
|
||||
string hash_rate;
|
||||
|
||||
if (testnet || stagenet)
|
||||
{
|
||||
hash_rate = std::to_string(current_network_info.hash_rate) + " H/s";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (current_network_info.hash_rate > 1e6)
|
||||
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,
|
||||
current_network_info.info_timestamp);
|
||||
|
@ -1157,7 +1226,7 @@ public:
|
|||
}
|
||||
|
||||
// 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
|
||||
transaction coinbase_tx = blk.miner_tx;
|
||||
|
@ -1175,6 +1244,10 @@ public:
|
|||
_blk_height, current_blockchain_height);
|
||||
|
||||
// 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 {
|
||||
{"testnet" , testnet},
|
||||
{"stagenet" , stagenet},
|
||||
|
@ -1184,6 +1257,7 @@ public:
|
|||
{"blk_timestamp_epoch" , blk.timestamp},
|
||||
{"prev_hash" , prev_hash_str},
|
||||
{"next_hash" , next_hash_str},
|
||||
{"enable_as_hex" , enable_as_hex},
|
||||
{"have_next_hash" , have_next_hash},
|
||||
{"have_prev_hash" , have_prev_hash},
|
||||
{"have_txs" , have_txs},
|
||||
|
@ -1192,6 +1266,8 @@ public:
|
|||
{"blk_age" , age.first},
|
||||
{"delta_time" , delta_time},
|
||||
{"blk_nonce" , blk.nonce},
|
||||
{"blk_pow_hash" , blk_pow_hash_str},
|
||||
{"blk_difficulty" , blk_difficulty},
|
||||
{"age_format" , age.second},
|
||||
{"major_ver" , std::to_string(blk.major_version)},
|
||||
{"minor_ver" , std::to_string(blk.minor_version)},
|
||||
|
@ -1524,6 +1600,152 @@ public:
|
|||
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
|
||||
show_my_outputs(string tx_hash_str,
|
||||
string xmr_address_str,
|
||||
|
@ -1726,9 +1948,9 @@ public:
|
|||
|
||||
string shortcut_url = domain
|
||||
+ (tx_prove ? "/prove" : "/myoutputs")
|
||||
+ "/" + tx_hash_str
|
||||
+ "/" + xmr_address_str
|
||||
+ "/" + viewkey_str;
|
||||
+ '/' + tx_hash_str
|
||||
+ '/' + xmr_address_str
|
||||
+ '/' + viewkey_str;
|
||||
|
||||
|
||||
string viewkey_str_partial = viewkey_str;
|
||||
|
@ -1771,9 +1993,8 @@ public:
|
|||
key_derivation derivation;
|
||||
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 "
|
||||
"size doesn't match with the provided tx secret keys");
|
||||
|
@ -1813,7 +2034,8 @@ public:
|
|||
|
||||
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);
|
||||
}
|
||||
|
@ -1850,7 +2072,8 @@ public:
|
|||
|
||||
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],
|
||||
output_idx,
|
||||
|
@ -1875,15 +2098,17 @@ public:
|
|||
|
||||
bool r;
|
||||
|
||||
r = decode_ringct(tx.rct_signatures,
|
||||
with_additional ? additional_derivations[output_idx] : derivation,
|
||||
r = decode_ringct(
|
||||
tx.rct_signatures,
|
||||
with_additional
|
||||
? additional_derivations[output_idx] : derivation,
|
||||
output_idx,
|
||||
tx.rct_signatures.ecdhInfo[output_idx].mask,
|
||||
rct_amount);
|
||||
|
||||
if (!r)
|
||||
{
|
||||
cerr << "\nshow_my_outputs: Cant decode ringCT! " << endl;
|
||||
cerr << "\nshow_my_outputs: Cant decode RingCT!\n";
|
||||
}
|
||||
|
||||
outp.second = rct_amount;
|
||||
|
@ -1927,9 +2152,14 @@ public:
|
|||
// parefct matches must be equal to number of inputs in a tx.
|
||||
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)
|
||||
{
|
||||
|
||||
// get absolute offsets of mixins
|
||||
std::vector<uint64_t> absolute_offsets
|
||||
= cryptonote::relative_output_offsets_to_absolute(
|
||||
|
@ -1941,7 +2171,8 @@ public:
|
|||
|
||||
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
|
||||
// go to next input if a too large offset was found
|
||||
if (are_absolute_offsets_good(absolute_offsets, in_key) == false)
|
||||
|
@ -2009,10 +2240,9 @@ public:
|
|||
|
||||
string out_msg = fmt::format(
|
||||
"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;
|
||||
}
|
||||
|
@ -2028,7 +2258,6 @@ public:
|
|||
if (!mcore->get_tx(tx_out_idx.first, mixin_tx))
|
||||
{
|
||||
cerr << "Cant get tx: " << tx_out_idx.first << endl;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2036,33 +2265,35 @@ public:
|
|||
|
||||
mixins.push_back(mstch::map{
|
||||
{"mixin_pub_key" , out_pub_key_str},
|
||||
make_pair<string, mstch::array>("mixin_outputs" , mstch::array{}),
|
||||
{"has_mixin_outputs" , false}
|
||||
});
|
||||
make_pair<string, mstch::array>("mixin_outputs"
|
||||
, mstch::array{}),
|
||||
{"has_mixin_outputs" , false}});
|
||||
|
||||
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
|
||||
= boost::get<mstch::map>(mixins.back())["has_mixin_outputs"];
|
||||
|
||||
|
||||
bool found_something {false};
|
||||
|
||||
|
||||
public_key mixin_tx_pub_key
|
||||
= 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);
|
||||
|
||||
// public transaction key is combined with our viewkey
|
||||
// to create, so called, derived key.
|
||||
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"
|
||||
<< "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)
|
||||
{
|
||||
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"
|
||||
<< "pub_tx_key: " << mixin_additional_tx_pub_keys[i] << " and "
|
||||
<< "prv_view_key" << prv_view_key << endl;
|
||||
<< "pub_tx_key: " << mixin_additional_tx_pub_keys[i]
|
||||
<< " and prv_view_key" << prv_view_key << endl;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -2090,23 +2323,28 @@ public:
|
|||
mixin_outputs.push_back(mstch::map{
|
||||
{"mix_tx_hash" , mixin_tx_hash_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}
|
||||
});
|
||||
|
||||
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
|
||||
= 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
|
||||
// and check if its ours.
|
||||
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 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
|
||||
bool mine_output = (txout_k.key == tx_pubkey_generated);
|
||||
|
||||
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],
|
||||
output_idx_in_tx,
|
||||
address_info.address.m_spend_public_key,
|
||||
tx_pubkey_generated);
|
||||
|
||||
mine_output = (txout_k.key == tx_pubkey_generated);
|
||||
|
||||
with_additional = true;
|
||||
}
|
||||
|
||||
|
@ -2154,16 +2397,17 @@ public:
|
|||
|
||||
bool r;
|
||||
|
||||
r = decode_ringct(mixin_tx.rct_signatures,
|
||||
with_additional ? additional_derivations[output_idx_in_tx] : derivation,
|
||||
r = decode_ringct(
|
||||
mixin_tx.rct_signatures,
|
||||
with_additional
|
||||
? additional_derivations[output_idx_in_tx] : derivation,
|
||||
output_idx_in_tx,
|
||||
mixin_tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask,
|
||||
rct_amount);
|
||||
|
||||
if (!r)
|
||||
{
|
||||
cerr << "show_my_outputs: key images: Cant decode ringCT!" << endl;
|
||||
}
|
||||
cerr << "show_my_outputs: key images: "
|
||||
"Cant decode RingCT!\n";
|
||||
|
||||
amount = rct_amount;
|
||||
|
||||
|
@ -2190,11 +2434,9 @@ public:
|
|||
});
|
||||
|
||||
//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)
|
||||
{
|
||||
|
||||
found_something = true;
|
||||
show_key_images = true;
|
||||
|
||||
|
@ -2202,9 +2444,7 @@ public:
|
|||
// public key of an outputs used in ring signature,
|
||||
// matches a public key in a mixin_tx
|
||||
if (txout_k.key != output_data.pubkey)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// sum up only first output matched found in each input
|
||||
if (no_of_output_matches_found == 0)
|
||||
|
@ -2222,6 +2462,7 @@ public:
|
|||
else if (mixin_tx.version == 2) // ringct
|
||||
{
|
||||
sum_mixin_xmr += amount;
|
||||
ringct_amount += amount;
|
||||
}
|
||||
|
||||
no_of_matched_mixins++;
|
||||
|
@ -2247,11 +2488,9 @@ public:
|
|||
// << ", key_img == input_key: " << (key_img == in_key.k_image)
|
||||
// << endl;
|
||||
|
||||
|
||||
|
||||
no_of_output_matches_found++;
|
||||
|
||||
}
|
||||
} // if (mine_output)
|
||||
|
||||
} // for (const pair<txout_to_key, uint64_t>& mix_out: txd.output_pub_keys)
|
||||
|
||||
|
@ -2259,12 +2498,17 @@ public:
|
|||
|
||||
has_mixin_outputs = found_something;
|
||||
|
||||
// all_possible_mixins_amount += amount;
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
@ -2283,6 +2527,23 @@ public:
|
|||
|
||||
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
|
||||
// what we get + fee, and number of perferctly matched
|
||||
// mixis is equal to number of inputs
|
||||
|
@ -2657,7 +2918,7 @@ public:
|
|||
"Its prefix is: {:s}",
|
||||
data_prefix);
|
||||
|
||||
cout << msg << endl;
|
||||
cerr << msg << endl;
|
||||
|
||||
return string(msg);
|
||||
}
|
||||
|
@ -2666,6 +2927,11 @@ public:
|
|||
crypto::hash tx_prefix_hash_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,
|
||||
tx_from_blob,
|
||||
tx_hash_from_blob,
|
||||
|
@ -3965,6 +4231,8 @@ public:
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Lets use this json api convention for success and error
|
||||
* https://labs.omniti.com/labs/jsend
|
||||
|
@ -4214,6 +4482,56 @@ public:
|
|||
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
|
||||
* https://labs.omniti.com/labs/jsend
|
||||
|
@ -4293,7 +4611,7 @@ public:
|
|||
|
||||
|
||||
// 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
|
||||
transaction coinbase_tx = blk.miner_tx;
|
||||
|
@ -4522,7 +4840,7 @@ public:
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -4541,8 +4859,8 @@ public:
|
|||
|
||||
json& j_txs = j_blocks.back()["txs"];
|
||||
|
||||
list<cryptonote::transaction> blk_txs {blk.miner_tx};
|
||||
list<crypto::hash> missed_txs;
|
||||
vector<cryptonote::transaction> blk_txs {blk.miner_tx};
|
||||
vector<crypto::hash> 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
|
||||
list <cryptonote::transaction> blk_txs{blk.miner_tx};
|
||||
list <crypto::hash> missed_txs;
|
||||
vector<cryptonote::transaction> blk_txs{blk.miner_tx};
|
||||
vector<crypto::hash> 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_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 {
|
||||
{"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["server_time"] = server_time_str;
|
||||
context["enable_mixins_details"] = detailed_view;
|
||||
context["enable_as_hex"] = enable_as_hex;
|
||||
context["show_part_of_inputs"] = show_part_of_inputs;
|
||||
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
|
||||
search_mempool(crypto::hash tx_hash,
|
||||
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
|
||||
add_js_files(mstch::map& context)
|
||||
{
|
||||
|
|
|
@ -275,9 +275,9 @@ rpccalls::get_dynamic_per_kb_fee_estimate(
|
|||
uint64_t& fee,
|
||||
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);
|
||||
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);
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,11 @@
|
|||
<td>Total fees:</td><td>{{sum_fees}}</td>
|
||||
<td>No of txs:</td><td>{{no_txs}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PoW hash:</td><td>{{blk_pow_hash}}</td>
|
||||
<td>Difficulty:</td><td>{{blk_difficulty}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>Miner reward transaction</h3>
|
||||
|
@ -79,4 +84,12 @@
|
|||
</table>
|
||||
{{/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>
|
||||
|
|
|
@ -152,6 +152,12 @@
|
|||
it is impossible to know whether this is your real spending. <br/>
|
||||
So do not take this number seriously.
|
||||
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>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -531,7 +531,13 @@
|
|||
{{^have_raw_tx}}
|
||||
{{^with_ring_signatures}}
|
||||
{{#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}}
|
||||
{{/with_ring_signatures}}
|
||||
{{#with_ring_signatures}}
|
||||
|
|
|
@ -935,7 +935,7 @@ decode_ringct(rct::rctSig const& rv,
|
|||
switch (rv.type)
|
||||
{
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
case rct::RCTTypeBulletproof:
|
||||
amount = rct::decodeRctSimple(rv,
|
||||
rct::sk2rct(scalar1),
|
||||
i,
|
||||
|
@ -943,7 +943,6 @@ decode_ringct(rct::rctSig const& rv,
|
|||
hw::get_device("default"));
|
||||
break;
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
amount = rct::decodeRct(rv,
|
||||
rct::sk2rct(scalar1),
|
||||
i,
|
||||
|
@ -1048,7 +1047,7 @@ decrypt(const std::string &ciphertext,
|
|||
}
|
||||
|
||||
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];
|
||||
|
||||
|
@ -1266,4 +1265,10 @@ pause_execution(uint64_t no_seconds, const string& text)
|
|||
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
|
||||
pause_execution(uint64_t no_seconds, const string& text = "now");
|
||||
|
||||
string
|
||||
tx_to_hex(transaction const& tx);
|
||||
|
||||
}
|
||||
|
||||
#endif //XMREG01_TOOLS_H
|
Loading…
Add table
Add a link
Reference in a new issue