forked from lthn/blockchain
wallet: handling auditable coins (WIP)
This commit is contained in:
parent
aaa5fcbfa9
commit
36326e581f
3 changed files with 74 additions and 20 deletions
|
|
@ -220,7 +220,7 @@
|
|||
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
|
||||
|
||||
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+66)
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+67)
|
||||
|
||||
|
||||
#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31)
|
||||
|
|
|
|||
|
|
@ -265,8 +265,35 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
{
|
||||
const currency::txin_to_key& intk = boost::get<currency::txin_to_key>(in);
|
||||
|
||||
// TODO: check for references to our UTXO (auditability)
|
||||
// intk.key_offsets;
|
||||
if (is_auditable())
|
||||
{
|
||||
// auditable wallet
|
||||
// try to find a reference among own UTXOs
|
||||
std::vector<txout_v> abs_key_offsets = relative_output_offsets_to_absolute(intk.key_offsets);
|
||||
for(auto v : abs_key_offsets)
|
||||
{
|
||||
if (v.type() != typeid(uint64_t))
|
||||
continue;
|
||||
uint64_t gindex = boost::get<uint64_t>(v);
|
||||
auto it = m_amount_gindex_to_transfer_id.find(std::make_pair(intk.amount, gindex));
|
||||
if (it != m_amount_gindex_to_transfer_id.end())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "invalid tid: " << it->second << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex);
|
||||
auto& td = m_transfers[it->second];
|
||||
if (intk.key_offsets.size() != 1)
|
||||
{
|
||||
// own output was used in non-direct transaction
|
||||
// the core should not allow this to happen, the only way it may happen - mixing in own output that was sent without mix_attr == 1
|
||||
// log strange situation
|
||||
LOG_PRINT_YELLOW("own transfer tid=" << it->second << " tx=" << td.tx_hash() << " mix_attr=" << td.mix_attr() << ", is referenced by a transaction with mixins, ref from input with amount: " << intk.amount << ", gindex: " << gindex , LOG_LEVEL_0);
|
||||
continue;
|
||||
}
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!td.is_spent(), "transfer is spent, tid: " << it->second << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex);
|
||||
// own output is spent, handle it
|
||||
///
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto it = m_key_images.find(intk.k_image);
|
||||
if (it != m_key_images.end())
|
||||
|
|
@ -347,21 +374,21 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
if (m_watch_only)
|
||||
{
|
||||
if (!is_auditable())
|
||||
{
|
||||
// don't have spend secret key, so we unable to calculate key image for an output
|
||||
// look it up in special container instead
|
||||
auto it = m_pending_key_images.find(otk.key);
|
||||
if (it != m_pending_key_images.end())
|
||||
{
|
||||
ki = it->second;
|
||||
WLT_LOG_L1("pending key image " << ki << " was found by out pub key " << otk.key);
|
||||
// don't have spend secret key, so we unable to calculate key image for an output
|
||||
// look it up in special container instead
|
||||
auto it = m_pending_key_images.find(otk.key);
|
||||
if (it != m_pending_key_images.end())
|
||||
{
|
||||
ki = it->second;
|
||||
WLT_LOG_L1("pending key image " << ki << " was found by out pub key " << otk.key);
|
||||
}
|
||||
else
|
||||
{
|
||||
ki = currency::null_ki;
|
||||
WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ki = currency::null_ki;
|
||||
WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -373,6 +400,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
|
||||
if (ki != currency::null_ki)
|
||||
{
|
||||
// make sure calculated key image for this own output has not been seen before
|
||||
auto it = m_key_images.find(ki);
|
||||
if (it != m_key_images.end())
|
||||
{
|
||||
|
|
@ -407,6 +435,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
if (td.m_key_image != currency::null_ki)
|
||||
m_key_images[td.m_key_image] = transfer_index;
|
||||
add_transfer_to_transfers_cache(tx.vout[o].amount, transfer_index);
|
||||
uint64_t amount = tx.vout[o].amount;
|
||||
|
||||
r = m_amount_gindex_to_transfer_id.insert(std::make_pair(std::make_pair(amount, td.m_global_output_index), transfer_index)).second;
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "cannot update m_amount_gindex_to_transfer_id: amount " << amount << ", gindex " << td.m_global_output_index << " already exists");
|
||||
|
||||
if (max_out_unlock_time < get_tx_unlock_time(tx, o))
|
||||
max_out_unlock_time = get_tx_unlock_time(tx, o);
|
||||
|
|
@ -1811,6 +1843,17 @@ uint64_t wallet2::detach_from_block_ids(uint64_t including_height)
|
|||
return blocks_detached;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::remove_transfer_from_amount_gindex_map(uint64_t tid)
|
||||
{
|
||||
for (auto it = m_amount_gindex_to_transfer_id.begin(); it != m_amount_gindex_to_transfer_id.end(); )
|
||||
{
|
||||
if (it->second == tid)
|
||||
it = m_amount_gindex_to_transfer_id.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::detach_blockchain(uint64_t including_height)
|
||||
{
|
||||
WLT_LOG_L0("Detaching blockchain on height " << including_height);
|
||||
|
|
@ -1829,6 +1872,7 @@ void wallet2::detach_blockchain(uint64_t including_height)
|
|||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it_ki != m_key_images.end(), "key image " << m_transfers[i].m_key_image << " not found");
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers[i].m_ptx_wallet_info->m_block_height >= including_height, "transfer #" << i << " block height is less than " << including_height);
|
||||
m_key_images.erase(it_ki);
|
||||
remove_transfer_from_amount_gindex_map(i);
|
||||
++transfers_detached;
|
||||
}
|
||||
m_transfers.erase(it, m_transfers.end());
|
||||
|
|
@ -1914,6 +1958,7 @@ bool wallet2::reset_all()
|
|||
//m_blockchain.clear();
|
||||
m_chain.clear();
|
||||
m_transfers.clear();
|
||||
m_amount_gindex_to_transfer_id.clear();
|
||||
m_key_images.clear();
|
||||
// m_pending_key_images is not cleared intentionally
|
||||
m_unconfirmed_in_transfers.clear();
|
||||
|
|
@ -2170,14 +2215,16 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password)
|
|||
if (m_watch_only)
|
||||
load_keys2ki(true, need_to_resync);
|
||||
|
||||
WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str());
|
||||
WLT_LOG_L0("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")");
|
||||
|
||||
if (need_to_resync)
|
||||
{
|
||||
reset_history();
|
||||
WLT_LOG_L0("Unable to load history data from wallet file, wallet will be resynced!");
|
||||
}
|
||||
THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str());
|
||||
WLT_LOG_L0("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")");
|
||||
THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::store()
|
||||
|
|
|
|||
|
|
@ -380,6 +380,9 @@ namespace tools
|
|||
uint32_t m_flags;
|
||||
|
||||
uint64_t amount() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index].amount; }
|
||||
const currency::tx_out& output() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index]; }
|
||||
uint8_t mix_attr() const { return output().target.type() == typeid(currency::txout_to_key) ? boost::get<const currency::txout_to_key&>(output().target).mix_attr : UINT8_MAX; }
|
||||
crypto::hash tx_hash() const { return get_transaction_hash(m_ptx_wallet_info->m_tx); }
|
||||
bool is_spent() const { return m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT; }
|
||||
bool is_spendable() const { return (m_flags & (WALLET_TRANSFER_DETAIL_FLAG_SPENT | WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION | WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION)) == 0; }
|
||||
bool is_reserved_for_escrow() const { return ( (m_flags & WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) != 0 ); }
|
||||
|
|
@ -443,6 +446,7 @@ namespace tools
|
|||
typedef std::unordered_map<crypto::hash, transfer_details_base> multisig_transfer_container;
|
||||
typedef std::unordered_map<crypto::hash, tools::wallet_public::escrow_contract_details_basic> escrow_contracts_container;
|
||||
typedef std::map<uint64_t, std::set<size_t> > free_amounts_cache_type;
|
||||
typedef std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t> amount_gindex_to_transfer_id_container; // maps [amount; gindex] -> tid
|
||||
|
||||
|
||||
struct keys_file_data_old
|
||||
|
|
@ -503,7 +507,7 @@ namespace tools
|
|||
|
||||
//i_wallet2_callback* callback() const { return m_wcallback; }
|
||||
//void callback(i_wallet2_callback* callback) { m_callback = callback; }
|
||||
void callback(std::shared_ptr<i_wallet2_callback> callback) { m_wcallback = callback; m_do_rise_transfer = true; }
|
||||
void callback(std::shared_ptr<i_wallet2_callback> callback) { m_wcallback = callback; m_do_rise_transfer = (callback != nullptr); }
|
||||
void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; }
|
||||
|
||||
bool has_related_alias_entry_unconfirmed(const currency::transaction& tx);
|
||||
|
|
@ -724,6 +728,7 @@ namespace tools
|
|||
|
||||
a & m_transfers;
|
||||
a & m_multisig_transfers;
|
||||
a & m_amount_gindex_to_transfer_id;
|
||||
a & m_key_images;
|
||||
a & m_unconfirmed_txs;
|
||||
a & m_unconfirmed_multisig_transfers;
|
||||
|
|
@ -935,6 +940,7 @@ private:
|
|||
uint64_t get_wallet_minimum_height();
|
||||
|
||||
void push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector<currency::extra_v>& extra);
|
||||
void remove_transfer_from_amount_gindex_map(uint64_t tid);
|
||||
|
||||
currency::account_base m_account;
|
||||
bool m_watch_only;
|
||||
|
|
@ -950,6 +956,7 @@ private:
|
|||
|
||||
transfer_container m_transfers;
|
||||
multisig_transfer_container m_multisig_transfers;
|
||||
amount_gindex_to_transfer_id_container m_amount_gindex_to_transfer_id;
|
||||
payment_container m_payments;
|
||||
std::unordered_map<crypto::key_image, size_t> m_key_images;
|
||||
std::unordered_map<crypto::public_key, crypto::key_image> m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue