|
|
@ -894,6 +894,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
|
|
|
|
m_key_reuse_mitigation2(true),
|
|
|
|
m_key_reuse_mitigation2(true),
|
|
|
|
m_segregation_height(0),
|
|
|
|
m_segregation_height(0),
|
|
|
|
m_ignore_fractional_outputs(true),
|
|
|
|
m_ignore_fractional_outputs(true),
|
|
|
|
|
|
|
|
m_track_uses(false),
|
|
|
|
m_is_initialized(false),
|
|
|
|
m_is_initialized(false),
|
|
|
|
m_kdf_rounds(kdf_rounds),
|
|
|
|
m_kdf_rounds(kdf_rounds),
|
|
|
|
is_old_file_format(false),
|
|
|
|
is_old_file_format(false),
|
|
|
@ -1446,8 +1447,9 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data)
|
|
|
|
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
PERF_TIMER(process_new_transaction);
|
|
|
|
// In this function, tx (probably) only contains the base information
|
|
|
|
// In this function, tx (probably) only contains the base information
|
|
|
|
// (that is, the prunable stuff may or may not be included)
|
|
|
|
// (that is, the prunable stuff may or may not be included)
|
|
|
|
if (!miner_tx && !pool)
|
|
|
|
if (!miner_tx && !pool)
|
|
|
@ -1684,6 +1686,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|
|
|
if (!m_multisig && !m_watch_only)
|
|
|
|
if (!m_multisig && !m_watch_only)
|
|
|
|
m_key_images[td.m_key_image] = m_transfers.size()-1;
|
|
|
|
m_key_images[td.m_key_image] = m_transfers.size()-1;
|
|
|
|
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
|
|
|
|
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
|
|
|
|
|
|
|
|
if (output_tracker_cache)
|
|
|
|
|
|
|
|
(*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = m_transfers.size() - 1;
|
|
|
|
if (m_multisig)
|
|
|
|
if (m_multisig)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
|
|
|
|
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
|
|
|
@ -1749,6 +1753,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|
|
|
td.m_mask = rct::identity();
|
|
|
|
td.m_mask = rct::identity();
|
|
|
|
td.m_rct = false;
|
|
|
|
td.m_rct = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (output_tracker_cache)
|
|
|
|
|
|
|
|
(*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = kit->second;
|
|
|
|
if (m_multisig)
|
|
|
|
if (m_multisig)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
|
|
|
|
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
|
|
|
@ -1780,11 +1786,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(in.type() != typeid(cryptonote::txin_to_key))
|
|
|
|
if(in.type() != typeid(cryptonote::txin_to_key))
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
|
|
|
|
const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(in);
|
|
|
|
|
|
|
|
auto it = m_key_images.find(in_to_key.k_image);
|
|
|
|
if(it != m_key_images.end())
|
|
|
|
if(it != m_key_images.end())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
transfer_details& td = m_transfers[it->second];
|
|
|
|
transfer_details& td = m_transfers[it->second];
|
|
|
|
uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
|
|
|
|
uint64_t amount = in_to_key.amount;
|
|
|
|
if (amount > 0)
|
|
|
|
if (amount > 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(amount != td.amount())
|
|
|
|
if(amount != td.amount())
|
|
|
@ -1815,6 +1822,34 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|
|
|
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
|
|
|
|
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!pool && m_track_uses)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
PERF_TIMER(track_uses);
|
|
|
|
|
|
|
|
const uint64_t amount = in_to_key.amount;
|
|
|
|
|
|
|
|
std::vector<uint64_t> offsets = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
|
|
|
|
|
|
|
|
if (output_tracker_cache)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (uint64_t offset: offsets)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const std::map<std::pair<uint64_t, uint64_t>, size_t>::const_iterator i = output_tracker_cache->find(std::make_pair(amount, offset));
|
|
|
|
|
|
|
|
if (i != output_tracker_cache->end())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
size_t idx = i->second;
|
|
|
|
|
|
|
|
THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Output tracker cache index out of range");
|
|
|
|
|
|
|
|
m_transfers[idx].m_uses.push_back(std::make_pair(height, txid));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else for (transfer_details &td: m_transfers)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (amount != in_to_key.amount)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (uint64_t offset: offsets)
|
|
|
|
|
|
|
|
if (offset == td.m_global_output_index)
|
|
|
|
|
|
|
|
td.m_uses.push_back(std::make_pair(height, txid));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
|
|
|
|
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
|
|
|
@ -1997,7 +2032,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
|
|
|
|
add_rings(tx);
|
|
|
|
add_rings(tx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset)
|
|
|
|
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
|
|
|
|
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
|
|
|
|
"block transactions=" + std::to_string(bche.txs.size()) +
|
|
|
|
"block transactions=" + std::to_string(bche.txs.size()) +
|
|
|
@ -2010,7 +2045,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
|
|
|
|
{
|
|
|
|
{
|
|
|
|
TIME_MEASURE_START(miner_tx_handle_time);
|
|
|
|
TIME_MEASURE_START(miner_tx_handle_time);
|
|
|
|
if (m_refresh_type != RefreshNoCoinbase)
|
|
|
|
if (m_refresh_type != RefreshNoCoinbase)
|
|
|
|
process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset]);
|
|
|
|
process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
|
|
|
|
++tx_cache_data_offset;
|
|
|
|
++tx_cache_data_offset;
|
|
|
|
TIME_MEASURE_FINISH(miner_tx_handle_time);
|
|
|
|
TIME_MEASURE_FINISH(miner_tx_handle_time);
|
|
|
|
|
|
|
|
|
|
|
@ -2019,7 +2054,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
|
|
|
|
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
|
|
|
|
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
|
|
|
|
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
|
|
|
|
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++]);
|
|
|
|
process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TIME_MEASURE_FINISH(txs_handle_time);
|
|
|
|
TIME_MEASURE_FINISH(txs_handle_time);
|
|
|
|
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
|
|
|
|
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
|
|
|
@ -2117,7 +2152,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
|
|
|
|
hashes = std::move(res.m_block_ids);
|
|
|
|
hashes = std::move(res.m_block_ids);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added)
|
|
|
|
void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
size_t current_index = start_height;
|
|
|
|
size_t current_index = start_height;
|
|
|
|
blocks_added = 0;
|
|
|
|
blocks_added = 0;
|
|
|
@ -2224,7 +2259,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
|
|
|
|
|
|
|
|
|
|
|
|
if(current_index >= m_blockchain.size())
|
|
|
|
if(current_index >= m_blockchain.size())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
|
|
|
|
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
|
|
|
|
++blocks_added;
|
|
|
|
++blocks_added;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(bl_id != m_blockchain[current_index])
|
|
|
|
else if(bl_id != m_blockchain[current_index])
|
|
|
@ -2236,7 +2271,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
|
|
|
|
string_tools::pod_to_hex(m_blockchain[current_index]));
|
|
|
|
string_tools::pod_to_hex(m_blockchain[current_index]));
|
|
|
|
|
|
|
|
|
|
|
|
detach_blockchain(current_index);
|
|
|
|
detach_blockchain(current_index);
|
|
|
|
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
|
|
|
|
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -2668,6 +2703,17 @@ bool wallet2::delete_address_book_row(std::size_t row_id) {
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create_output_tracker_cache() const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> cache{new std::map<std::pair<uint64_t, uint64_t>, size_t>()};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < m_transfers.size(); ++i)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const transfer_details &td = m_transfers[i];
|
|
|
|
|
|
|
|
(*cache)[std::make_pair(td.is_rct() ? 0 : td.amount(), td.m_global_output_index)] = i;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return cache;
|
|
|
|
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
|
|
|
|
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -2715,6 +2761,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
|
|
|
std::vector<cryptonote::block_complete_entry> blocks;
|
|
|
|
std::vector<cryptonote::block_complete_entry> blocks;
|
|
|
|
std::vector<parsed_block> parsed_blocks;
|
|
|
|
std::vector<parsed_block> parsed_blocks;
|
|
|
|
bool refreshed = false;
|
|
|
|
bool refreshed = false;
|
|
|
|
|
|
|
|
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> output_tracker_cache;
|
|
|
|
|
|
|
|
|
|
|
|
// pull the first set of blocks
|
|
|
|
// pull the first set of blocks
|
|
|
|
get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
|
|
|
|
get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
|
|
|
@ -2768,7 +2815,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
|
|
|
{
|
|
|
|
{
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
|
|
|
|
process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks, output_tracker_cache.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const tools::error::out_of_hashchain_bounds_error&)
|
|
|
|
catch (const tools::error::out_of_hashchain_bounds_error&)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -2811,6 +2858,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
|
|
|
throw std::runtime_error("proxy exception in refresh thread");
|
|
|
|
throw std::runtime_error("proxy exception in refresh thread");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if we've got at least 10 blocks to refresh, assume we're starting
|
|
|
|
|
|
|
|
// a long refresh, and setup a tracking output cache if we need to
|
|
|
|
|
|
|
|
if (m_track_uses && !output_tracker_cache && next_blocks.size() >= 10)
|
|
|
|
|
|
|
|
output_tracker_cache = create_output_tracker_cache();
|
|
|
|
|
|
|
|
|
|
|
|
// switch to the new blocks from the daemon
|
|
|
|
// switch to the new blocks from the daemon
|
|
|
|
blocks_start_height = next_blocks_start_height;
|
|
|
|
blocks_start_height = next_blocks_start_height;
|
|
|
|
blocks = std::move(next_blocks);
|
|
|
|
blocks = std::move(next_blocks);
|
|
|
@ -3183,6 +3235,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
|
|
|
|
value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
|
|
|
|
value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
|
|
|
|
json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
|
|
|
|
json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
value2.SetInt(m_track_uses ? 1 : 0);
|
|
|
|
|
|
|
|
json.AddMember("track_uses", value2, json.GetAllocator());
|
|
|
|
|
|
|
|
|
|
|
|
value2.SetUint(m_subaddress_lookahead_major);
|
|
|
|
value2.SetUint(m_subaddress_lookahead_major);
|
|
|
|
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
|
|
|
|
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
|
|
|
|
|
|
|
|
|
|
|
@ -3329,6 +3384,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
|
|
|
|
m_key_reuse_mitigation2 = true;
|
|
|
|
m_key_reuse_mitigation2 = true;
|
|
|
|
m_segregation_height = 0;
|
|
|
|
m_segregation_height = 0;
|
|
|
|
m_ignore_fractional_outputs = true;
|
|
|
|
m_ignore_fractional_outputs = true;
|
|
|
|
|
|
|
|
m_track_uses = false;
|
|
|
|
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
|
|
|
|
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
|
|
|
|
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
|
|
|
|
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
|
|
|
|
m_original_keys_available = false;
|
|
|
|
m_original_keys_available = false;
|
|
|
@ -3481,6 +3537,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
|
|
|
|
m_segregation_height = field_segregation_height;
|
|
|
|
m_segregation_height = field_segregation_height;
|
|
|
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
|
|
|
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
|
|
|
|
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
|
|
|
|
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
|
|
|
|
|
|
|
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
|
|
|
|
|
|
|
|
m_track_uses = field_track_uses;
|
|
|
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
|
|
|
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
|
|
|
|
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
|
|
|
|
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
|
|
|
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
|
|
|
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
|
|
|
|