forked from lthn/blockchain
ca: wallet refactoring to support confidential assets (WIP)
This commit is contained in:
parent
4ae6616a2b
commit
f9b54f305a
6 changed files with 79 additions and 39 deletions
|
|
@ -218,6 +218,8 @@ namespace currency
|
|||
crypto::scalar_t amount_blinding_mask = 0;
|
||||
crypto::scalar_t asset_id_blinding_mask = 0;
|
||||
crypto::public_key asset_id = currency::native_coin_asset_id; // use point_t instead as this is for internal use only?
|
||||
|
||||
bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace currency
|
|||
res += o.amount;
|
||||
}
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, o)
|
||||
//@#@
|
||||
//@#@# TODO obtain info about public burn of native coins in ZC outputs
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace currency
|
|||
crypto::public_key asset_id = currency::native_coin_asset_id; //asset id (not blinded, not premultiplied by 1/8) TODO @#@# consider changing to crypto::point_t
|
||||
|
||||
bool is_multisig() const { return ms_sigs_count > 0; }
|
||||
bool is_zarcanum() const { return !real_out_amount_blinding_mask.is_zero(); }
|
||||
bool is_zc() const { return !real_out_amount_blinding_mask.is_zero(); }
|
||||
bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
|
|
|
|||
|
|
@ -499,7 +499,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
uint64_t max_out_unlock_time = 0;
|
||||
|
||||
std::vector<wallet_out_info> outs;
|
||||
uint64_t tx_money_got_in_outs = 0; // TODO: @#@# correctly calculate tx_money_got_in_outs for post-HF4
|
||||
uint64_t sum_of_native_outs = 0; // TODO: @#@# correctly calculate tx_money_got_in_outs for post-HF4
|
||||
crypto::public_key tx_pub_key = null_pkey;
|
||||
bool r = parse_and_validate_tx_extra(tx, tx_pub_key);
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::tx_extra_parse_error, tx);
|
||||
|
|
@ -507,10 +507,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
//check for transaction income
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
std::list<htlc_info> htlc_info_list;
|
||||
r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs, derivation, htlc_info_list);
|
||||
r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, sum_of_native_outs, derivation, htlc_info_list);
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
|
||||
|
||||
if(!outs.empty() /*&& tx_money_got_in_outs*/)
|
||||
if (!outs.empty())
|
||||
{
|
||||
//good news - got money! take care about it
|
||||
//usually we have only one transfer for user in transaction
|
||||
|
|
@ -545,16 +545,17 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
{
|
||||
const wallet_out_info& out = outs[i_in_outs];
|
||||
size_t o = out.index;
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(o < tx.vout.size(), "wrong out in transaction: internal index=" << o << ", total_outs=" << tx.vout.size());
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(o < tx.vout.size(), "wrong out in transaction: internal index: " << o << ", tx.vout.size(): " << tx.vout.size());
|
||||
{
|
||||
const currency::tx_out_v& out_v = tx.vout[o];
|
||||
bool out_type_zc = out_is_zc(out_v);
|
||||
bool out_type_to_key = out_is_to_key(out_v);
|
||||
bool out_type_htlc = out_is_to_htlc(out_v);
|
||||
bool out_type_multisig = out_is_multisig(out_v);
|
||||
|
||||
bool out_type_zc = out_is_zc(out_v);
|
||||
bool out_type_to_key = out_is_to_key(out_v);
|
||||
if (out_type_zc || out_type_to_key || out_is_to_htlc(out_v))
|
||||
if (out_type_zc || out_type_to_key || out_type_htlc)
|
||||
{
|
||||
crypto::public_key out_key = out_get_pub_key(out_v, htlc_info_list);
|
||||
//const currency::txout_to_key& otk = boost::get<currency::txout_to_key>(out.target);
|
||||
crypto::public_key out_key = out_get_pub_key(out_v, htlc_info_list); // htlc_info_list contains information about which one, redeem or refund key is ours for an htlc output
|
||||
|
||||
// obtain key image for this output
|
||||
crypto::key_image ki = currency::null_ki;
|
||||
|
|
@ -600,8 +601,11 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0);
|
||||
if (m_wcallback)
|
||||
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tx_money_got_in_outs >= outs[i_in_outs].amount, "tx_money_got_in_outs: " << tx_money_got_in_outs << ", out.amount:" << outs[i_in_outs].amount);
|
||||
tx_money_got_in_outs -= outs[i_in_outs].amount;
|
||||
if (out.is_native_coin())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount);
|
||||
sum_of_native_outs -= out.amount;
|
||||
}
|
||||
continue; // skip the output
|
||||
}
|
||||
}
|
||||
|
|
@ -611,11 +615,15 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
{
|
||||
std::stringstream ss;
|
||||
ss << "output #" << o << " from tx " << get_transaction_hash(tx) << " with amount " << print_money_brief(outs[i_in_outs].amount)
|
||||
<< " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)out_get_mixin_attr(out_v) << ". Output IGNORED.";
|
||||
<< " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)out_get_mixin_attr(out_v) << ". Output is IGNORED.";
|
||||
WLT_LOG_RED(ss.str(), LOG_LEVEL_0);
|
||||
if (m_wcallback)
|
||||
m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str());
|
||||
tx_money_got_in_outs -= out.amount;
|
||||
if (out.is_native_coin())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount);
|
||||
sum_of_native_outs -= out.amount;
|
||||
}
|
||||
continue; // skip the output
|
||||
}
|
||||
|
||||
|
|
@ -643,7 +651,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
if (ptc.coin_base_tx)
|
||||
{
|
||||
//last out in coinbase tx supposed to be change from coinstake
|
||||
if (!(o == tx.vout.size() - 1 && !ptc.is_derived_from_coinbase))
|
||||
if (!(o == tx.vout.size() - 1 && !ptc.is_derived_from_coinbase)) // TODO: @#@# reconsider this condition
|
||||
{
|
||||
td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER;
|
||||
}
|
||||
|
|
@ -655,7 +663,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
}
|
||||
|
||||
size_t transfer_index = m_transfers.size() - 1;
|
||||
if (out_is_to_htlc(out_v))
|
||||
if (out_type_htlc)
|
||||
{
|
||||
const currency::txout_htlc& hltc = out_get_htlc(out_v);
|
||||
//mark this as spent
|
||||
|
|
@ -702,8 +710,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
if (is_watch_only() && is_auditable())
|
||||
{
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(td.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, "td.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED validation failed");
|
||||
auto amount_gindex_pair = std::make_pair(td.m_amount, td.m_global_output_index);
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(m_amount_gindex_to_transfer_id.count(amount_gindex_pair) == 0, "update m_amount_gindex_to_transfer_id: amount " << td.m_amount << ", gindex " << td.m_global_output_index << " already exists");
|
||||
auto amount_gindex_pair = std::make_pair(td.amount_for_global_output_index(), td.m_global_output_index);
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(m_amount_gindex_to_transfer_id.count(amount_gindex_pair) == 0, "update m_amount_gindex_to_transfer_id: amount_for_global_output_index: " << td.amount_for_global_output_index() << ", gindex: " << td.m_global_output_index << " already exists");
|
||||
m_amount_gindex_to_transfer_id[amount_gindex_pair] = transfer_index;
|
||||
}
|
||||
|
||||
|
|
@ -712,14 +720,22 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
|
||||
if (out_type_to_key || out_type_zc)
|
||||
{
|
||||
WLT_LOG_L0("Received money, transfer #" << transfer_index << ", amount: " << print_money_brief(td.amount()) << (out_type_zc ? " (hidden)" : "") << ", with tx: " << get_transaction_hash(tx) << ", at height " << height);
|
||||
if (td.is_native_coin())
|
||||
{
|
||||
WLT_LOG_L0("Received native coins, transfer #" << transfer_index << ", amount: " << print_money_brief(td.amount()) << (out_type_zc ? " (hidden)" : "") << ", with tx: " << get_transaction_hash(tx) << ", at height " << height);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO @#@# output asset's ticker/name
|
||||
WLT_LOG_L0("Received asset " << print16(td.get_asset_id()) << ", transfer #" << transfer_index << ", amount: " << print_money_brief(td.amount()) << (out_type_zc ? " (hidden)" : "") << ", with tx: " << get_transaction_hash(tx) << ", at height " << height);
|
||||
}
|
||||
}
|
||||
else if (out_is_to_htlc(out_v))
|
||||
else if (out_type_htlc)
|
||||
{
|
||||
WLT_LOG_L0("Detected HTLC[" << (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? "REDEEM" : "REFUND") << "], transfer #" << transfer_index << ", amount: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height);
|
||||
}
|
||||
}
|
||||
else if (out_is_multisig(out_v))
|
||||
else if (out_type_multisig)
|
||||
{
|
||||
crypto::hash multisig_id = currency::get_multisig_out_id(tx, o);
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(m_multisig_transfers.count(multisig_id) == 0, "multisig_id = " << multisig_id << " already in multisig container");
|
||||
|
|
@ -729,15 +745,22 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
tdb.m_amount = outs[i_in_outs].amount;
|
||||
WLT_LOG_L0("Received multisig, multisig out id: " << multisig_id << ", amount: " << tdb.amount() << ", with tx: " << get_transaction_hash(tx));
|
||||
}
|
||||
else
|
||||
{
|
||||
WLT_LOG_YELLOW("Unexpected output type: " << out_v.type().name() << ", out index: " << o << " in tx " << get_transaction_hash(tx), LOG_LEVEL_0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string payment_id;
|
||||
if (tx_money_got_in_outs && get_payment_id_from_tx(tx.attachment, payment_id))
|
||||
if (sum_of_native_outs != 0 && get_payment_id_from_tx(tx.attachment, payment_id))
|
||||
{
|
||||
uint64_t received = (ptc.tx_money_spent_in_ins < tx_money_got_in_outs) ? tx_money_got_in_outs - ptc.tx_money_spent_in_ins : 0;
|
||||
// TODO @#@# this code takes care only of native coins
|
||||
// we need to add assets support
|
||||
|
||||
uint64_t received = (ptc.sum_of_own_native_inputs < sum_of_native_outs) ? sum_of_native_outs - ptc.sum_of_own_native_inputs : 0;
|
||||
if (0 < received && payment_id.size())
|
||||
{
|
||||
payment_details payment;
|
||||
|
|
@ -750,7 +773,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
}
|
||||
}
|
||||
|
||||
if (ptc.tx_money_spent_in_ins)
|
||||
if (ptc.sum_of_own_native_inputs)
|
||||
{
|
||||
//check if there are asset_registration that belong to this wallet
|
||||
asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
|
||||
|
|
@ -798,25 +821,27 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
}
|
||||
}
|
||||
|
||||
if (ptc.tx_money_spent_in_ins)
|
||||
if (ptc.sum_of_own_native_inputs)
|
||||
{//this actually is transfer transaction, notify about spend
|
||||
if (ptc.tx_money_spent_in_ins > tx_money_got_in_outs)
|
||||
if (ptc.sum_of_own_native_inputs > sum_of_native_outs)
|
||||
{//usual transfer
|
||||
handle_money_spent2(b, tx, ptc.tx_money_spent_in_ins - (tx_money_got_in_outs+get_tx_fee(tx)), ptc.mtd, recipients, remote_aliases);
|
||||
handle_money_spent2(b, tx, ptc.sum_of_own_native_inputs - (sum_of_native_outs + get_tx_fee(tx)), ptc.mtd, recipients, remote_aliases);
|
||||
}
|
||||
else
|
||||
{//strange transfer, seems that in one transaction have transfers from different wallets.
|
||||
if (!is_coinbase(tx))
|
||||
{
|
||||
WLT_LOG_RED("Unusual transaction " << currency::get_transaction_hash(tx) << ", tx_money_spent_in_ins: " << ptc.tx_money_spent_in_ins << ", tx_money_got_in_outs: " << tx_money_got_in_outs, LOG_LEVEL_0);
|
||||
WLT_LOG_RED("Unusual transaction " << currency::get_transaction_hash(tx) << ", sum_of_native_inputs: " << ptc.sum_of_own_native_inputs << ", sum_of_native_outs: " << sum_of_native_outs, LOG_LEVEL_0);
|
||||
}
|
||||
handle_money_received2(b, tx, (tx_money_got_in_outs - (ptc.tx_money_spent_in_ins - get_tx_fee(tx))), ptc.mtd);
|
||||
handle_money_received2(b, tx, (sum_of_native_outs - (ptc.sum_of_own_native_inputs - get_tx_fee(tx))), ptc.mtd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tx_money_got_in_outs)
|
||||
handle_money_received2(b, tx, tx_money_got_in_outs, ptc.mtd);
|
||||
if (sum_of_native_outs != 0)
|
||||
{
|
||||
handle_money_received2(b, tx, sum_of_native_outs, ptc.mtd);
|
||||
}
|
||||
else if (currency::is_derivation_used_to_encrypt(tx, derivation))
|
||||
{
|
||||
//transaction doesn't transfer actually money, bud bring some information
|
||||
|
|
@ -5777,7 +5802,7 @@ void wallet2::print_source_entry(std::stringstream& output, const currency::tx_s
|
|||
for(auto& el : src.outputs)
|
||||
ss << el.out_reference << " ";
|
||||
|
||||
output << "amount: " << print_money_brief(src.amount) << (src.is_zarcanum() ? " (hidden)" : "")
|
||||
output << "amount: " << print_money_brief(src.amount) << (src.is_zc() ? " (hidden)" : "")
|
||||
<< ", real_output: " << src.real_output
|
||||
<< ", real_output_in_tx_index: " << src.real_output_in_tx_index
|
||||
<< ", indexes: " << ss.str();
|
||||
|
|
|
|||
|
|
@ -364,7 +364,8 @@ namespace tools
|
|||
boost::shared_ptr<ZC_out_info> m_zc_info_ptr;
|
||||
|
||||
uint64_t amount() const { return m_amount; }
|
||||
|
||||
uint64_t amount_for_global_output_index() const { return is_zc() ? 0 : m_amount; } // amount value for global outputs index, it's zero for outputs with hidden amounts
|
||||
|
||||
// @#@ will throw if type is not tx_out_bare, TODO: change according to new model,
|
||||
// need to replace all get_tx_out_bare_from_out_v() to proper code
|
||||
//const currency::tx_out_bare& output() const { return currency::get_tx_out_bare_from_out_v(m_ptx_wallet_info->m_tx.vout[m_internal_output_index]); }
|
||||
|
|
@ -377,6 +378,7 @@ namespace tools
|
|||
bool is_reserved_for_escrow() const { return ( (m_flags & WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) != 0 ); }
|
||||
bool is_zc() const { return m_zc_info_ptr.get(); }
|
||||
const crypto::public_key& get_asset_id() const { if (m_zc_info_ptr.get()) { return m_zc_info_ptr->asset_id; } else { return currency::native_coin_asset_id; } }
|
||||
bool is_native_coin() const { return m_zc_info_ptr.get() ? (m_zc_info_ptr->asset_id == currency::native_coin_asset_id) : true; }
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_CUSTOM(m_ptx_wallet_info, const transaction_wallet_info&, tools::wallet2::transform_ptr_to_value, tools::wallet2::transform_value_to_ptr)
|
||||
|
|
@ -504,7 +506,7 @@ namespace tools
|
|||
|
||||
struct process_transaction_context
|
||||
{
|
||||
uint64_t tx_money_spent_in_ins = 0;
|
||||
uint64_t sum_of_own_native_inputs = 0; // old-fashioned bare inputs or ZC inputs referring to native coin asset_id
|
||||
// check all outputs for spending (compare key images)
|
||||
money_transfer2_details mtd;
|
||||
bool is_pos_coinbase = false;
|
||||
|
|
@ -1330,7 +1332,8 @@ namespace tools
|
|||
if (tr_index != UINT64_MAX)
|
||||
{
|
||||
transfer_details& td = m_transfers[tr_index];
|
||||
ptc.tx_money_spent_in_ins += td.amount();
|
||||
if (td.is_native_coin())
|
||||
ptc.sum_of_own_native_inputs += td.m_amount;
|
||||
uint32_t flags_before = td.m_flags;
|
||||
td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT;
|
||||
td.m_spent_height = ptc.height;
|
||||
|
|
@ -1338,8 +1341,18 @@ namespace tools
|
|||
ptc.is_derived_from_coinbase = true;
|
||||
else
|
||||
ptc.is_derived_from_coinbase = false;
|
||||
WLT_LOG_L0("Spent key out, transfer #" << tr_index << ", amount: " << currency::print_money_brief(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << ptc.height <<
|
||||
"; flags: " << flags_before << " -> " << td.m_flags);
|
||||
|
||||
if (td.is_native_coin())
|
||||
{
|
||||
WLT_LOG_L0("Spent native coins, transfer #" << tr_index << ", amount: " << currency::print_money_brief(td.amount()) << (td.is_zc() ? " (hidden), with tx: " : ", with tx: ") << get_transaction_hash(tx) << ", at height " << ptc.height <<
|
||||
"; flags: " << flags_before << " -> " << td.m_flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLT_LOG_L0("Spent asset " << print16(td.get_asset_id()) << " , transfer #" << tr_index << ", amount: " << currency::print_money_brief(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << ptc.height <<
|
||||
"; flags: " << flags_before << " -> " << td.m_flags);
|
||||
}
|
||||
|
||||
ptc.mtd.spent_indices.push_back(ptc.i);
|
||||
remove_transfer_from_expiration_list(tr_index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ namespace tools
|
|||
const currency::tx_source_entry& src = m_sources[i];
|
||||
ss << "\n " << i << ": ";
|
||||
ss << " amount: " << std::setw(21) << currency::print_money(src.amount);
|
||||
ss << (src.is_zarcanum() ? " ZC " : " old ");
|
||||
ss << (src.is_zc() ? " ZC " : " old ");
|
||||
ss << " asset_id: " << src.asset_id;
|
||||
for (size_t j = 0; j < src.outputs.size(); ++j)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue