Merge pull request #6745
80e535c
wallet2: adapt to deterministic unlock time (TheCharlatan)4971219
blockchain: deterministic UNIX time unlock checks (moneromooo-monero)
This commit is contained in:
commit
ea587de300
@ -180,6 +180,7 @@
|
||||
#define HF_VERSION_EFFECTIVE_SHORT_TERM_MEDIAN_IN_PENALTY 12
|
||||
#define HF_VERSION_EXACT_COINBASE 13
|
||||
#define HF_VERSION_CLSAG 13
|
||||
#define HF_VERSION_DETERMINISTIC_UNLOCK_TIME 13
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
|
||||
|
@ -2267,8 +2267,9 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA
|
||||
MERROR("Unexpected output data size: expected " << req.outputs.size() << ", got " << data.size());
|
||||
return false;
|
||||
}
|
||||
const uint8_t hf_version = m_hardfork->get_current_version();
|
||||
for (const auto &t: data)
|
||||
res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time), t.height, crypto::null_hash});
|
||||
res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time, hf_version), t.height, crypto::null_hash});
|
||||
|
||||
if (req.get_txid)
|
||||
{
|
||||
@ -2292,7 +2293,8 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint
|
||||
key = o_data.pubkey;
|
||||
mask = o_data.commitment;
|
||||
tx_out_index toi = m_db->get_output_tx_and_index(amount, index);
|
||||
unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
|
||||
const uint8_t hf_version = m_hardfork->get_current_version();
|
||||
unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first), hf_version);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const
|
||||
@ -3363,7 +3365,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
|
||||
// make sure that output being spent matches up correctly with the
|
||||
// signature spending it.
|
||||
if (!check_tx_input(tx.version, in_to_key, tx_prefix_hash, tx.version == 1 ? tx.signatures[sig_index] : std::vector<crypto::signature>(), tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height))
|
||||
if (!check_tx_input(tx.version, in_to_key, tx_prefix_hash, tx.version == 1 ? tx.signatures[sig_index] : std::vector<crypto::signature>(), tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height, hf_version))
|
||||
{
|
||||
MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index);
|
||||
if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain()
|
||||
@ -3756,7 +3758,7 @@ uint64_t Blockchain::get_dynamic_base_fee_estimate(uint64_t grace_blocks) const
|
||||
//------------------------------------------------------------------
|
||||
// This function checks to see if a tx is unlocked. unlock_time is either
|
||||
// a block index or a unix time.
|
||||
bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const
|
||||
bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time, uint8_t hf_version) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
|
||||
@ -3771,7 +3773,7 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const
|
||||
else
|
||||
{
|
||||
//interpret as time
|
||||
uint64_t current_time = static_cast<uint64_t>(time(NULL));
|
||||
const uint64_t current_time = hf_version >= HF_VERSION_DETERMINISTIC_UNLOCK_TIME ? get_adjusted_time(m_db->height()) : static_cast<uint64_t>(time(NULL));
|
||||
if(current_time + (get_current_hard_fork_version() < 2 ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2) >= unlock_time)
|
||||
return true;
|
||||
else
|
||||
@ -3783,7 +3785,7 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const
|
||||
// This function locates all outputs associated with a given input (mixins)
|
||||
// and validates that they exist and are usable. It also checks the ring
|
||||
// signature for each input.
|
||||
bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height) const
|
||||
bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height, uint8_t hf_version) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
@ -3795,14 +3797,15 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons
|
||||
{
|
||||
std::vector<rct::ctkey >& m_output_keys;
|
||||
const Blockchain& m_bch;
|
||||
outputs_visitor(std::vector<rct::ctkey>& output_keys, const Blockchain& bch) :
|
||||
m_output_keys(output_keys), m_bch(bch)
|
||||
const uint8_t hf_version;
|
||||
outputs_visitor(std::vector<rct::ctkey>& output_keys, const Blockchain& bch, uint8_t hf_version) :
|
||||
m_output_keys(output_keys), m_bch(bch), hf_version(hf_version)
|
||||
{
|
||||
}
|
||||
bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey, const rct::key &commitment)
|
||||
{
|
||||
//check tx unlock time
|
||||
if (!m_bch.is_tx_spendtime_unlocked(unlock_time))
|
||||
if (!m_bch.is_tx_spendtime_unlocked(unlock_time, hf_version))
|
||||
{
|
||||
MERROR_VER("One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time);
|
||||
return false;
|
||||
@ -3821,7 +3824,7 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons
|
||||
output_keys.clear();
|
||||
|
||||
// collect output keys
|
||||
outputs_visitor vi(output_keys, *this);
|
||||
outputs_visitor vi(output_keys, *this, hf_version);
|
||||
if (!scan_outputkeys_for_indexes(tx_version, txin, vi, tx_prefix_hash, pmax_related_block_height))
|
||||
{
|
||||
MERROR_VER("Failed to get output keys for tx with amount = " << print_money(txin.amount) << " and count indexes " << txin.key_offsets.size());
|
||||
@ -3840,12 +3843,38 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
//TODO: Is this intended to do something else? Need to look into the todo there.
|
||||
uint64_t Blockchain::get_adjusted_time() const
|
||||
// only works on the main chain
|
||||
uint64_t Blockchain::get_adjusted_time(uint64_t height) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
//TODO: add collecting median time
|
||||
return time(NULL);
|
||||
|
||||
// if not enough blocks, no proper median yet, return current time
|
||||
if(height < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
|
||||
{
|
||||
return static_cast<uint64_t>(time(NULL));
|
||||
}
|
||||
std::vector<uint64_t> timestamps;
|
||||
|
||||
// need most recent 60 blocks, get index of first of those
|
||||
size_t offset = height - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
|
||||
timestamps.reserve(height - offset);
|
||||
for(;offset < height; ++offset)
|
||||
{
|
||||
timestamps.push_back(m_db->get_block_timestamp(offset));
|
||||
}
|
||||
uint64_t median_ts = epee::misc_utils::median(timestamps);
|
||||
|
||||
// project the median to match approximately when the block being validated will appear
|
||||
// the median is calculated from a chunk of past blocks, so we use +1 to offset onto the current block
|
||||
median_ts += (BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW + 1) * DIFFICULTY_TARGET_V2 / 2;
|
||||
|
||||
// project the current block's time based on the previous block's time
|
||||
// we don't use the current block's time directly to mitigate timestamp manipulation
|
||||
uint64_t adjusted_current_block_ts = timestamps.back() + DIFFICULTY_TARGET_V2;
|
||||
|
||||
// return minimum of ~current block time and adjusted median time
|
||||
// we do this since it's better to report a time in the past than a time in the future
|
||||
return (adjusted_current_block_ts < median_ts ? adjusted_current_block_ts : median_ts);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
//TODO: revisit, has changed a bit on upstream
|
||||
@ -3873,9 +3902,9 @@ bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const
|
||||
bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT)
|
||||
if(b.timestamp > (uint64_t)time(NULL) + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT)
|
||||
{
|
||||
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 2 hours");
|
||||
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than local time + 2 hours");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1042,6 +1042,21 @@ namespace cryptonote
|
||||
*/
|
||||
void flush_invalid_blocks();
|
||||
|
||||
/**
|
||||
* @brief get the "adjusted time"
|
||||
*
|
||||
* Computes the median timestamp of the previous 60 blocks, projects it
|
||||
* onto the current block to get an 'adjusted median time' which approximates
|
||||
* what the current block's timestamp should be. Also projects the previous
|
||||
* block's timestamp to estimate the current block's timestamp.
|
||||
*
|
||||
* Returns the minimum of the two projections, or the current local time on
|
||||
* the machine if less than 60 blocks are available.
|
||||
*
|
||||
* @return current time approximated from chain data
|
||||
*/
|
||||
uint64_t get_adjusted_time(uint64_t height) const;
|
||||
|
||||
#ifndef IN_UNIT_TESTS
|
||||
private:
|
||||
#endif
|
||||
@ -1182,10 +1197,11 @@ namespace cryptonote
|
||||
* @param output_keys return-by-reference the public keys of the outputs in the input set
|
||||
* @param rct_signatures the ringCT signatures, which are only valid if tx version > 1
|
||||
* @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set
|
||||
* @param hf_version the consensus rules version to use
|
||||
*
|
||||
* @return false if any output is not yet unlocked, or is missing, otherwise true
|
||||
*/
|
||||
bool check_tx_input(size_t tx_version,const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height) const;
|
||||
bool check_tx_input(size_t tx_version,const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height, uint8_t hf_version) const;
|
||||
|
||||
/**
|
||||
* @brief validate a transaction's inputs and their keys
|
||||
@ -1373,10 +1389,11 @@ namespace cryptonote
|
||||
* unlock_time is either a block index or a unix time.
|
||||
*
|
||||
* @param unlock_time the unlock parameter (height or time)
|
||||
* @param hf_version the consensus rules version to use
|
||||
*
|
||||
* @return true if spendable, otherwise false
|
||||
*/
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time) const;
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint8_t hf_version) const;
|
||||
|
||||
/**
|
||||
* @brief stores an invalid block in a separate container
|
||||
@ -1437,16 +1454,6 @@ namespace cryptonote
|
||||
bool check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b, uint64_t& median_ts) const;
|
||||
bool check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b) const { uint64_t median_ts; return check_block_timestamp(timestamps, b, median_ts); }
|
||||
|
||||
/**
|
||||
* @brief get the "adjusted time"
|
||||
*
|
||||
* Currently this simply returns the current time according to the
|
||||
* user's machine.
|
||||
*
|
||||
* @return the current time
|
||||
*/
|
||||
uint64_t get_adjusted_time() const;
|
||||
|
||||
/**
|
||||
* @brief finish an alternate chain's timestamp window from the main chain
|
||||
*
|
||||
|
@ -461,6 +461,8 @@ namespace cryptonote
|
||||
res.cumulative_difficulty, res.wide_cumulative_difficulty, res.cumulative_difficulty_top64);
|
||||
res.block_size_limit = res.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit();
|
||||
res.block_size_median = res.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median();
|
||||
res.adjusted_time = m_core.get_blockchain_storage().get_adjusted_time(res.height);
|
||||
|
||||
res.start_time = restricted ? 0 : (uint64_t)m_core.get_start_time();
|
||||
res.free_space = restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
|
||||
res.offline = m_core.offline();
|
||||
|
@ -88,7 +88,7 @@ namespace cryptonote
|
||||
// advance which version they will stop working with
|
||||
// Don't go over 32767 for any of these
|
||||
#define CORE_RPC_VERSION_MAJOR 3
|
||||
#define CORE_RPC_VERSION_MINOR 1
|
||||
#define CORE_RPC_VERSION_MINOR 2
|
||||
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
||||
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
|
||||
|
||||
@ -675,6 +675,7 @@ namespace cryptonote
|
||||
uint64_t block_weight_limit;
|
||||
uint64_t block_size_median;
|
||||
uint64_t block_weight_median;
|
||||
uint64_t adjusted_time;
|
||||
uint64_t start_time;
|
||||
uint64_t free_space;
|
||||
bool offline;
|
||||
@ -713,6 +714,7 @@ namespace cryptonote
|
||||
KV_SERIALIZE_OPT(block_weight_limit, (uint64_t)0)
|
||||
KV_SERIALIZE(block_size_median)
|
||||
KV_SERIALIZE_OPT(block_weight_median, (uint64_t)0)
|
||||
KV_SERIALIZE(adjusted_time)
|
||||
KV_SERIALIZE(start_time)
|
||||
KV_SERIALIZE(free_space)
|
||||
KV_SERIALIZE(offline)
|
||||
|
@ -538,6 +538,7 @@ namespace rpc
|
||||
res.info.cumulative_difficulty = (res.info.wide_cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
|
||||
res.info.block_size_limit = res.info.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit();
|
||||
res.info.block_size_median = res.info.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median();
|
||||
res.info.adjusted_time = m_core.get_blockchain_storage().get_adjusted_time(res.info.height);
|
||||
res.info.start_time = (uint64_t)m_core.get_start_time();
|
||||
res.info.version = MONERO_VERSION;
|
||||
|
||||
|
@ -196,6 +196,7 @@ namespace rpc
|
||||
uint64_t block_size_limit;
|
||||
uint64_t block_weight_limit;
|
||||
uint64_t block_size_median;
|
||||
uint64_t adjusted_time;
|
||||
uint64_t block_weight_median;
|
||||
uint64_t start_time;
|
||||
std::string version;
|
||||
|
@ -1342,6 +1342,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::r
|
||||
INSERT_INTO_JSON_OBJECT(dest, block_weight_limit, info.block_weight_limit);
|
||||
INSERT_INTO_JSON_OBJECT(dest, block_size_median, info.block_size_median);
|
||||
INSERT_INTO_JSON_OBJECT(dest, block_weight_median, info.block_weight_median);
|
||||
INSERT_INTO_JSON_OBJECT(dest, adjusted_time, info.adjusted_time);
|
||||
INSERT_INTO_JSON_OBJECT(dest, start_time, info.start_time);
|
||||
|
||||
dest.EndObject();
|
||||
@ -1375,6 +1376,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
|
||||
GET_FROM_JSON_OBJECT(val, info.block_weight_limit, block_weight_limit);
|
||||
GET_FROM_JSON_OBJECT(val, info.block_size_median, block_size_median);
|
||||
GET_FROM_JSON_OBJECT(val, info.block_weight_median, block_weight_median);
|
||||
GET_FROM_JSON_OBJECT(val, info.adjusted_time, adjusted_time);
|
||||
GET_FROM_JSON_OBJECT(val, info.start_time, start_time);
|
||||
}
|
||||
|
||||
|
@ -8553,8 +8553,8 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t current_time = static_cast<uint64_t>(time(NULL));
|
||||
uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1);
|
||||
const uint64_t adjusted_time = m_wallet->get_daemon_adjusted_time();
|
||||
uint64_t threshold = adjusted_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1);
|
||||
if (threshold < pd.m_unlock_time)
|
||||
locked_msg = get_human_readable_timespan(std::chrono::seconds(pd.m_unlock_time - threshold));
|
||||
}
|
||||
@ -10265,8 +10265,8 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t current_time = static_cast<uint64_t>(time(NULL));
|
||||
uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1);
|
||||
const uint64_t adjusted_time = m_wallet->get_daemon_adjusted_time();
|
||||
uint64_t threshold = adjusted_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1);
|
||||
if (threshold >= pd.m_unlock_time)
|
||||
success_msg_writer() << "unlocked for " << get_human_readable_timespan(std::chrono::seconds(threshold - pd.m_unlock_time));
|
||||
else
|
||||
|
@ -72,6 +72,7 @@ void NodeRPCProxy::invalidate()
|
||||
m_rpc_version = 0;
|
||||
m_target_height = 0;
|
||||
m_block_weight_limit = 0;
|
||||
m_adjusted_time = 0;
|
||||
m_get_info_time = 0;
|
||||
m_rpc_payment_info_time = 0;
|
||||
m_rpc_payment_seed_height = 0;
|
||||
@ -131,6 +132,7 @@ boost::optional<std::string> NodeRPCProxy::get_info()
|
||||
m_height = resp_t.height;
|
||||
m_target_height = resp_t.target_height;
|
||||
m_block_weight_limit = resp_t.block_weight_limit ? resp_t.block_weight_limit : resp_t.block_size_limit;
|
||||
m_adjusted_time = resp_t.adjusted_time;
|
||||
m_get_info_time = now;
|
||||
m_height_time = now;
|
||||
}
|
||||
@ -171,6 +173,15 @@ boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &bloc
|
||||
return boost::optional<std::string>();
|
||||
}
|
||||
|
||||
boost::optional<std::string> NodeRPCProxy::get_adjusted_time(uint64_t &adjusted_time)
|
||||
{
|
||||
auto res = get_info();
|
||||
if (res)
|
||||
return res;
|
||||
adjusted_time = m_adjusted_time;
|
||||
return boost::optional<std::string>();
|
||||
}
|
||||
|
||||
boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height)
|
||||
{
|
||||
if (m_offline)
|
||||
|
@ -52,6 +52,7 @@ public:
|
||||
void set_height(uint64_t h);
|
||||
boost::optional<std::string> get_target_height(uint64_t &height);
|
||||
boost::optional<std::string> get_block_weight_limit(uint64_t &block_weight_limit);
|
||||
boost::optional<std::string> get_adjusted_time(uint64_t &adjusted_time);
|
||||
boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height);
|
||||
boost::optional<std::string> get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee);
|
||||
boost::optional<std::string> get_fee_quantization_mask(uint64_t &fee_quantization_mask);
|
||||
@ -84,6 +85,7 @@ private:
|
||||
uint64_t m_dynamic_base_fee_estimate_cached_height;
|
||||
uint64_t m_dynamic_base_fee_estimate_grace_blocks;
|
||||
uint64_t m_fee_quantization_mask;
|
||||
uint64_t m_adjusted_time;
|
||||
uint32_t m_rpc_version;
|
||||
uint64_t m_target_height;
|
||||
uint64_t m_block_weight_limit;
|
||||
|
@ -5969,7 +5969,7 @@ uint64_t wallet2::balance(uint32_t index_major, bool strict) const
|
||||
return amount;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
|
||||
uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock)
|
||||
{
|
||||
uint64_t amount = 0;
|
||||
if (blocks_to_unlock)
|
||||
@ -6021,7 +6021,7 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
|
||||
return amount_per_subaddr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
|
||||
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict)
|
||||
{
|
||||
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> amount_per_subaddr;
|
||||
const uint64_t blockchain_height = get_blockchain_current_height();
|
||||
@ -6069,7 +6069,7 @@ uint64_t wallet2::balance_all(bool strict) const
|
||||
return r;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
|
||||
uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
if (blocks_to_unlock)
|
||||
@ -6234,12 +6234,12 @@ void wallet2::rescan_blockchain(bool hard, bool refresh, bool keep_key_images)
|
||||
finish_rescan_bc_keep_key_images(transfers_cnt, transfers_hash);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_unlocked(const transfer_details& td) const
|
||||
bool wallet2::is_transfer_unlocked(const transfer_details& td)
|
||||
{
|
||||
return is_transfer_unlocked(td.m_tx.unlock_time, td.m_block_height);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const
|
||||
bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height)
|
||||
{
|
||||
if(!is_tx_spendtime_unlocked(unlock_time, block_height))
|
||||
return false;
|
||||
@ -6250,7 +6250,7 @@ bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height)
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const
|
||||
bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height)
|
||||
{
|
||||
if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
|
||||
{
|
||||
@ -6262,12 +6262,14 @@ bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_heig
|
||||
}else
|
||||
{
|
||||
//interpret as time
|
||||
uint64_t current_time = static_cast<uint64_t>(time(NULL));
|
||||
uint64_t adjusted_time;
|
||||
try { adjusted_time = get_daemon_adjusted_time(); }
|
||||
catch(...) { adjusted_time = time(NULL); } // use local time if no daemon to report blockchain time
|
||||
// XXX: this needs to be fast, so we'd need to get the starting heights
|
||||
// from the daemon to be correct once voting kicks in
|
||||
uint64_t v2height = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827;
|
||||
uint64_t leeway = block_height < v2height ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2;
|
||||
if(current_time + leeway >= unlock_time)
|
||||
if(adjusted_time + leeway >= unlock_time)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -9109,7 +9111,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
LOG_PRINT_L2("transfer_selected_rct done");
|
||||
}
|
||||
|
||||
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const
|
||||
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices)
|
||||
{
|
||||
std::vector<size_t> picks;
|
||||
float current_output_relatdness = 1.0f;
|
||||
@ -10780,7 +10782,7 @@ uint64_t wallet2::get_upper_transaction_weight_limit()
|
||||
return full_reward_zone - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const
|
||||
std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(const transfer_details &td)> &f)
|
||||
{
|
||||
std::vector<size_t> outputs;
|
||||
size_t n = 0;
|
||||
@ -12085,6 +12087,15 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err)
|
||||
return height;
|
||||
}
|
||||
|
||||
uint64_t wallet2::get_daemon_adjusted_time()
|
||||
{
|
||||
uint64_t adjusted_time;
|
||||
|
||||
boost::optional<std::string> result = m_node_rpc_proxy.get_adjusted_time(adjusted_time);
|
||||
THROW_WALLET_EXCEPTION_IF(result, error::wallet_internal_error, "Invalid adjusted time from daemon");
|
||||
return adjusted_time;
|
||||
}
|
||||
|
||||
uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
|
||||
{
|
||||
err = "";
|
||||
|
@ -939,13 +939,13 @@ private:
|
||||
|
||||
// locked & unlocked balance of given or current subaddress account
|
||||
uint64_t balance(uint32_t subaddr_index_major, bool strict) const;
|
||||
uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
|
||||
uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL);
|
||||
// locked & unlocked balance per subaddress of given or current subaddress account
|
||||
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
|
||||
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
|
||||
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict);
|
||||
// all locked & unlocked balances of all subaddress accounts
|
||||
uint64_t balance_all(bool strict) const;
|
||||
uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
|
||||
uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL);
|
||||
template<typename T>
|
||||
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
|
||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||
@ -1003,8 +1003,8 @@ private:
|
||||
uint64_t get_blockchain_current_height() const { return m_light_wallet_blockchain_height ? m_light_wallet_blockchain_height : m_blockchain.size(); }
|
||||
void rescan_spent();
|
||||
void rescan_blockchain(bool hard, bool refresh = true, bool keep_key_images = false);
|
||||
bool is_transfer_unlocked(const transfer_details& td) const;
|
||||
bool is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const;
|
||||
bool is_transfer_unlocked(const transfer_details& td);
|
||||
bool is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height);
|
||||
|
||||
uint64_t get_last_block_reward() const { return m_last_block_reward; }
|
||||
uint64_t get_device_last_key_image_sync() const { return m_device_last_key_image_sync; }
|
||||
@ -1301,13 +1301,15 @@ private:
|
||||
const boost::optional<epee::net_utils::http::login>& get_daemon_login() const { return m_daemon_login; }
|
||||
uint64_t get_daemon_blockchain_height(std::string& err);
|
||||
uint64_t get_daemon_blockchain_target_height(std::string& err);
|
||||
uint64_t get_daemon_adjusted_time();
|
||||
|
||||
/*!
|
||||
* \brief Calculates the approximate blockchain height from current date/time.
|
||||
*/
|
||||
uint64_t get_approximate_blockchain_height() const;
|
||||
uint64_t estimate_blockchain_height();
|
||||
std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct);
|
||||
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const;
|
||||
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f);
|
||||
std::vector<size_t> select_available_unmixable_outputs();
|
||||
std::vector<size_t> select_available_mixable_outputs();
|
||||
|
||||
@ -1536,7 +1538,7 @@ private:
|
||||
|
||||
void set_tx_notify(const std::shared_ptr<tools::Notify> ¬ify) { m_tx_notify = notify; }
|
||||
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const;
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height);
|
||||
void hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const;
|
||||
uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const;
|
||||
void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash);
|
||||
@ -1600,7 +1602,7 @@ private:
|
||||
std::vector<uint64_t> get_unspent_amounts_vector(bool strict);
|
||||
uint64_t get_dynamic_base_fee_estimate();
|
||||
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
|
||||
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const;
|
||||
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices);
|
||||
void set_spent(size_t idx, uint64_t height);
|
||||
void set_unspent(size_t idx);
|
||||
bool is_spent(const transfer_details &td, bool strict = true) const;
|
||||
|
Loading…
Reference in New Issue
Block a user