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})
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)

@ -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",

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 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();

@ -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,11 +2498,16 @@ public:
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)
@ -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…
Cancel
Save