mirror of
https://git.wownero.com/wownero/onion-wownero-blockchain-explorer.git
synced 2024-08-15 00:33:12 +00:00
proving ringct added
This commit is contained in:
parent
7b64cf1764
commit
aacce05208
2 changed files with 31 additions and 275 deletions
304
src/page.h
304
src/page.h
|
@ -662,6 +662,8 @@ namespace xmreg {
|
||||||
delta_time[3], delta_time[4]);
|
delta_time[3], delta_time[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cout << _tx_info.tx_json << endl;
|
||||||
|
|
||||||
// sum xmr in inputs and ouputs in the given tx
|
// sum xmr in inputs and ouputs in the given tx
|
||||||
pair<uint64_t, uint64_t> sum_inputs = sum_xmr_inputs(_tx_info.tx_json);
|
pair<uint64_t, uint64_t> sum_inputs = sum_xmr_inputs(_tx_info.tx_json);
|
||||||
pair<uint64_t, uint64_t> sum_outputs = sum_xmr_outputs(_tx_info.tx_json);
|
pair<uint64_t, uint64_t> sum_outputs = sum_xmr_outputs(_tx_info.tx_json);
|
||||||
|
@ -669,6 +671,11 @@ namespace xmreg {
|
||||||
// get mixin number in each transaction
|
// get mixin number in each transaction
|
||||||
vector<uint64_t> mixin_numbers = get_mixin_no_in_txs(_tx_info.tx_json);
|
vector<uint64_t> mixin_numbers = get_mixin_no_in_txs(_tx_info.tx_json);
|
||||||
|
|
||||||
|
uint64_t mixin_no = 0;
|
||||||
|
|
||||||
|
if (!mixin_numbers.empty())
|
||||||
|
mixin_numbers.at(0) - 1;
|
||||||
|
|
||||||
// set output page template map
|
// set output page template map
|
||||||
txs.push_back(mstch::map {
|
txs.push_back(mstch::map {
|
||||||
{"timestamp" , xmreg::timestamp_to_str(_tx_info.receive_time)},
|
{"timestamp" , xmreg::timestamp_to_str(_tx_info.receive_time)},
|
||||||
|
@ -679,7 +686,7 @@ namespace xmreg {
|
||||||
{"xmr_outputs" , fmt::format("{:0.2f}", XMR_AMOUNT(sum_outputs.first))},
|
{"xmr_outputs" , fmt::format("{:0.2f}", XMR_AMOUNT(sum_outputs.first))},
|
||||||
{"no_inputs" , sum_inputs.second},
|
{"no_inputs" , sum_inputs.second},
|
||||||
{"no_outputs" , sum_outputs.second},
|
{"no_outputs" , sum_outputs.second},
|
||||||
{"mixin" , fmt::format("{:d}", mixin_numbers.at(0) - 1)},
|
{"mixin" , fmt::format("{:d}", mixin_no)},
|
||||||
{"txsize" , fmt::format("{:0.2f}", static_cast<double>(_tx_info.blob_size)/1024.0)}
|
{"txsize" , fmt::format("{:0.2f}", static_cast<double>(_tx_info.blob_size)/1024.0)}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1227,7 +1234,10 @@ namespace xmreg {
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
show_my_outputs(string tx_hash_str, string xmr_address_str, string viewkey_str)
|
show_my_outputs(string tx_hash_str,
|
||||||
|
string xmr_address_str,
|
||||||
|
string viewkey_str, /* or tx_prv_key_str when tx_prove == true */
|
||||||
|
bool tx_prove = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
// remove white characters
|
// remove white characters
|
||||||
|
@ -1247,7 +1257,10 @@ namespace xmreg {
|
||||||
|
|
||||||
if (viewkey_str.empty())
|
if (viewkey_str.empty())
|
||||||
{
|
{
|
||||||
return string("Viewkey not provided!");
|
if (!tx_prove)
|
||||||
|
return string("Viewkey not provided!");
|
||||||
|
else
|
||||||
|
return string("Tx private key not provided!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse tx hash string to hash object
|
// parse tx hash string to hash object
|
||||||
|
@ -1268,16 +1281,15 @@ namespace xmreg {
|
||||||
return string("Cant parse xmr address: " + xmr_address_str);
|
return string("Cant parse xmr address: " + xmr_address_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse string representing given private viewkey
|
// parse string representing given private key
|
||||||
crypto::secret_key prv_view_key;
|
crypto::secret_key prv_view_key;
|
||||||
|
|
||||||
if (!xmreg::parse_str_secret_key(viewkey_str, prv_view_key))
|
if (!xmreg::parse_str_secret_key(viewkey_str, prv_view_key))
|
||||||
{
|
{
|
||||||
cerr << "Cant parse view key: " << viewkey_str << endl;
|
cerr << "Cant parse the private key: " << viewkey_str << endl;
|
||||||
return string("Cant parse view key: " + viewkey_str);
|
return string("Cant parse private key: " + viewkey_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// tx age
|
// tx age
|
||||||
pair<string, string> age;
|
pair<string, string> age;
|
||||||
|
|
||||||
|
@ -1378,7 +1390,7 @@ namespace xmreg {
|
||||||
{"has_payment_id8" , txd.payment_id8 != null_hash8},
|
{"has_payment_id8" , txd.payment_id8 != null_hash8},
|
||||||
{"payment_id" , pid_str},
|
{"payment_id" , pid_str},
|
||||||
{"payment_id8" , pid8_str},
|
{"payment_id8" , pid8_str},
|
||||||
{"tx_prove" , false}
|
{"tx_prove" , tx_prove}
|
||||||
};
|
};
|
||||||
|
|
||||||
string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F");
|
string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F");
|
||||||
|
@ -1389,16 +1401,17 @@ namespace xmreg {
|
||||||
// to create, so called, derived key.
|
// to create, so called, derived key.
|
||||||
key_derivation derivation;
|
key_derivation derivation;
|
||||||
|
|
||||||
if (!generate_key_derivation(txd.pk, prv_view_key, derivation))
|
public_key pub_key = tx_prove ? address.m_view_public_key : txd.pk;
|
||||||
|
|
||||||
|
if (!generate_key_derivation(pub_key, prv_view_key, derivation))
|
||||||
{
|
{
|
||||||
cerr << "Cant get dervied key for: " << "\n"
|
cerr << "Cant get derived key for: " << "\n"
|
||||||
<< "pub_tx_key: " << txd.pk << " and "
|
<< "pub_tx_key: " << pub_key << " and "
|
||||||
<< "prv_view_key" << prv_view_key << endl;
|
<< "prv_view_key" << prv_view_key << endl;
|
||||||
|
|
||||||
return string("Cant get key_derivation");
|
return string("Cant get key_derivation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mstch::array outputs;
|
mstch::array outputs;
|
||||||
|
|
||||||
uint64_t sum_xmr {0};
|
uint64_t sum_xmr {0};
|
||||||
|
@ -1415,15 +1428,15 @@ namespace xmreg {
|
||||||
// get the tx output public key
|
// get the tx output public key
|
||||||
// that normally would be generated for us,
|
// that normally would be generated for us,
|
||||||
// if someone had sent us some xmr.
|
// if someone had sent us some xmr.
|
||||||
public_key pubkey;
|
public_key tx_pubkey;
|
||||||
|
|
||||||
derive_public_key(derivation,
|
derive_public_key(derivation,
|
||||||
output_idx,
|
output_idx,
|
||||||
address.m_spend_public_key,
|
address.m_spend_public_key,
|
||||||
pubkey);
|
tx_pubkey);
|
||||||
|
|
||||||
// check if generated public key matches the current output's key
|
// check if generated public key matches the current output's key
|
||||||
bool mine_output = (outp.first.key == pubkey);
|
bool mine_output = (outp.first.key == tx_pubkey);
|
||||||
|
|
||||||
// if mine output has RingCT, i.e., tx version is 2
|
// if mine output has RingCT, i.e., tx version is 2
|
||||||
if (mine_output && tx.version == 2)
|
if (mine_output && tx.version == 2)
|
||||||
|
@ -1434,7 +1447,7 @@ namespace xmreg {
|
||||||
bool r;
|
bool r;
|
||||||
|
|
||||||
r = decode_ringct(tx.rct_signatures,
|
r = decode_ringct(tx.rct_signatures,
|
||||||
txd.pk,
|
pub_key,
|
||||||
prv_view_key,
|
prv_view_key,
|
||||||
i,
|
i,
|
||||||
tx.rct_signatures.ecdhInfo[i].mask,
|
tx.rct_signatures.ecdhInfo[i].mask,
|
||||||
|
@ -1491,264 +1504,7 @@ namespace xmreg {
|
||||||
string xmr_address_str,
|
string xmr_address_str,
|
||||||
string tx_prv_key_str)
|
string tx_prv_key_str)
|
||||||
{
|
{
|
||||||
|
return show_my_outputs(tx_hash_str, xmr_address_str, tx_prv_key_str, true);
|
||||||
// remove white characters
|
|
||||||
boost::trim(tx_hash_str);
|
|
||||||
boost::trim(xmr_address_str);
|
|
||||||
boost::trim(tx_prv_key_str);
|
|
||||||
|
|
||||||
if (tx_hash_str.empty())
|
|
||||||
{
|
|
||||||
return string("tx hash/id not provided!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xmr_address_str.empty())
|
|
||||||
{
|
|
||||||
return string("Monero address not provided!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx_prv_key_str.empty())
|
|
||||||
{
|
|
||||||
return string("Tx private key not provided!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse tx hash string to hash object
|
|
||||||
crypto::hash tx_hash;
|
|
||||||
|
|
||||||
if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash))
|
|
||||||
{
|
|
||||||
cerr << "Cant parse tx hash: " << tx_hash_str << endl;
|
|
||||||
return string("Cant get tx hash due to parse error: " + tx_hash_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse string representing given monero address
|
|
||||||
cryptonote::account_public_address address;
|
|
||||||
|
|
||||||
if (!xmreg::parse_str_address(xmr_address_str, address, testnet))
|
|
||||||
{
|
|
||||||
cerr << "Cant parse string address: " << xmr_address_str << endl;
|
|
||||||
return string("Cant parse xmr address: " + xmr_address_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse string representing given private viewkey
|
|
||||||
crypto::secret_key tx_prv_key;
|
|
||||||
|
|
||||||
if (!xmreg::parse_str_secret_key(tx_prv_key_str, tx_prv_key))
|
|
||||||
{
|
|
||||||
cerr << "Cant parse view key: " << tx_prv_key_str << endl;
|
|
||||||
return string("Cant parse view key: " + tx_prv_key_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tx age
|
|
||||||
pair<string, string> age;
|
|
||||||
|
|
||||||
string blk_timestamp {"N/A"};
|
|
||||||
|
|
||||||
// get transaction
|
|
||||||
transaction tx;
|
|
||||||
|
|
||||||
if (!mcore->get_tx(tx_hash, tx))
|
|
||||||
{
|
|
||||||
cerr << "Cant get tx in blockchain: " << tx_hash
|
|
||||||
<< ". \n Check mempool now" << endl;
|
|
||||||
|
|
||||||
vector<pair<tx_info, transaction>> found_txs
|
|
||||||
= search_mempool(tx_hash);
|
|
||||||
|
|
||||||
if (!found_txs.empty())
|
|
||||||
{
|
|
||||||
// there should be only one tx found
|
|
||||||
tx = found_txs.at(0).second;
|
|
||||||
|
|
||||||
// since its tx in mempool, it has no blk yet
|
|
||||||
// so use its recive_time as timestamp to show
|
|
||||||
|
|
||||||
uint64_t tx_recieve_timestamp
|
|
||||||
= found_txs.at(0).first.receive_time;
|
|
||||||
|
|
||||||
blk_timestamp = xmreg::timestamp_to_str(tx_recieve_timestamp);
|
|
||||||
|
|
||||||
age = get_age(server_timestamp,
|
|
||||||
tx_recieve_timestamp,
|
|
||||||
FULL_AGE_FORMAT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// tx is nowhere to be found :-(
|
|
||||||
return string("Cant get tx: " + tx_hash_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tx_details txd = get_tx_details(tx);
|
|
||||||
|
|
||||||
uint64_t tx_blk_height {0};
|
|
||||||
|
|
||||||
bool tx_blk_found {false};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tx_blk_height = core_storage->get_db().get_tx_block_height(tx_hash);
|
|
||||||
tx_blk_found = true;
|
|
||||||
}
|
|
||||||
catch (exception& e)
|
|
||||||
{
|
|
||||||
cerr << "Cant get block height: " << tx_hash
|
|
||||||
<< e.what() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// get block cointaining this tx
|
|
||||||
block blk;
|
|
||||||
|
|
||||||
if (tx_blk_found && !mcore->get_block_by_height(tx_blk_height, blk))
|
|
||||||
{
|
|
||||||
cerr << "Cant get block: " << tx_blk_height << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
string tx_blk_height_str {"N/A"};
|
|
||||||
|
|
||||||
if (tx_blk_found)
|
|
||||||
{
|
|
||||||
// calculate difference between tx and server timestamps
|
|
||||||
age = get_age(server_timestamp, blk.timestamp, FULL_AGE_FORMAT);
|
|
||||||
|
|
||||||
blk_timestamp = xmreg::timestamp_to_str(blk.timestamp);
|
|
||||||
|
|
||||||
tx_blk_height_str = std::to_string(tx_blk_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// payments id. both normal and encrypted (payment_id8)
|
|
||||||
string pid_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.payment_id));
|
|
||||||
string pid8_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.payment_id8));
|
|
||||||
|
|
||||||
// initalise page tempate map with basic info about blockchain
|
|
||||||
mstch::map context {
|
|
||||||
{"testnet" , testnet},
|
|
||||||
{"tx_hash" , tx_hash_str},
|
|
||||||
{"xmr_address" , xmr_address_str},
|
|
||||||
{"tx_prv_key" , REMOVE_HASH_BRAKETS(
|
|
||||||
fmt::format("{:s}", tx_prv_key))},
|
|
||||||
{"tx_pub_key" , REMOVE_HASH_BRAKETS(
|
|
||||||
fmt::format("{:s}", txd.pk))},
|
|
||||||
{"blk_height" , tx_blk_height_str},
|
|
||||||
{"tx_size" , fmt::format("{:0.4f}",
|
|
||||||
static_cast<double>(txd.size) / 1024.0)},
|
|
||||||
{"tx_fee" , fmt::format("{:0.12f}", XMR_AMOUNT(txd.fee))},
|
|
||||||
{"blk_timestamp" , blk_timestamp},
|
|
||||||
{"delta_time" , age.first},
|
|
||||||
{"outputs_no" , txd.output_pub_keys.size()},
|
|
||||||
{"has_payment_id" , txd.payment_id != null_hash},
|
|
||||||
{"has_payment_id8" , txd.payment_id8 != null_hash8},
|
|
||||||
{"payment_id" , pid_str},
|
|
||||||
{"payment_id8" , pid8_str},
|
|
||||||
{"tx_prove" , true}
|
|
||||||
};
|
|
||||||
|
|
||||||
string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F");
|
|
||||||
|
|
||||||
uint64_t output_idx {0};
|
|
||||||
|
|
||||||
// public transaction key is combined with our viewkey
|
|
||||||
// to create, so called, derived key.
|
|
||||||
key_derivation derivation;
|
|
||||||
|
|
||||||
if (!generate_key_derivation(address.m_view_public_key,
|
|
||||||
tx_prv_key,
|
|
||||||
derivation))
|
|
||||||
{
|
|
||||||
cerr << "Cant get dervied key for: " << "\n"
|
|
||||||
<< "pub_tx_key: " << txd.pk << " and "
|
|
||||||
<< "tx_prv_key" << tx_prv_key << endl;
|
|
||||||
|
|
||||||
return string("Cant get key_derivation");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
mstch::array outputs;
|
|
||||||
|
|
||||||
uint64_t sum_xmr {0};
|
|
||||||
|
|
||||||
std::vector<uint64_t> money_transfered(tx.vout.size());
|
|
||||||
|
|
||||||
std::deque<rct::key> mask(tx.vout.size());
|
|
||||||
|
|
||||||
uint64_t i {0};
|
|
||||||
|
|
||||||
for (pair<txout_to_key, uint64_t>& outp: txd.output_pub_keys)
|
|
||||||
{
|
|
||||||
|
|
||||||
// get the tx output public key
|
|
||||||
// that normally would be generated for us,
|
|
||||||
// if someone had sent us some xmr.
|
|
||||||
public_key pubkey;
|
|
||||||
|
|
||||||
derive_public_key(derivation,
|
|
||||||
output_idx,
|
|
||||||
address.m_spend_public_key,
|
|
||||||
pubkey);
|
|
||||||
|
|
||||||
// check if generated public key matches the current output's key
|
|
||||||
bool mine_output = (outp.first.key == pubkey);
|
|
||||||
|
|
||||||
// if mine output has RingCT, i.e., tx version is 2
|
|
||||||
if (mine_output && tx.version == 2)
|
|
||||||
{
|
|
||||||
|
|
||||||
uint64_t rct_amount {0};
|
|
||||||
|
|
||||||
bool r;
|
|
||||||
|
|
||||||
r = decode_ringct(tx.rct_signatures,
|
|
||||||
txd.pk,
|
|
||||||
tx_prv_key,
|
|
||||||
i,
|
|
||||||
tx.rct_signatures.ecdhInfo[i].mask,
|
|
||||||
money_transfered[i]);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
{
|
|
||||||
cerr << "Cant decode ringCT!" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
outp.second = money_transfered[i];
|
|
||||||
|
|
||||||
cout << "i, money_transfered[i]"
|
|
||||||
<< i << ","
|
|
||||||
<< money_transfered[i]
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mine_output)
|
|
||||||
{
|
|
||||||
sum_xmr += outp.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputs.push_back(mstch::map {
|
|
||||||
{"out_pub_key" , REMOVE_HASH_BRAKETS(
|
|
||||||
fmt::format("{:s}",
|
|
||||||
outp.first.key))},
|
|
||||||
{"amount" , fmt::format("{:0.12f}",
|
|
||||||
XMR_AMOUNT(outp.second))},
|
|
||||||
{"mine_output" , mine_output},
|
|
||||||
{"output_idx" , fmt::format("{:02d}", output_idx++)}
|
|
||||||
});
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "outputs.size(): " << outputs.size() << endl;
|
|
||||||
|
|
||||||
context["outputs"] = outputs;
|
|
||||||
context["sum_xmr"] = XMR_AMOUNT(sum_xmr);
|
|
||||||
|
|
||||||
// read my_outputs.html
|
|
||||||
string my_outputs_html = xmreg::read(TMPL_MY_OUTPUTS);
|
|
||||||
|
|
||||||
// add header and footer
|
|
||||||
string full_page = get_full_page(my_outputs_html);
|
|
||||||
|
|
||||||
// render the page
|
|
||||||
return mstch::render(full_page, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
{{#tx_prove}}
|
{{#tx_prove}}
|
||||||
<h3>Prove that you send this tx to the given address</h3>
|
<h3>Prove that you send this tx to the given address</h3>
|
||||||
<h5>address: {{xmr_address}}</h5>
|
<h5>address: {{xmr_address}}</h5>
|
||||||
<h5>Tx private key: {{tx_prv_key}}</h5>
|
<h5>Tx private key: {{viewkey}}</h5>
|
||||||
{{/tx_prove}}
|
{{/tx_prove}}
|
||||||
|
|
||||||
<h3>Outputs ({{outputs_no}})</h3>
|
<h3>Outputs ({{outputs_no}})</h3>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue