Skip to content

Commit bb5bc6f

Browse files
committed
Include n tree layers in PoW block hash as well
1 parent a34e6a2 commit bb5bc6f

21 files changed

+87
-59
lines changed

src/blockchain_db/blockchain_db.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1820,7 +1820,7 @@ class BlockchainDB
18201820
virtual bool audit_tree(const uint64_t expected_n_leaf_tuples) const = 0;
18211821
virtual uint64_t get_n_leaf_tuples() const = 0;
18221822
virtual uint64_t get_block_n_leaf_tuples(const uint64_t block_idx) const = 0;
1823-
virtual std::size_t get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const = 0;
1823+
virtual uint8_t get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const = 0;
18241824

18251825
/**
18261826
* @brief return custom timelocked outputs after the provided block idx

src/blockchain_db/lmdb/db_lmdb.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,7 +2116,7 @@ uint64_t BlockchainLMDB::get_block_n_leaf_tuples(const uint64_t block_idx) const
21162116
return n_leaf_tuples;
21172117
}
21182118

2119-
std::size_t BlockchainLMDB::get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const
2119+
uint8_t BlockchainLMDB::get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const
21202120
{
21212121
const std::vector<crypto::ec_point> tree_edge = this->get_tree_edge(blk_idx);
21222122
if (tree_edge.empty())
@@ -2125,7 +2125,8 @@ std::size_t BlockchainLMDB::get_tree_root_at_blk_idx(const uint64_t blk_idx, cry
21252125
return 0;
21262126
}
21272127
tree_root_out = tree_edge.back();
2128-
return tree_edge.size();
2128+
static_assert(sizeof(std::size_t) >= sizeof(uint8_t), "unexpected size of size_t");
2129+
return (uint8_t) tree_edge.size();
21292130
}
21302131

21312132
bool BlockchainLMDB::audit_tree(const uint64_t expected_n_leaf_tuples) const

src/blockchain_db/lmdb/db_lmdb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ class BlockchainLMDB : public BlockchainDB
457457

458458
uint64_t get_block_n_leaf_tuples(uint64_t block_idx) const;
459459

460-
virtual std::size_t get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const;
460+
virtual uint8_t get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const;
461461

462462
std::vector<crypto::ec_point> get_tree_edge(uint64_t block_id) const;
463463

src/blockchain_db/testdb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class BaseTestDB: public cryptonote::BlockchainDB {
122122
virtual std::pair<uint64_t, fcmp_pp::curve_trees::PathBytes> get_last_path(const uint64_t block_idx) const override { return {0, fcmp_pp::curve_trees::PathBytes{}}; };
123123
virtual void trim_tree(const uint64_t new_n_leaf_tuples, const uint64_t trim_block_id) override {};
124124
virtual bool audit_tree(const uint64_t expected_n_leaf_tuples) const override { return false; };
125-
virtual std::size_t get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const override { return {}; };
125+
virtual uint8_t get_tree_root_at_blk_idx(const uint64_t blk_idx, crypto::ec_point &tree_root_out) const override { return {}; };
126126
virtual uint64_t get_n_leaf_tuples() const override { return 0; };
127127
virtual uint64_t get_block_n_leaf_tuples(const uint64_t block_idx) const override { return 0; };
128128
virtual fcmp_pp::curve_trees::OutsByLastLockedBlock get_custom_timelocked_outputs(uint64_t start_block_idx) const override { return {{}}; };

src/cryptonote_basic/cryptonote_basic.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,8 +478,8 @@ namespace cryptonote
478478

479479
public:
480480
block(): block_header(), hash_valid(false) {}
481-
block(const block &b): block_header(b), hash_valid(false), miner_tx(b.miner_tx), tx_hashes(b.tx_hashes), fcmp_pp_tree_root(b.fcmp_pp_tree_root) { if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } }
482-
block &operator=(const block &b) { block_header::operator=(b); hash_valid = false; miner_tx = b.miner_tx; tx_hashes = b.tx_hashes; fcmp_pp_tree_root = b.fcmp_pp_tree_root; if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } return *this; }
481+
block(const block &b): block_header(b), hash_valid(false), miner_tx(b.miner_tx), tx_hashes(b.tx_hashes), fcmp_pp_n_tree_layers(b.fcmp_pp_n_tree_layers), fcmp_pp_tree_root(b.fcmp_pp_tree_root) { if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } }
482+
block &operator=(const block &b) { block_header::operator=(b); hash_valid = false; miner_tx = b.miner_tx; tx_hashes = b.tx_hashes; fcmp_pp_n_tree_layers = b.fcmp_pp_n_tree_layers; fcmp_pp_tree_root = b.fcmp_pp_tree_root; if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } return *this; }
483483
void invalidate_hashes() { set_hash_valid(false); }
484484
bool is_hash_valid() const { return hash_valid.load(std::memory_order_acquire); }
485485
void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
@@ -488,6 +488,8 @@ namespace cryptonote
488488
transaction miner_tx;
489489
std::vector<crypto::hash> tx_hashes;
490490

491+
// We include both n tree layers and the root so SPV nodes can verify FCMP++ proofs
492+
uint8_t fcmp_pp_n_tree_layers;
491493
crypto::ec_point fcmp_pp_tree_root;
492494

493495
// hash cash
@@ -503,7 +505,12 @@ namespace cryptonote
503505
if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
504506
return false;
505507
if (major_version >= HF_VERSION_FCMP_PLUS_PLUS)
508+
{
509+
FIELD(fcmp_pp_n_tree_layers)
510+
if (fcmp_pp_n_tree_layers > FCMP_PLUS_PLUS_MAX_LAYERS)
511+
return false;
506512
FIELD(fcmp_pp_tree_root)
513+
}
507514
END_SERIALIZE()
508515
};
509516

src/cryptonote_basic/cryptonote_boost_serialization.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,10 @@ namespace boost
203203
a & b.miner_tx;
204204
a & b.tx_hashes;
205205
if (b.major_version >= HF_VERSION_FCMP_PLUS_PLUS)
206+
{
207+
a & b.fcmp_pp_n_tree_layers;
206208
a & b.fcmp_pp_tree_root;
209+
}
207210
}
208211

209212
template <class Archive>

src/cryptonote_basic/cryptonote_format_utils.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,8 +1476,8 @@ namespace cryptonote
14761476
blobdata get_block_hashing_blob(const block& b)
14771477
{
14781478
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
1479-
crypto::hash tree_root_hash = get_tree_hash(b);
1480-
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
1479+
crypto::hash block_content_hash = get_block_content_hash(b);
1480+
blob.append(reinterpret_cast<const char*>(&block_content_hash), sizeof(block_content_hash));
14811481
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
14821482
return blob;
14831483
}
@@ -1619,20 +1619,24 @@ namespace cryptonote
16191619
return t_serializable_object_to_blob(tx, b_blob);
16201620
}
16211621
//---------------------------------------------------------------
1622-
crypto::hash get_tree_hash(const block& b)
1622+
crypto::hash get_block_content_hash(const block& b)
16231623
{
16241624
std::vector<crypto::hash> hashes;
1625-
hashes.reserve(1 + 1 + b.tx_hashes.size());
1626-
// 1. FCMP++ root
1625+
hashes.reserve(1 + 1 + 1 + b.tx_hashes.size());
1626+
// 1. n tree layers in FCMP++ tree
1627+
static_assert(sizeof(crypto::hash) >= sizeof(uint8_t), "crypto::hash is too small");
1628+
if (b.major_version >= HF_VERSION_FCMP_PLUS_PLUS)
1629+
hashes.push_back(crypto::hash{static_cast<char>(b.fcmp_pp_n_tree_layers)});
1630+
// 2. FCMP++ tree root
16271631
static_assert(sizeof(crypto::hash) == sizeof(crypto::ec_point), "expected sizeof hash == sizeof ec_point");
16281632
if (b.major_version >= HF_VERSION_FCMP_PLUS_PLUS)
16291633
hashes.push_back((crypto::hash&)b.fcmp_pp_tree_root);
1630-
// 2. Miner tx
1634+
// 3. Miner tx
16311635
crypto::hash h = null_hash;
16321636
size_t bl_sz = 0;
16331637
CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.miner_tx, h, bl_sz), "Failed to calculate transaction hash");
16341638
hashes.push_back(h);
1635-
// 3. All other txs
1639+
// 4. All other txs
16361640
for(auto& th: b.tx_hashes)
16371641
hashes.push_back(th);
16381642
return get_tree_hash(hashes);

src/cryptonote_basic/cryptonote_format_utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ namespace cryptonote
260260
bool block_to_blob(const block& b, blobdata& b_blob);
261261
blobdata tx_to_blob(const transaction& b);
262262
bool tx_to_blob(const transaction& b, blobdata& b_blob);
263-
crypto::hash get_tree_hash(const block& b);
263+
crypto::hash get_block_content_hash(const block& b);
264264
bool is_valid_decomposed_amount(uint64_t amount);
265265
void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached);
266266

src/cryptonote_core/blockchain.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,7 +1664,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
16641664

16651665
if (b.major_version >= HF_VERSION_FCMP_PLUS_PLUS)
16661666
{
1667-
m_db->get_tree_root_at_blk_idx(height, b.fcmp_pp_tree_root);
1667+
b.fcmp_pp_n_tree_layers = m_db->get_tree_root_at_blk_idx(height, b.fcmp_pp_tree_root);
16681668
}
16691669

16701670
size_t txs_weight;
@@ -1800,21 +1800,20 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
18001800
return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, cumulative_weight, ex_nonce, seed_height, seed_hash);
18011801
}
18021802
//------------------------------------------------------------------
1803-
bool Blockchain::get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::ec_point& fcmp_pp_tree_root, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog)
1803+
bool Blockchain::get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, uint8_t& fcmp_pp_n_tree_layers, crypto::ec_point& fcmp_pp_tree_root, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog)
18041804
{
18051805
prev_id = m_db->top_block_hash(&height);
18061806
++height;
18071807

18081808
major_version = m_hardfork->get_ideal_version(height);
18091809

1810-
const uint8_t cur_version = m_hardfork->get_current_version();
1811-
1810+
fcmp_pp_n_tree_layers = 0;
18121811
fcmp_pp_tree_root = crypto::ec_point{};
1813-
if (cur_version >= HF_VERSION_FCMP_PLUS_PLUS)
1814-
m_db->get_tree_root_at_blk_idx(height, fcmp_pp_tree_root);
1812+
if (major_version >= HF_VERSION_FCMP_PLUS_PLUS)
1813+
fcmp_pp_n_tree_layers = m_db->get_tree_root_at_blk_idx(height, fcmp_pp_tree_root);
18151814

18161815
seed_hash = crypto::null_hash;
1817-
if (cur_version >= RX_BLOCK_VERSION)
1816+
if (major_version >= RX_BLOCK_VERSION)
18181817
{
18191818
uint64_t seed_height, next_height;
18201819
crypto::rx_seedheights(height, &seed_height, &next_height);
@@ -2605,12 +2604,11 @@ static bool get_fcmp_tx_tree_root(const BlockchainDB *db, const cryptonote::tran
26052604
"tx included reference block that was too high");
26062605

26072606
// Get the tree root and n tree layers at provided block
2608-
const std::size_t n_tree_layers = db->get_tree_root_at_blk_idx(tx.rct_signatures.p.reference_block, tree_root_out);
2607+
const uint8_t n_tree_layers = db->get_tree_root_at_blk_idx(tx.rct_signatures.p.reference_block, tree_root_out);
26092608

26102609
// Make sure the provided n tree layers matches expected
26112610
// IMPORTANT!
2612-
static_assert(sizeof(std::size_t) >= sizeof(uint8_t), "unexpected size of size_t");
2613-
CHECK_AND_ASSERT_MES((std::size_t)tx.rct_signatures.p.n_tree_layers == n_tree_layers, false,
2611+
CHECK_AND_ASSERT_MES(tx.rct_signatures.p.n_tree_layers == n_tree_layers, false,
26142612
"tx included incorrect number of tree layers");
26152613

26162614
return true;
@@ -4354,14 +4352,14 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
43544352

43554353
TIME_MEASURE_START(t3);
43564354

4357-
// Make sure the block uses the correct FCMP++ tree root
4355+
// Make sure the block uses the correct FCMP++ tree root and n tree layers
43584356
if (hf_version >= HF_VERSION_FCMP_PLUS_PLUS)
43594357
{
43604358
crypto::ec_point fcmp_pp_tree_root;
4361-
m_db->get_tree_root_at_blk_idx(blockchain_height, fcmp_pp_tree_root);
4362-
if (bl.fcmp_pp_tree_root != fcmp_pp_tree_root)
4359+
const uint8_t n_tree_layers = m_db->get_tree_root_at_blk_idx(blockchain_height, fcmp_pp_tree_root);
4360+
if (bl.fcmp_pp_n_tree_layers != n_tree_layers || bl.fcmp_pp_tree_root != fcmp_pp_tree_root)
43634361
{
4364-
MERROR_VER("Block with id: " << id << " used incorrect FCMP++ tree root");
4362+
MERROR_VER("Block with id: " << id << " used incorrect FCMP++ n tree layers or tree root");
43654363
bvc.m_verifivation_failed = true;
43664364
goto leave;
43674365
}
@@ -5982,13 +5980,14 @@ void Blockchain::send_miner_notifications(uint64_t height, const crypto::hash &s
59825980
std::vector<tx_block_template_backlog_entry> tx_backlog;
59835981
m_tx_pool.get_block_template_backlog(tx_backlog);
59845982

5983+
uint8_t fcmp_pp_n_tree_layers = 0;
59855984
crypto::ec_point fcmp_pp_tree_root{};
5986-
if (m_hardfork->get_current_version() >= HF_VERSION_FCMP_PLUS_PLUS)
5987-
m_db->get_tree_root_at_blk_idx(height, fcmp_pp_tree_root);
5985+
if (major_version >= HF_VERSION_FCMP_PLUS_PLUS)
5986+
fcmp_pp_n_tree_layers = m_db->get_tree_root_at_blk_idx(height, fcmp_pp_tree_root);
59885987

59895988
for (const auto& notifier : m_miner_notifiers)
59905989
{
5991-
notifier(major_version, height, prev_id, fcmp_pp_tree_root, seed_hash, diff, median_weight, already_generated_coins, tx_backlog);
5990+
notifier(major_version, height, prev_id, fcmp_pp_n_tree_layers, fcmp_pp_tree_root, seed_hash, diff, median_weight, already_generated_coins, tx_backlog);
59925991
}
59935992
}
59945993

src/cryptonote_core/blockchain.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ namespace cryptonote
9494

9595
typedef boost::function<void(std::vector<txpool_event>)> TxpoolNotifyCallback;
9696
typedef boost::function<void(uint64_t /* height */, epee::span<const block> /* blocks */)> BlockNotifyCallback;
97-
typedef boost::function<void(uint8_t /* major_version */, uint64_t /* height */, const crypto::hash& /* prev_id */, const crypto::ec_point& /* fcmp_pp_tree_root */, const crypto::hash& /* seed_hash */, difficulty_type /* diff */, uint64_t /* median_weight */, uint64_t /* already_generated_coins */, const std::vector<tx_block_template_backlog_entry>& /* tx_backlog */)> MinerNotifyCallback;
97+
typedef boost::function<void(uint8_t /* major_version */, uint64_t /* height */, const crypto::hash& /* prev_id */, const uint8_t& /*fcmp_pp_n_tree_layers*/, const crypto::ec_point& /* fcmp_pp_tree_root */, const crypto::hash& /* seed_hash */, difficulty_type /* diff */, uint64_t /* median_weight */, uint64_t /* already_generated_coins */, const std::vector<tx_block_template_backlog_entry>& /* tx_backlog */)> MinerNotifyCallback;
9898

9999
/************************************************************************/
100100
/* */
@@ -396,6 +396,7 @@ namespace cryptonote
396396
* @param major_version current hardfork version
397397
* @param height current blockchain height
398398
* @param prev_id hash of the top block
399+
* @param fcmp_pp_n_tree_layers number of layers in the FCMP++ curve tree
399400
* @param fcmp_pp_tree_root FCMP++ root as of when this next block enters the chain
400401
* @param seed_hash seed hash used for RandomX initialization
401402
* @param difficulty current mining difficulty
@@ -405,7 +406,7 @@ namespace cryptonote
405406
*
406407
* @return true if block template filled in successfully, else false
407408
*/
408-
bool get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::ec_point& fcmp_pp_tree_root, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog);
409+
bool get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, uint8_t& fcmp_pp_n_tree_layers, crypto::ec_point& fcmp_pp_tree_root, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog);
409410

410411
/**
411412
* @brief checks if a block is known about with a given hash

0 commit comments

Comments
 (0)