aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2019-04-11 12:41:07 +0200
committerRiccardo Spagni <ric@spagni.net>2019-04-11 12:41:07 +0200
commit76fbcfe2ddf597b4d8f6d2f5e6f387d57db427eb (patch)
tree4d9fdf15d9e1eab2482dd11e3c8d2e69864e1765
parentMerge pull request #4939 (diff)
parentcryptonote: rework block blob size sanity check (diff)
downloadmonero-76fbcfe2ddf597b4d8f6d2f5e6f387d57db427eb.tar.xz
Merge pull request #5123
089c7637 cryptonote: rework block blob size sanity check (moneromooo-monero)
-rw-r--r--src/blockchain_db/blockchain_db.h14
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp52
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h3
-rw-r--r--src/blockchain_db/testdb.h3
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp5
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h1
-rw-r--r--src/cryptonote_config.h4
-rw-r--r--src/cryptonote_core/blockchain.cpp6
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp26
10 files changed, 100 insertions, 16 deletions
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index d2fe39fc2..2c40b5a78 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1514,6 +1514,20 @@ public:
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
*
* The subclass should run the passed function for each txpool tx it has
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 9f71fd068..a07e9ac55 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -2513,6 +2513,58 @@ std::vector<uint64_t> BlockchainLMDB::get_block_info_64bit_fields(uint64_t start
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
{
return get_block_info_64bit_fields(start_height, count, offsetof(mdb_block_info, bi_weight));
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 2f89b77ac..f6b00817d 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -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;
+ 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
virtual void fixup();
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 7916364c5..04fad26a4 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -149,6 +149,9 @@ public:
virtual bool update_pruning() { return true; }
virtual bool check_pruning() { return true; }
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) { }
};
}
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 03caafbb0..20d92bdf1 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -422,6 +422,8 @@ namespace cryptonote
FIELDS(*static_cast<block_header *>(this))
FIELD(miner_tx)
FIELD(tx_hashes)
+ if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
+ return false;
END_SERIALIZE()
};
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp
index e336cc1d1..d8de65b81 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.cpp
+++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp
@@ -76,11 +76,6 @@ namespace cryptonote {
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()
{
return CRYPTONOTE_MAX_TX_SIZE;
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index 036273f0e..c7198a16f 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -87,7 +87,6 @@ namespace cryptonote {
/* Cryptonote helper functions */
/************************************************************************/
size_t get_min_block_weight(uint8_t version);
- size_t get_max_block_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);
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index b6087de22..56b6a63b7 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -37,9 +37,9 @@
#define CRYPTONOTE_DNS_TIMEOUT_MS 20000
#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_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_MINED_MONEY_UNLOCK_WINDOW 60
#define CURRENT_TRANSACTION_VERSION 2
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 73c60760b..503267a1a 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -3873,6 +3873,8 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
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
const uint64_t db_height = m_db->height();
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)
*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;
}
//------------------------------------------------------------------
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 8ab7d174c..6b0052dc0 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -62,6 +62,9 @@ DISABLE_VS_WARNINGS(4355)
#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
{
const command_line::arg_descriptor<bool, false> arg_testnet_on = {
@@ -1417,18 +1420,21 @@ namespace cryptonote
{
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>();
- 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;
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;
if (!b)
{
@@ -1453,9 +1459,13 @@ namespace cryptonote
// block_blob
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 true;