diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 562fc8d6c..f2cce542d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1650,8 +1650,8 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, } b.timestamp = time(NULL); - uint64_t median_ts; - if (!check_block_timestamp(b, median_ts)) + uint64_t median_ts{}; + if (!check_block_timestamp_main_chain(b, &median_ts)) { b.timestamp = median_ts; } @@ -3791,11 +3791,29 @@ uint64_t Blockchain::get_adjusted_time(uint64_t height) const return (adjusted_current_block_ts < median_ts ? adjusted_current_block_ts : median_ts); } //------------------------------------------------------------------ -//TODO: revisit, has changed a bit on upstream -bool Blockchain::check_block_timestamp(std::vector& timestamps, const block& b, uint64_t& median_ts) const +bool Blockchain::check_block_timestamp(std::vector& timestamps, const block& b, uint64_t* median_ts_out) { + if (median_ts_out) + *median_ts_out = 0; + LOG_PRINT_L3("Blockchain::" << __func__); - median_ts = epee::misc_utils::median(timestamps); + + 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 local time + 2 hours"); + return false; + } + + // if not enough blocks, no proper median yet, return true + if(timestamps.size() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) + { + return true; + } + + const uint64_t median_ts = epee::misc_utils::median(timestamps); + if (median_ts_out) + *median_ts_out = median_ts; if(b.timestamp < median_ts) { @@ -3813,34 +3831,24 @@ bool Blockchain::check_block_timestamp(std::vector& timestamps, const // true if the block's timestamp is not less than the timestamp of the // median of the selected blocks // false otherwise -bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) const +bool Blockchain::check_block_timestamp_main_chain(const block& b, uint64_t* median_ts_out) const { LOG_PRINT_L3("Blockchain::" << __func__); - 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 local time + 2 hours"); - return false; - } const auto h = m_db->height(); - // if not enough blocks, no proper median yet, return true - if(h < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) - { - return true; - } - std::vector timestamps; // need most recent 60 blocks, get index of first of those - size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW; + size_t offset = (h >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) ? (h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) : 0; + assert(offset <= h); timestamps.reserve(h - offset); for(;offset < h; ++offset) { timestamps.push_back(m_db->get_block_timestamp(offset)); } - return check_block_timestamp(timestamps, b, median_ts); + return check_block_timestamp(timestamps, b, median_ts_out); } //------------------------------------------------------------------ bool Blockchain::flush_txes_from_pool(const std::vector &txids) @@ -3919,7 +3927,7 @@ leave: // make sure block timestamp is not less than the median timestamp // of a set number of the most recent blocks. - if(!check_block_timestamp(bl)) + if(!check_block_timestamp_main_chain(bl)) { MERROR_VER("Block with id: " << id << std::endl << "has invalid timestamp: " << bl.timestamp); bvc.m_verifivation_failed = true; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 79c1c2640..53d309866 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1552,7 +1552,7 @@ namespace cryptonote bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); /** - * @brief checks a block's timestamp + * @brief checks a block's timestamp on top of the main chain * * This function grabs the timestamps from the most recent blocks, * where n = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. If there are not those many @@ -1563,26 +1563,27 @@ namespace cryptonote * false otherwise * * @param b the block to be checked - * @param median_ts return-by-reference the median of timestamps + * @param[out] median_ts_out the median of timestamps (optional) * * @return true if the block's timestamp is valid, otherwise false */ - bool check_block_timestamp(const block& b, uint64_t& median_ts) const; - bool check_block_timestamp(const block& b) const { uint64_t median_ts; return check_block_timestamp(b, median_ts); } + bool check_block_timestamp_main_chain(const block& b, uint64_t* median_ts_out = nullptr) const; /** * @brief checks a block's timestamp * * If the block is not more recent than the median of the recent - * timestamps passed here, it is considered invalid. + * timestamps passed here, it is considered invalid. If the block is too + * recent, according to the local system clock, it is considered invalid. * - * @param timestamps a list of the most recent timestamps to check against + * @param[inout] timestamps a list of the most recent timestamps to check against * @param b the block to be checked + * @param[out] median_ts_out the median of `timestamps` (optional) * * @return true if the block's timestamp is valid, otherwise false */ - bool check_block_timestamp(std::vector& timestamps, const block& b, uint64_t& median_ts) const; - bool check_block_timestamp(std::vector& timestamps, const block& b) const { uint64_t median_ts; return check_block_timestamp(timestamps, b, median_ts); } + static bool check_block_timestamp(std::vector& timestamps, const block& b, + uint64_t* median_ts_out = nullptr); /** * @brief finish an alternate chain's timestamp window from the main chain