sending tx proving added

master
moneroexamples 8 years ago
parent c2f3949340
commit bbc39559a1

@ -198,6 +198,19 @@ int main(int ac, const char* av[]) {
return xmrblocks.show_my_outputs(tx_hash, xmr_address, viewkey);
});
CROW_ROUTE(app, "/prove").methods("GET"_method)
([&](const crow::request& req) {
string tx_hash = string(req.url_params.get("txhash"));
string tx_prv_key = string(req.url_params.get("txprvkey"));
string xmr_address = string(req.url_params.get("xmraddress"));
return xmrblocks.show_prove(tx_hash, xmr_address, tx_prv_key);
});
CROW_ROUTE(app, "/search").methods("GET"_method)
([&](const crow::request& req) {
return xmrblocks.search(string(req.url_params.get("value")));

@ -1377,7 +1377,8 @@ namespace xmreg {
{"has_payment_id" , txd.payment_id != null_hash},
{"has_payment_id8" , txd.payment_id8 != null_hash8},
{"payment_id" , pid_str},
{"payment_id8" , pid8_str}
{"payment_id8" , pid8_str},
{"tx_prove" , false}
};
string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F");
@ -1485,6 +1486,274 @@ namespace xmreg {
return mstch::render(full_page, context);
}
string
show_prove(string tx_hash_str,
string xmr_address_str,
string tx_prv_key_str)
{
// 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);
}
string
search(string search_text)
{

@ -78,6 +78,54 @@
box-shadow: 0 0 5px 1px #969696;
}
.tabs {
position: relative;
min-height: 200px; /* This part sucks */
clear: both;
margin: 25px 0;
}
.tab {
float: left;
}
.tab label {
background: black;
padding: 10px;
border: 1px solid #ccc;
margin-left: -1px;
position: relative;
left: 1px;
}
.tab [type=radio] {
display: none;
}
.content {
position: absolute;
top: 28px;
left: 0;
background: black;
right: 0;
bottom: 0;
padding: 20px;
border: 1px solid #ccc;
}
[type=radio]:checked ~ label {
background: #505050 ;
border-bottom: 1px solid white;
z-index: 2;
}
[type=radio]:checked ~ label ~ .content {
z-index: 1;
}
</style>
</head>

@ -25,9 +25,16 @@
</table>
{{^tx_prove}}
<h3>Checking which outputs belong to the given address and viewkey</h3>
<h5>address: {{xmr_address}}</h5>
<h5>viewkey: {{viewkey}}</h5>
{{/tx_prove}}
{{#tx_prove}}
<h3>Prove that you send this tx to the given address</h3>
<h5>address: {{xmr_address}}</h5>
<h5>Tx private key: {{tx_prv_key}}</h5>
{{/tx_prove}}
<h3>Outputs ({{outputs_no}})</h3>
<div class="center">

@ -65,8 +65,14 @@
</table>
</div>
<h4 style="margin-bottom:0px">Decode the amounts of the above outputs which belong to the following address and viewkey</h4>
<div class="center" style="width:80%">
<div class="tabs">
<div class="tab">
<input type="radio" id="tab-1" name="tab-group-1" checked>
<label for="tab-1">Decode outputs</label>
<div class="content">
<h4 style="margin: 0px">Check which outputs belong to given Moenro address and viewkey</h4>
<form action="/myoutputs" method="get" style="width:100%; margin-top:2px" class="style-1">
<input type="hidden" name="tx_hash" size="100" value="{{tx_hash}}"><br/>
<input type="text" name="xmr_address" size="100" placeholder="Monero address"><br/>
@ -74,6 +80,30 @@
<input type="submit" value="Decode outputs" style="margin-top:5px" >
</form>
</div>
</div>
<div class="tab">
<input type="radio" id="tab-2" name="tab-group-1">
<label for="tab-2">Prove sending</label>
<div class="content">
<h4 style="margin: 0px">Prove to someone that you send them Monero in this transaction</h4>
<h5 style="margin: 0px">Tx private key can be obtained using <i>get_tx_key</i>
command in <i>monero-wallet-cli</i> command line tool</h5>
<form action="/prove" method="get" style="width:100%; margin-top:15px" class="style-1">
<input type="hidden" name="txhash" size="100" value="{{tx_hash}}"><br/>
<input type="text" name="txprvkey" size="100" placeholder="Tx private key" style="margin-top:5px"><br/>
<input type="text" name="xmraddress" size="100"placeholder="Recipient's Monero Address" style="margin-top:5px"><br/>
<input type="submit" value="Prove" style="margin-top:5px">
</form>
</div>
</div>
</div>
</div>
{{#has_inputs}}
<h3>Inputs' mixins time scale (from {{min_mix_time}} till {{max_mix_time}};

Loading…
Cancel
Save