mirror of
https://git.wownero.com/wownero/onion-wownero-blockchain-explorer.git
synced 2024-08-15 00:33:12 +00:00
Merge pull request #29 from moneroexamples/refactor_viewkey
Decode mixins using viewkey and address
This commit is contained in:
commit
22c09ab5d4
5 changed files with 335 additions and 199 deletions
|
@ -109,33 +109,32 @@ namespace xmreg
|
||||||
bool
|
bool
|
||||||
MicroCore::get_block_by_height(const uint64_t& height, block& blk)
|
MicroCore::get_block_by_height(const uint64_t& height, block& blk)
|
||||||
{
|
{
|
||||||
|
|
||||||
crypto::hash block_id;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
block_id = m_blockchain_storage.get_block_id_by_height(height);
|
blk = m_blockchain_storage.get_db().get_block_from_height(height);
|
||||||
}
|
}
|
||||||
catch (const exception& e)
|
catch (const BLOCK_DNE& e)
|
||||||
{
|
{
|
||||||
cerr << e.what() << endl;
|
cerr << "Block of height " << height
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_blockchain_storage.have_block(block_id))
|
|
||||||
{
|
|
||||||
cerr << "Block with hash " << block_id
|
|
||||||
<< " not found in the blockchain!"
|
<< " not found in the blockchain!"
|
||||||
|
<< e.what()
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
catch (const DB_ERROR& e)
|
||||||
if (!m_blockchain_storage.get_block_by_hash(block_id, blk))
|
|
||||||
{
|
{
|
||||||
cerr << "Block with hash " << block_id
|
cerr << "Blockchain access error when getting block " << height
|
||||||
<< "and height " << height << " not found!"
|
<< e.what()
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
cerr << "Something went terribly wrong when getting block " << height
|
||||||
|
<< endl;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
372
src/page.h
372
src/page.h
|
@ -1283,27 +1283,28 @@ public:
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
// initialize with regular amount
|
|
||||||
uint64_t rct_amount = money_transfered[output_idx];
|
|
||||||
|
|
||||||
bool r;
|
|
||||||
|
|
||||||
r = decode_ringct(tx.rct_signatures,
|
|
||||||
pub_key,
|
|
||||||
prv_view_key,
|
|
||||||
output_idx,
|
|
||||||
tx.rct_signatures.ecdhInfo[output_idx].mask,
|
|
||||||
rct_amount);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
{
|
|
||||||
cerr << "\nshow_my_outputs: Cant decode ringCT! " << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cointbase txs have amounts in plain sight.
|
// cointbase txs have amounts in plain sight.
|
||||||
// so use amount from ringct, only for non-coinbase txs
|
// so use amount from ringct, only for non-coinbase txs
|
||||||
if (!is_coinbase(tx))
|
if (!is_coinbase(tx))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// initialize with regular amount
|
||||||
|
uint64_t rct_amount = money_transfered[output_idx];
|
||||||
|
|
||||||
|
bool r;
|
||||||
|
|
||||||
|
r = decode_ringct(tx.rct_signatures,
|
||||||
|
pub_key,
|
||||||
|
prv_view_key,
|
||||||
|
output_idx,
|
||||||
|
tx.rct_signatures.ecdhInfo[output_idx].mask,
|
||||||
|
rct_amount);
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
cerr << "\nshow_my_outputs: Cant decode ringCT! " << endl;
|
||||||
|
}
|
||||||
|
|
||||||
outp.second = rct_amount;
|
outp.second = rct_amount;
|
||||||
money_transfered[output_idx] = rct_amount;
|
money_transfered[output_idx] = rct_amount;
|
||||||
}
|
}
|
||||||
|
@ -1330,28 +1331,20 @@ public:
|
||||||
// we can also test ouputs used in mixins for key images
|
// we can also test ouputs used in mixins for key images
|
||||||
// this can show possible spending. Only possible, because
|
// this can show possible spending. Only possible, because
|
||||||
// without a spend key, we cant know for sure. It might be
|
// without a spend key, we cant know for sure. It might be
|
||||||
// that our output was used by someelse for their mixin.
|
// that our output was used by someone else for their mixins.
|
||||||
// for this we can look in our custom db, for efficiencly
|
// For this we can look in our custom db, for efficiencly
|
||||||
|
|
||||||
unique_ptr<xmreg::MyLMDB> mylmdb;
|
bool show_key_images {false};
|
||||||
|
|
||||||
if (bf::is_directory(lmdb2_path))
|
|
||||||
{
|
|
||||||
mylmdb = make_unique<xmreg::MyLMDB>(lmdb2_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
mstch::array inputs;
|
mstch::array inputs;
|
||||||
|
|
||||||
vector<txin_to_key> input_key_imgs = xmreg::get_key_images(tx);
|
vector<txin_to_key> input_key_imgs = xmreg::get_key_images(tx);
|
||||||
|
|
||||||
|
uint64_t sum_mixin_xmr {0};
|
||||||
|
|
||||||
for (const txin_to_key& in_key: input_key_imgs)
|
for (const txin_to_key& in_key: input_key_imgs)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!mylmdb)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get absolute offsets of mixins
|
// get absolute offsets of mixins
|
||||||
std::vector<uint64_t> absolute_offsets
|
std::vector<uint64_t> absolute_offsets
|
||||||
= cryptonote::relative_output_offsets_to_absolute(
|
= cryptonote::relative_output_offsets_to_absolute(
|
||||||
|
@ -1386,113 +1379,145 @@ public:
|
||||||
// to store our mixins found for the given key image
|
// to store our mixins found for the given key image
|
||||||
vector<map<string, string>> our_mixins_found;
|
vector<map<string, string>> our_mixins_found;
|
||||||
|
|
||||||
// for each found output public key find check if its ours or not
|
// mixin counter
|
||||||
for (const cryptonote::output_data_t& output_data: mixin_outputs)
|
size_t count = 0;
|
||||||
|
|
||||||
|
// for each found output public key check if its ours or not
|
||||||
|
//for (const cryptonote::output_data_t& output_data: mixin_outputs)
|
||||||
|
for (const uint64_t& abs_offset: absolute_offsets)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// get basic information about mixn's output
|
||||||
|
cryptonote::output_data_t output_data = mixin_outputs.at(count);
|
||||||
|
|
||||||
|
tx_out_index tx_out_idx;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// get pair pair<crypto::hash, uint64_t> where first is tx hash
|
||||||
|
// and second is local index of the output i in that tx
|
||||||
|
tx_out_idx = core_storage->get_db()
|
||||||
|
.get_output_tx_and_index(in_key.amount, abs_offset);
|
||||||
|
}
|
||||||
|
catch (const OUTPUT_DNE& e)
|
||||||
|
{
|
||||||
|
|
||||||
|
string out_msg = fmt::format(
|
||||||
|
"Output with amount {:d} and index {:d} does not exist!",
|
||||||
|
in_key.amount, abs_offset
|
||||||
|
);
|
||||||
|
|
||||||
|
cerr << out_msg << endl;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
string out_pub_key_str = pod_to_hex(output_data.pubkey);
|
string out_pub_key_str = pod_to_hex(output_data.pubkey);
|
||||||
|
|
||||||
//cout << "out_pub_key_str: " << out_pub_key_str << endl;
|
//cout << "out_pub_key_str: " << out_pub_key_str << endl;
|
||||||
|
|
||||||
// this will be txs where the outputs come from
|
|
||||||
vector<string> found_tx_hashes;
|
|
||||||
|
|
||||||
|
// get mixin transaction
|
||||||
|
transaction mixin_tx;
|
||||||
|
|
||||||
mylmdb->search(out_pub_key_str,
|
if (!mcore->get_tx(tx_out_idx.first, mixin_tx))
|
||||||
found_tx_hashes,
|
{
|
||||||
"output_public_keys");
|
cerr << "Cant get tx: " << tx_out_idx.first << endl;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
mixins.push_back(mstch::map{
|
mixins.push_back(mstch::map{
|
||||||
{"mixin_pub_key", out_pub_key_str},
|
{"mixin_pub_key" , out_pub_key_str},
|
||||||
make_pair(string("mixin_outputs"), mstch::array{})
|
{"mixin_outputs" , mstch::array{}},
|
||||||
|
{"has_mixin_outputs" , false}
|
||||||
});
|
});
|
||||||
|
|
||||||
mstch::array& mixin_outputs = boost::get<mstch::array>(
|
mstch::array& mixin_outputs = boost::get<mstch::array>(
|
||||||
boost::get<mstch::map>(mixins.back())["mixin_outputs"]
|
boost::get<mstch::map>(mixins.back())["mixin_outputs"]
|
||||||
);
|
);
|
||||||
|
|
||||||
// for each output transaction, check if its ours
|
mstch::node& has_mixin_outputs
|
||||||
// as before
|
= boost::get<mstch::map>(mixins.back())["has_mixin_outputs"];
|
||||||
for (string tx_hash_str: found_tx_hashes)
|
|
||||||
|
|
||||||
|
bool found_something {false};
|
||||||
|
|
||||||
|
|
||||||
|
public_key mixin_tx_pub_key
|
||||||
|
= xmreg::get_tx_pub_key_from_received_outs(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;
|
||||||
|
|
||||||
|
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 "
|
||||||
|
<< "prv_view_key" << prv_view_key << endl;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// <public_key , amount , out idx>
|
||||||
|
vector<tuple<txout_to_key, uint64_t, uint64_t>> output_pub_keys;
|
||||||
|
|
||||||
|
output_pub_keys = xmreg::get_ouputs_tuple(mixin_tx);
|
||||||
|
|
||||||
|
mixin_outputs.push_back(mstch::map{
|
||||||
|
{"mix_tx_hash" , tx_hash_str},
|
||||||
|
{"mix_tx_pub_key" , mixin_tx_pub_key_str},
|
||||||
|
{"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"]
|
||||||
|
);
|
||||||
|
|
||||||
|
mstch::node& has_found_outputs
|
||||||
|
= boost::get<mstch::map>(mixin_outputs.back())["has_found_outputs"];
|
||||||
|
|
||||||
|
// 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)
|
||||||
{
|
{
|
||||||
|
|
||||||
crypto::hash tx_hash;
|
txout_to_key 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);
|
||||||
|
|
||||||
hex_to_pod(tx_hash_str, tx_hash);
|
//cout << " - " << pod_to_hex(txout_k.key) << endl;
|
||||||
|
|
||||||
transaction mixin_tx;
|
// // analyze only those output keys
|
||||||
|
// // that were used in mixins
|
||||||
if (!mcore->get_tx(tx_hash, mixin_tx))
|
// if (txout_k.key != output_data.pubkey)
|
||||||
{
|
|
||||||
cerr << "Cant get tx in blockchain: " << tx_hash << endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public_key tx_pub_key
|
|
||||||
= xmreg::get_tx_pub_key_from_received_outs(mixin_tx);
|
|
||||||
|
|
||||||
// public transaction key is combined with our viewkey
|
|
||||||
// to create, so called, derived key.
|
|
||||||
key_derivation derivation;
|
|
||||||
|
|
||||||
if (!generate_key_derivation(tx_pub_key, prv_view_key, derivation))
|
|
||||||
{
|
|
||||||
cerr << "Cant get derived key for: " << "\n"
|
|
||||||
<< "pub_tx_key: " << tx_pub_key << " and "
|
|
||||||
<< "prv_view_key" << prv_view_key << endl;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// <public_key , amount , out idx>
|
|
||||||
vector<tuple<txout_to_key, uint64_t, uint64_t>> output_pub_keys;
|
|
||||||
|
|
||||||
output_pub_keys = xmreg::get_ouputs_tuple(mixin_tx);
|
|
||||||
|
|
||||||
mixin_outputs.push_back(mstch::map{
|
|
||||||
{"mix_tx_hash" , tx_hash_str},
|
|
||||||
make_pair(string("found_outputs"), mstch::array{})
|
|
||||||
});
|
|
||||||
|
|
||||||
mstch::array& found_outputs = boost::get<mstch::array>(
|
|
||||||
boost::get<mstch::map>(mixin_outputs.back())["found_outputs"]
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
uint64_t amount = std::get<1>(mix_out);
|
|
||||||
uint64_t output_idx_in_tx = std::get<2>(mix_out);
|
|
||||||
|
|
||||||
//@todo fix this for loop
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// if (mix_out.first.key != output_data.pubkey)
|
|
||||||
// {
|
// {
|
||||||
// continue;
|
// continue;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 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 tx_pubkey_generated;
|
public_key tx_pubkey_generated;
|
||||||
|
|
||||||
derive_public_key(derivation,
|
derive_public_key(derivation,
|
||||||
output_idx_in_tx,
|
output_idx_in_tx,
|
||||||
address.m_spend_public_key,
|
address.m_spend_public_key,
|
||||||
tx_pubkey_generated);
|
tx_pubkey_generated);
|
||||||
|
|
||||||
// check if generated public key matches the current output's key
|
// check if generated public key matches the current output's key
|
||||||
bool mine_output = (txout_k.key == tx_pubkey_generated);
|
bool mine_output = (txout_k.key == tx_pubkey_generated);
|
||||||
|
|
||||||
|
|
||||||
if (mine_output && mixin_tx.version == 2)
|
if (mine_output && mixin_tx.version == 2)
|
||||||
|
{
|
||||||
|
// cointbase txs have amounts in plain sight.
|
||||||
|
// so use amount from ringct, only for non-coinbase txs
|
||||||
|
if (!is_coinbase(mixin_tx))
|
||||||
{
|
{
|
||||||
// initialize with regular amount
|
// initialize with regular amount
|
||||||
uint64_t rct_amount = amount;
|
uint64_t rct_amount = amount;
|
||||||
|
@ -1500,10 +1525,10 @@ public:
|
||||||
bool r;
|
bool r;
|
||||||
|
|
||||||
r = decode_ringct(mixin_tx.rct_signatures,
|
r = decode_ringct(mixin_tx.rct_signatures,
|
||||||
txout_k.key,
|
mixin_tx_pub_key,
|
||||||
prv_view_key,
|
prv_view_key,
|
||||||
output_idx_in_tx,
|
output_idx_in_tx,
|
||||||
mixin_tx.rct_signatures.ecdhInfo[output_idx].mask,
|
mixin_tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask,
|
||||||
rct_amount);
|
rct_amount);
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
|
@ -1511,50 +1536,86 @@ public:
|
||||||
cerr << "show_my_outputs: key images: Cant decode ringCT!" << endl;
|
cerr << "show_my_outputs: key images: Cant decode ringCT!" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cointbase txs have amounts in plain sight.
|
amount = rct_amount;
|
||||||
// so use amount from ringct, only for non-coinbase txs
|
|
||||||
if (!is_coinbase(mixin_tx))
|
} // if (mine_output && mixin_tx.version == 2)
|
||||||
{
|
}
|
||||||
amount = rct_amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// save our mixnin's public keys
|
// save our mixnin's public keys
|
||||||
found_outputs.push_back(mstch::map {
|
found_outputs.push_back(mstch::map {
|
||||||
{"my_public_key" , pod_to_hex(txout_k.key)},
|
{"my_public_key" , pod_to_hex(txout_k.key)},
|
||||||
{"tx_hash" , tx_hash_str},
|
{"tx_hash" , tx_hash_str},
|
||||||
{"mine_output" , mine_output},
|
{"mine_output" , mine_output},
|
||||||
{"out_idx" , to_string(output_idx_in_tx)},
|
{"out_idx" , to_string(output_idx_in_tx)},
|
||||||
{"formed_output_pk", out_pub_key_str},
|
{"formed_output_pk", out_pub_key_str},
|
||||||
{"amount" , xmreg::xmr_amount_to_str(amount)},
|
{"out_in_match" , (amount == in_key.amount)},
|
||||||
});
|
{"amount" , xmreg::xmr_amount_to_str(amount)}
|
||||||
|
});
|
||||||
if (mine_output)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
if (mine_output)
|
||||||
|
{
|
||||||
// cout << " - " << pod_to_hex(txout_k.key)
|
// cout << " - " << pod_to_hex(txout_k.key)
|
||||||
// <<": " << mine_output << " amount: "
|
// <<": " << mine_output << " amount: "
|
||||||
// << xmreg::xmr_amount_to_str(amount)
|
// << xmreg::xmr_amount_to_str(amount)
|
||||||
// << endl;
|
// << endl;
|
||||||
|
|
||||||
|
found_something = true;
|
||||||
|
show_key_images = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// for regular txs, just concentrated on outputs
|
||||||
|
// which have same amount as the key image.
|
||||||
|
// for ringct its not possible to know for sure amount
|
||||||
|
// in key image without spend key, so we just use all
|
||||||
|
if (mixin_tx.version < 2 && amount == in_key.amount)
|
||||||
|
{
|
||||||
|
sum_mixin_xmr += amount;
|
||||||
|
}
|
||||||
|
else if (mixin_tx.version == 2) // ringct
|
||||||
|
{
|
||||||
|
sum_mixin_xmr += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // for (const pair<txout_to_key, uint64_t>& mix_out: txd.output_pub_keys)
|
}
|
||||||
|
|
||||||
} // for (string tx_hash_str: found_tx_hashes)
|
} // for (const pair<txout_to_key, uint64_t>& mix_out: txd.output_pub_keys)
|
||||||
|
|
||||||
|
has_found_outputs = !found_outputs.empty();
|
||||||
|
|
||||||
|
has_mixin_outputs = found_something;
|
||||||
|
|
||||||
} // for (const cryptonote::output_data_t& output_data: mixin_outputs)
|
} // for (const cryptonote::output_data_t& output_data: mixin_outputs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // for (const txin_to_key& in_key: input_key_imgs)
|
} // for (const txin_to_key& in_key: input_key_imgs)
|
||||||
|
|
||||||
|
|
||||||
context.emplace("outputs", outputs);
|
context.emplace("outputs", outputs);
|
||||||
|
|
||||||
context["found_our_outputs"] = (sum_xmr > 0);
|
context["found_our_outputs"] = (sum_xmr > 0);
|
||||||
context["sum_xmr"] = xmreg::xmr_amount_to_str(sum_xmr);
|
context["sum_xmr"] = xmreg::xmr_amount_to_str(sum_xmr);
|
||||||
|
|
||||||
context.emplace("inputs", inputs);
|
context.emplace("inputs", inputs);
|
||||||
context["show_inputs"] = false;
|
|
||||||
|
context["show_inputs"] = show_key_images;
|
||||||
|
context["inputs_no"] = inputs.size();
|
||||||
|
context["sum_mixin_xmr"] = xmreg::xmr_amount_to_str(sum_mixin_xmr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t possible_spending {0};
|
||||||
|
|
||||||
|
if (sum_mixin_xmr > (sum_xmr + txd.fee))
|
||||||
|
{
|
||||||
|
// (outcoming - incoming) - fee
|
||||||
|
possible_spending = (sum_mixin_xmr - sum_xmr) - txd.fee;
|
||||||
|
}
|
||||||
|
context["possible_spending"] = xmreg::xmr_amount_to_str(
|
||||||
|
possible_spending, "{:0.12f}", false);
|
||||||
|
|
||||||
|
|
||||||
// read my_outputs.html
|
// read my_outputs.html
|
||||||
string my_outputs_html = xmreg::read(TMPL_MY_OUTPUTS);
|
string my_outputs_html = xmreg::read(TMPL_MY_OUTPUTS);
|
||||||
|
@ -2678,30 +2739,35 @@ public:
|
||||||
// seems we found our output. so now lets decode its amount
|
// seems we found our output. so now lets decode its amount
|
||||||
// using ringct
|
// using ringct
|
||||||
|
|
||||||
bool r;
|
if (output_source_tx.version == 2
|
||||||
|
&& !is_coinbase(output_source_tx))
|
||||||
r = decode_ringct(output_source_tx.rct_signatures,
|
|
||||||
tx_pub_key,
|
|
||||||
prv_view_key,
|
|
||||||
output_idx_in_tx,
|
|
||||||
output_source_tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask,
|
|
||||||
rct_amount);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
{
|
{
|
||||||
string error_msg = fmt::format(
|
bool r;
|
||||||
"Cant decode ringCT for "
|
|
||||||
"pub_tx_key: {:s} "
|
|
||||||
"using prv_view_key: {:s}",
|
|
||||||
tx_pub_key, prv_view_key);
|
|
||||||
|
|
||||||
context["has_error"] = true;
|
r = decode_ringct(output_source_tx.rct_signatures,
|
||||||
context["error_msg"] = error_msg;
|
tx_pub_key,
|
||||||
|
prv_view_key,
|
||||||
|
output_idx_in_tx,
|
||||||
|
output_source_tx.rct_signatures.ecdhInfo[output_idx_in_tx].mask,
|
||||||
|
rct_amount);
|
||||||
|
|
||||||
return mstch::render(full_page, context);
|
if (!r)
|
||||||
}
|
{
|
||||||
|
string error_msg = fmt::format(
|
||||||
|
"Cant decode ringCT for "
|
||||||
|
"pub_tx_key: {:s} "
|
||||||
|
"using prv_view_key: {:s}",
|
||||||
|
tx_pub_key, prv_view_key);
|
||||||
|
|
||||||
xmr_amount = rct_amount;
|
context["has_error"] = true;
|
||||||
|
context["error_msg"] = error_msg;
|
||||||
|
|
||||||
|
return mstch::render(full_page, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmr_amount = rct_amount;
|
||||||
|
|
||||||
|
} // if (output_source_tx.version == 2 && !is_coinbase(output_source_tx))
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -111,4 +111,31 @@ form {
|
||||||
|
|
||||||
[type=radio]:checked ~ label ~ .content {
|
[type=radio]:checked ~ label ~ .content {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input#toggle-1[type=checkbox] {
|
||||||
|
position: absolute;
|
||||||
|
top: -9999px;
|
||||||
|
left: -9999px;
|
||||||
|
|
||||||
|
}
|
||||||
|
label#show-decoded-inputs {
|
||||||
|
/*-webkit-appearance: push-button;*/
|
||||||
|
/*-moz-appearance: button;*/
|
||||||
|
display: inline-block;
|
||||||
|
/*margin: 60px 0 10px 0;*/
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: black;;
|
||||||
|
color: white;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#decoded-inputs{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toggled State */
|
||||||
|
input#toggle-1[type=checkbox]:checked ~ div#decoded-inputs {
|
||||||
|
display: block;
|
||||||
}
|
}
|
|
@ -40,7 +40,7 @@
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<table class="center" >
|
<table class="center" >
|
||||||
<tr>
|
<tr>
|
||||||
<td>Stealth address</td>
|
<td>output public key</td>
|
||||||
<td>amount</td>
|
<td>amount</td>
|
||||||
<td>output match?</td>
|
<td>output match?</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h3>
|
<h3>
|
||||||
Sum XMR from matched outputs:
|
Sum XMR from matched outputs (i.e., incoming XMR):
|
||||||
{{#found_our_outputs}}
|
{{#found_our_outputs}}
|
||||||
{{sum_xmr}}
|
{{sum_xmr}}
|
||||||
{{/found_our_outputs}}
|
{{/found_our_outputs}}
|
||||||
|
@ -75,43 +75,78 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#show_inputs}}
|
{{#show_inputs}}
|
||||||
|
<br/>
|
||||||
|
<label id="show-decoded-inputs" for="toggle-1">Show decoded inputs</label>
|
||||||
|
<input type="checkbox" id="toggle-1">
|
||||||
|
|
||||||
<hr>
|
<div id="decoded-inputs">
|
||||||
|
<h3>Inputs ({{inputs_no}})</h3>
|
||||||
<h3>Inputs</h3>
|
|
||||||
<div class="center">
|
<div class="center">
|
||||||
{{#inputs}}
|
{{#inputs}}
|
||||||
<h4>Key image: {{key_image}}, amount {{key_image_amount}}</h4>
|
<h4>Key image: {{key_image}}, amount {{key_image_amount}}</h4>
|
||||||
{{#mixins}}
|
{{#mixins}}
|
||||||
<h5>Mixin of pub key: {{mixin_pub_key}}</h5>
|
{{#has_mixin_outputs}}
|
||||||
{{#mixin_outputs}}
|
{{#mixin_outputs}}
|
||||||
<h5>
|
<div class="center">
|
||||||
uses outputs from tx:
|
<table class="center">
|
||||||
<a href="/tx/{{mix_tx_hash}}">{{mix_tx_hash}}</a>
|
<tr>
|
||||||
</h5>
|
<td style="text-align: center;">
|
||||||
{{#found_outputs}}
|
Mixin {{mixin_pub_key}} might use your outputs
|
||||||
|
<br/>
|
||||||
<h6 style="font-family: 'Lucida Console', Monaco, monospace; font-size: 12px; font-weight: normal;">
|
from tx of public key: <a href="/tx/{{mix_tx_hash}}">{{mix_tx_pub_key}}</a>
|
||||||
Output public key: {{my_public_key}},
|
</td>
|
||||||
amount: {{amount}},
|
</tr>
|
||||||
is ours:
|
{{#has_found_outputs}}
|
||||||
{{#mine_output}}
|
<tr><td>
|
||||||
<span style="color: #008009;font-weight: bold">{{mine_output}}</span>
|
<div class="center">
|
||||||
{{/mine_output}}
|
<table class="center">
|
||||||
{{^mine_output}}
|
<tr>
|
||||||
{{mine_output}}
|
<td>output public key</td>
|
||||||
{{/mine_output}}
|
<td>amount</td>
|
||||||
</h6>
|
<td>output match?</td>
|
||||||
|
</tr>
|
||||||
{{/found_outputs}}
|
{{#found_outputs}}
|
||||||
{{/mixin_outputs}}
|
<tr>
|
||||||
|
<td>{{my_public_key}}</td>
|
||||||
|
<td>{{amount}}</td>
|
||||||
|
<td>
|
||||||
|
{{#mine_output}}
|
||||||
|
<span style="color: #008009;font-weight: bold">{{mine_output}}</span>{{#out_in_match}}*{{/out_in_match}}
|
||||||
|
{{/mine_output}}
|
||||||
|
{{^mine_output}}
|
||||||
|
{{mine_output}}
|
||||||
|
{{/mine_output}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/found_outputs}}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</td></tr>
|
||||||
|
{{/has_found_outputs}}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{/mixin_outputs}}
|
||||||
|
{{/has_mixin_outputs}}
|
||||||
{{/mixins}}
|
{{/mixins}}
|
||||||
{{/inputs}}
|
{{/inputs}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<h3>
|
||||||
|
Sum XMR from matched mixin's outputs: {{sum_mixin_xmr}}
|
||||||
|
<br/>
|
||||||
|
<span style="font-size: 16px"> Possible spending is:
|
||||||
|
{{possible_spending}} (tx fee included)
|
||||||
|
</span>
|
||||||
|
<br/>
|
||||||
|
<span style="font-size: 14px">Note: without private spendkey,
|
||||||
|
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>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{/show_inputs}}
|
{{/show_inputs}}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<br/>
|
13
src/tools.h
13
src/tools.h
|
@ -245,14 +245,23 @@ parse(const std::string& str, string format="%Y-%m-%d %H:%M:%S");
|
||||||
|
|
||||||
static
|
static
|
||||||
string
|
string
|
||||||
xmr_amount_to_str(const uint64_t& xmr_amount, string _format="{:0.12f}")
|
xmr_amount_to_str(const uint64_t& xmr_amount,
|
||||||
|
string _format="{:0.12f}",
|
||||||
|
bool zero_to_question_mark=true)
|
||||||
{
|
{
|
||||||
string amount_str = "?";
|
string amount_str = "?";
|
||||||
|
|
||||||
if (xmr_amount > 0)
|
if (!zero_to_question_mark)
|
||||||
{
|
{
|
||||||
amount_str = fmt::format(_format, XMR_AMOUNT(xmr_amount));
|
amount_str = fmt::format(_format, XMR_AMOUNT(xmr_amount));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (xmr_amount > 0 && zero_to_question_mark == true)
|
||||||
|
{
|
||||||
|
amount_str = fmt::format(_format, XMR_AMOUNT(xmr_amount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return amount_str;
|
return amount_str;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue