Merge pull request #5123
089c7637
cryptonote: rework block blob size sanity check (moneromooo-monero)
This commit is contained in:
commit
76fbcfe2dd
|
@ -1513,6 +1513,20 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool check_pruning() = 0;
|
virtual bool check_pruning() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the max block size
|
||||||
|
*/
|
||||||
|
virtual uint64_t get_max_block_size() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief add a new max block size
|
||||||
|
*
|
||||||
|
* The max block size will be the maximum of sz and the current block size
|
||||||
|
*
|
||||||
|
* @param: sz the block size
|
||||||
|
*/
|
||||||
|
|
||||||
|
virtual void add_max_block_size(uint64_t sz) = 0;
|
||||||
/**
|
/**
|
||||||
* @brief runs a function over all txpool transactions
|
* @brief runs a function over all txpool transactions
|
||||||
*
|
*
|
||||||
|
|
|
@ -2513,6 +2513,58 @@ std::vector<uint64_t> BlockchainLMDB::get_block_info_64bit_fields(uint64_t start
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t BlockchainLMDB::get_max_block_size()
|
||||||
|
{
|
||||||
|
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||||
|
check_open();
|
||||||
|
|
||||||
|
TXN_PREFIX_RDONLY();
|
||||||
|
RCURSOR(properties)
|
||||||
|
MDB_val_str(k, "max_block_size");
|
||||||
|
MDB_val v;
|
||||||
|
int result = mdb_cursor_get(m_cur_properties, &k, &v, MDB_SET);
|
||||||
|
if (result == MDB_NOTFOUND)
|
||||||
|
return std::numeric_limits<uint64_t>::max();
|
||||||
|
if (result)
|
||||||
|
throw0(DB_ERROR(lmdb_error("Failed to retrieve max block size: ", result).c_str()));
|
||||||
|
if (v.mv_size != sizeof(uint64_t))
|
||||||
|
throw0(DB_ERROR("Failed to retrieve or create max block size: unexpected value size"));
|
||||||
|
uint64_t max_block_size;
|
||||||
|
memcpy(&max_block_size, v.mv_data, sizeof(max_block_size));
|
||||||
|
TXN_POSTFIX_RDONLY();
|
||||||
|
return max_block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockchainLMDB::add_max_block_size(uint64_t sz)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||||
|
check_open();
|
||||||
|
mdb_txn_cursors *m_cursors = &m_wcursors;
|
||||||
|
|
||||||
|
CURSOR(properties)
|
||||||
|
|
||||||
|
MDB_val_str(k, "max_block_size");
|
||||||
|
MDB_val v;
|
||||||
|
int result = mdb_cursor_get(m_cur_properties, &k, &v, MDB_SET);
|
||||||
|
if (result && result != MDB_NOTFOUND)
|
||||||
|
throw0(DB_ERROR(lmdb_error("Failed to retrieve max block size: ", result).c_str()));
|
||||||
|
uint64_t max_block_size = 0;
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
if (v.mv_size != sizeof(uint64_t))
|
||||||
|
throw0(DB_ERROR("Failed to retrieve or create max block size: unexpected value size"));
|
||||||
|
memcpy(&max_block_size, v.mv_data, sizeof(max_block_size));
|
||||||
|
}
|
||||||
|
if (sz > max_block_size)
|
||||||
|
max_block_size = sz;
|
||||||
|
v.mv_data = (void*)&max_block_size;
|
||||||
|
v.mv_size = sizeof(max_block_size);
|
||||||
|
result = mdb_cursor_put(m_cur_properties, &k, &v, 0);
|
||||||
|
if (result)
|
||||||
|
throw0(DB_ERROR(lmdb_error("Failed to set max_block_size: ", result).c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<uint64_t> BlockchainLMDB::get_block_weights(uint64_t start_height, size_t count) const
|
std::vector<uint64_t> BlockchainLMDB::get_block_weights(uint64_t start_height, size_t count) const
|
||||||
{
|
{
|
||||||
return get_block_info_64bit_fields(start_height, count, offsetof(mdb_block_info, bi_weight));
|
return get_block_info_64bit_fields(start_height, count, offsetof(mdb_block_info, bi_weight));
|
||||||
|
|
|
@ -400,6 +400,9 @@ private:
|
||||||
|
|
||||||
std::vector<uint64_t> get_block_info_64bit_fields(uint64_t start_height, size_t count, off_t offset) const;
|
std::vector<uint64_t> get_block_info_64bit_fields(uint64_t start_height, size_t count, off_t offset) const;
|
||||||
|
|
||||||
|
uint64_t get_max_block_size();
|
||||||
|
void add_max_block_size(uint64_t sz);
|
||||||
|
|
||||||
// fix up anything that may be wrong due to past bugs
|
// fix up anything that may be wrong due to past bugs
|
||||||
virtual void fixup();
|
virtual void fixup();
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,9 @@ public:
|
||||||
virtual bool update_pruning() { return true; }
|
virtual bool update_pruning() { return true; }
|
||||||
virtual bool check_pruning() { return true; }
|
virtual bool check_pruning() { return true; }
|
||||||
virtual void prune_outputs(uint64_t amount) {}
|
virtual void prune_outputs(uint64_t amount) {}
|
||||||
|
|
||||||
|
virtual uint64_t get_max_block_size() { return 100000000; }
|
||||||
|
virtual void add_max_block_size(uint64_t sz) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,6 +422,8 @@ namespace cryptonote
|
||||||
FIELDS(*static_cast<block_header *>(this))
|
FIELDS(*static_cast<block_header *>(this))
|
||||||
FIELD(miner_tx)
|
FIELD(miner_tx)
|
||||||
FIELD(tx_hashes)
|
FIELD(tx_hashes)
|
||||||
|
if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
|
||||||
|
return false;
|
||||||
END_SERIALIZE()
|
END_SERIALIZE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -76,11 +76,6 @@ namespace cryptonote {
|
||||||
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
|
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
size_t get_max_block_size()
|
|
||||||
{
|
|
||||||
return CRYPTONOTE_MAX_BLOCK_SIZE;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------------------
|
|
||||||
size_t get_max_tx_size()
|
size_t get_max_tx_size()
|
||||||
{
|
{
|
||||||
return CRYPTONOTE_MAX_TX_SIZE;
|
return CRYPTONOTE_MAX_TX_SIZE;
|
||||||
|
|
|
@ -87,7 +87,6 @@ namespace cryptonote {
|
||||||
/* Cryptonote helper functions */
|
/* Cryptonote helper functions */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
size_t get_min_block_weight(uint8_t version);
|
size_t get_min_block_weight(uint8_t version);
|
||||||
size_t get_max_block_size();
|
|
||||||
size_t get_max_tx_size();
|
size_t get_max_tx_size();
|
||||||
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version);
|
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version);
|
||||||
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
|
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
|
||||||
|
|
|
@ -37,9 +37,9 @@
|
||||||
#define CRYPTONOTE_DNS_TIMEOUT_MS 20000
|
#define CRYPTONOTE_DNS_TIMEOUT_MS 20000
|
||||||
|
|
||||||
#define CRYPTONOTE_MAX_BLOCK_NUMBER 500000000
|
#define CRYPTONOTE_MAX_BLOCK_NUMBER 500000000
|
||||||
#define CRYPTONOTE_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used!
|
|
||||||
#define CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE 196608 //size of block (bytes) that is the maximum that miners will produce
|
#define CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE 196608 //size of block (bytes) that is the maximum that miners will produce
|
||||||
#define CRYPTONOTE_MAX_TX_SIZE 1000000000
|
#define CRYPTONOTE_MAX_TX_SIZE 1000000
|
||||||
|
#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
|
||||||
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
|
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
|
||||||
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
|
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
|
||||||
#define CURRENT_TRANSACTION_VERSION 2
|
#define CURRENT_TRANSACTION_VERSION 2
|
||||||
|
|
|
@ -3873,6 +3873,8 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
|
||||||
|
|
||||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||||
|
|
||||||
|
m_db->block_txn_start(false);
|
||||||
|
|
||||||
// when we reach this, the last hf version is not yet written to the db
|
// when we reach this, the last hf version is not yet written to the db
|
||||||
const uint64_t db_height = m_db->height();
|
const uint64_t db_height = m_db->height();
|
||||||
const uint8_t hf_version = get_current_hard_fork_version();
|
const uint8_t hf_version = get_current_hard_fork_version();
|
||||||
|
@ -3935,6 +3937,10 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
|
||||||
if (long_term_effective_median_block_weight)
|
if (long_term_effective_median_block_weight)
|
||||||
*long_term_effective_median_block_weight = m_long_term_effective_median_block_weight;
|
*long_term_effective_median_block_weight = m_long_term_effective_median_block_weight;
|
||||||
|
|
||||||
|
m_db->add_max_block_size(m_current_block_cumul_weight_limit);
|
||||||
|
|
||||||
|
m_db->block_txn_stop();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
|
@ -62,6 +62,9 @@ DISABLE_VS_WARNINGS(4355)
|
||||||
|
|
||||||
#define BAD_SEMANTICS_TXES_MAX_SIZE 100
|
#define BAD_SEMANTICS_TXES_MAX_SIZE 100
|
||||||
|
|
||||||
|
// basically at least how many bytes the block itself serializes to without the miner tx
|
||||||
|
#define BLOCK_SIZE_SANITY_LEEWAY 100
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
const command_line::arg_descriptor<bool, false> arg_testnet_on = {
|
const command_line::arg_descriptor<bool, false> arg_testnet_on = {
|
||||||
|
@ -1417,18 +1420,21 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
|
|
||||||
// load json & DNS checkpoints every 10min/hour respectively,
|
|
||||||
// and verify them with respect to what blocks we already have
|
|
||||||
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
|
|
||||||
|
|
||||||
bvc = boost::value_initialized<block_verification_context>();
|
bvc = boost::value_initialized<block_verification_context>();
|
||||||
if(block_blob.size() > get_max_block_size())
|
|
||||||
|
if (!check_incoming_block_size(block_blob))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected");
|
|
||||||
bvc.m_verifivation_failed = true;
|
bvc.m_verifivation_failed = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((size_t)-1) <= 0xffffffff && block_blob.size() >= 0x3fffffff)
|
||||||
|
MWARNING("This block's size is " << block_blob.size() << ", closing on the 32 bit limit");
|
||||||
|
|
||||||
|
// load json & DNS checkpoints every 10min/hour respectively,
|
||||||
|
// and verify them with respect to what blocks we already have
|
||||||
|
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
|
||||||
|
|
||||||
block lb;
|
block lb;
|
||||||
if (!b)
|
if (!b)
|
||||||
{
|
{
|
||||||
|
@ -1453,9 +1459,13 @@ namespace cryptonote
|
||||||
// block_blob
|
// block_blob
|
||||||
bool core::check_incoming_block_size(const blobdata& block_blob) const
|
bool core::check_incoming_block_size(const blobdata& block_blob) const
|
||||||
{
|
{
|
||||||
if(block_blob.size() > get_max_block_size())
|
// note: we assume block weight is always >= block blob size, so we check incoming
|
||||||
|
// blob size against the block weight limit, which acts as a sanity check without
|
||||||
|
// having to parse/weigh first; in fact, since the block blob is the block header
|
||||||
|
// plus the tx hashes, the weight will typically be much larger than the blob size
|
||||||
|
if(block_blob.size() > m_blockchain_storage.get_current_cumulative_block_weight_limit() + BLOCK_SIZE_SANITY_LEEWAY)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected");
|
LOG_PRINT_L1("WRONG BLOCK BLOB, sanity check failed on size " << block_blob.size() << ", rejected");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue