mirror of
https://github.com/monero-project/monero.git
synced 2024-11-17 08:17:37 +00:00
protocol: more sanity checks in new chain block hashes
This commit is contained in:
parent
a1eca8ca7e
commit
0aa541b361
8 changed files with 90 additions and 21 deletions
|
@ -2758,32 +2758,44 @@ void Blockchain::flush_invalid_blocks()
|
||||||
m_invalid_blocks.clear();
|
m_invalid_blocks.clear();
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
bool Blockchain::have_block(const crypto::hash& id) const
|
bool Blockchain::have_block_unlocked(const crypto::hash& id, int *where) const
|
||||||
{
|
{
|
||||||
|
// WARNING: this function does not take m_blockchain_lock, and thus should only call read only
|
||||||
|
// m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
|
||||||
|
// well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
|
||||||
|
// lock if it is otherwise needed.
|
||||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
|
||||||
|
|
||||||
if(m_db->block_exists(id))
|
if(m_db->block_exists(id))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L2("block " << id << " found in main chain");
|
LOG_PRINT_L2("block " << id << " found in main chain");
|
||||||
|
if (where) *where = HAVE_BLOCK_MAIN_CHAIN;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_db->get_alt_block(id, NULL, NULL))
|
if(m_db->get_alt_block(id, NULL, NULL))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L2("block " << id << " found in alternative chains");
|
LOG_PRINT_L2("block " << id << " found in alternative chains");
|
||||||
|
if (where) *where = HAVE_BLOCK_ALT_CHAIN;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_invalid_blocks.count(id))
|
if(m_invalid_blocks.count(id))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L2("block " << id << " found in m_invalid_blocks");
|
LOG_PRINT_L2("block " << id << " found in m_invalid_blocks");
|
||||||
|
if (where) *where = HAVE_BLOCK_INVALID;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
bool Blockchain::have_block(const crypto::hash& id, int *where) const
|
||||||
|
{
|
||||||
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||||
|
return have_block_unlocked(id, where);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
bool Blockchain::handle_block_to_main_chain(const block& bl, block_verification_context& bvc, bool notify/* = true*/)
|
bool Blockchain::handle_block_to_main_chain(const block& bl, block_verification_context& bvc, bool notify/* = true*/)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||||
|
|
|
@ -377,10 +377,12 @@ namespace cryptonote
|
||||||
* for a block with the given hash
|
* for a block with the given hash
|
||||||
*
|
*
|
||||||
* @param id the hash to search for
|
* @param id the hash to search for
|
||||||
|
* @param where the type of block, if non NULL
|
||||||
*
|
*
|
||||||
* @return true if the block is known, else false
|
* @return true if the block is known, else false
|
||||||
*/
|
*/
|
||||||
bool have_block(const crypto::hash& id) const;
|
bool have_block_unlocked(const crypto::hash& id, int *where = NULL) const;
|
||||||
|
bool have_block(const crypto::hash& id, int *where = NULL) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief gets the total number of transactions on the main chain
|
* @brief gets the total number of transactions on the main chain
|
||||||
|
|
|
@ -1625,9 +1625,14 @@ namespace cryptonote
|
||||||
return m_mempool.get_transactions_count(include_sensitive_txes);
|
return m_mempool.get_transactions_count(include_sensitive_txes);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
bool core::have_block(const crypto::hash& id) const
|
bool core::have_block_unlocked(const crypto::hash& id, int *where) const
|
||||||
{
|
{
|
||||||
return m_blockchain_storage.have_block(id);
|
return m_blockchain_storage.have_block_unlocked(id, where);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
bool core::have_block(const crypto::hash& id, int *where) const
|
||||||
|
{
|
||||||
|
return m_blockchain_storage.have_block(id, where);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob) const
|
bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob) const
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
PUSH_WARNINGS
|
PUSH_WARNINGS
|
||||||
DISABLE_VS_WARNINGS(4355)
|
DISABLE_VS_WARNINGS(4355)
|
||||||
|
|
||||||
|
enum { HAVE_BLOCK_MAIN_CHAIN, HAVE_BLOCK_ALT_CHAIN, HAVE_BLOCK_INVALID };
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
struct test_options {
|
struct test_options {
|
||||||
|
@ -543,7 +545,8 @@ namespace cryptonote
|
||||||
*
|
*
|
||||||
* @note see Blockchain::have_block
|
* @note see Blockchain::have_block
|
||||||
*/
|
*/
|
||||||
bool have_block(const crypto::hash& id) const;
|
bool have_block_unlocked(const crypto::hash& id, int *where = NULL) const;
|
||||||
|
bool have_block(const crypto::hash& id, int *where = NULL) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @copydoc Blockchain::get_short_chain_history
|
* @copydoc Blockchain::get_short_chain_history
|
||||||
|
|
|
@ -2570,17 +2570,6 @@ skip:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<crypto::hash> hashes;
|
|
||||||
for (const auto &h: arg.m_block_ids)
|
|
||||||
{
|
|
||||||
if (!hashes.insert(h).second)
|
|
||||||
{
|
|
||||||
LOG_ERROR_CCONTEXT("sent duplicate block, dropping connection");
|
|
||||||
drop_connection(context, true, false);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
|
uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
|
||||||
if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
|
if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
|
||||||
{
|
{
|
||||||
|
@ -2592,18 +2581,69 @@ skip:
|
||||||
context.m_needed_objects.clear();
|
context.m_needed_objects.clear();
|
||||||
uint64_t added = 0;
|
uint64_t added = 0;
|
||||||
std::unordered_set<crypto::hash> blocks_found;
|
std::unordered_set<crypto::hash> blocks_found;
|
||||||
|
bool first = true;
|
||||||
|
bool expect_unknown = false;
|
||||||
for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
|
for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!blocks_found.insert(arg.m_block_ids[i]).second)
|
if (!blocks_found.insert(arg.m_block_ids[i]).second)
|
||||||
{
|
{
|
||||||
LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
|
LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
|
||||||
drop_connection(context, true, false);
|
drop_connection_with_score(context, 5, false);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
int where;
|
||||||
|
const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
|
||||||
|
if (first && !have_block)
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
|
||||||
|
drop_connection_with_score(context, 5, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
// after the first, blocks may be known or unknown, but if they are known,
|
||||||
|
// they should be at the same height if on the main chain
|
||||||
|
if (have_block)
|
||||||
|
{
|
||||||
|
switch (where)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case HAVE_BLOCK_INVALID:
|
||||||
|
LOG_ERROR_CCONTEXT("Block is invalid or known without known type, dropping connection");
|
||||||
|
drop_connection(context, true, false);
|
||||||
|
return 1;
|
||||||
|
case HAVE_BLOCK_MAIN_CHAIN:
|
||||||
|
if (expect_unknown)
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
|
||||||
|
drop_connection_with_score(context, 5, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (m_core.get_block_id_by_height(arg.start_height + i) != arg.m_block_ids[i])
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("Block is on the main chain, but not at the expected height, dropping connection");
|
||||||
|
drop_connection_with_score(context, 5, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HAVE_BLOCK_ALT_CHAIN:
|
||||||
|
if (expect_unknown)
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
|
||||||
|
drop_connection_with_score(context, 5, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
expect_unknown = true;
|
||||||
|
}
|
||||||
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
|
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
|
||||||
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
|
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
|
||||||
if (++added == n_use_blocks)
|
if (++added == n_use_blocks)
|
||||||
break;
|
break;
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
|
context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
|
||||||
|
|
||||||
|
|
|
@ -245,12 +245,17 @@ bool tests::proxy_core::init(const boost::program_options::variables_map& /*vm*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tests::proxy_core::have_block(const crypto::hash& id) {
|
bool tests::proxy_core::have_block_unlocked(const crypto::hash& id, int *where) {
|
||||||
if (m_hash2blkidx.end() == m_hash2blkidx.find(id))
|
if (m_hash2blkidx.end() == m_hash2blkidx.find(id))
|
||||||
return false;
|
return false;
|
||||||
|
if (where) *where = HAVE_BLOCK_MAIN_CHAIN;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tests::proxy_core::have_block(const crypto::hash& id, int *where) {
|
||||||
|
return have_block_unlocked(id, where);
|
||||||
|
}
|
||||||
|
|
||||||
void tests::proxy_core::build_short_history(std::list<crypto::hash> &m_history, const crypto::hash &m_start) {
|
void tests::proxy_core::build_short_history(std::list<crypto::hash> &m_history, const crypto::hash &m_start) {
|
||||||
m_history.push_front(get_block_hash(m_genesis));
|
m_history.push_front(get_block_hash(m_genesis));
|
||||||
/*std::unordered_map<crypto::hash, tests::block_index>::const_iterator cit = m_hash2blkidx.find(m_lastblk);
|
/*std::unordered_map<crypto::hash, tests::block_index>::const_iterator cit = m_hash2blkidx.find(m_lastblk);
|
||||||
|
|
|
@ -74,7 +74,8 @@ namespace tests
|
||||||
bool init(const boost::program_options::variables_map& vm);
|
bool init(const boost::program_options::variables_map& vm);
|
||||||
bool deinit(){return true;}
|
bool deinit(){return true;}
|
||||||
bool get_short_chain_history(std::list<crypto::hash>& ids);
|
bool get_short_chain_history(std::list<crypto::hash>& ids);
|
||||||
bool have_block(const crypto::hash& id);
|
bool have_block(const crypto::hash& id, int *where = NULL);
|
||||||
|
bool have_block_unlocked(const crypto::hash& id, int *where = NULL);
|
||||||
void get_blockchain_top(uint64_t& height, crypto::hash& top_id);
|
void get_blockchain_top(uint64_t& height, crypto::hash& top_id);
|
||||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
||||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
||||||
|
|
|
@ -55,7 +55,8 @@ public:
|
||||||
bool init(const boost::program_options::variables_map& vm) {return true ;}
|
bool init(const boost::program_options::variables_map& vm) {return true ;}
|
||||||
bool deinit(){return true;}
|
bool deinit(){return true;}
|
||||||
bool get_short_chain_history(std::list<crypto::hash>& ids) const { return true; }
|
bool get_short_chain_history(std::list<crypto::hash>& ids) const { return true; }
|
||||||
bool have_block(const crypto::hash& id) const {return true;}
|
bool have_block(const crypto::hash& id, int *where = NULL) const {return false;}
|
||||||
|
bool have_block_unlocked(const crypto::hash& id, int *where = NULL) const {return false;}
|
||||||
void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;}
|
void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;}
|
||||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
||||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
||||||
|
|
Loading…
Reference in a new issue