From 198f557d38da3212fed1f12c0113bf2c4633ff44 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 22 Sep 2015 20:35:19 +0100 Subject: [PATCH 1/7] blockchain: use different hard fork settings for testnet and mainnet --- src/cryptonote_core/blockchain.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 65d07dcf..c6e9b768 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -73,7 +73,7 @@ static const struct { uint8_t version; uint64_t height; time_t time; -} hard_forks[] = { +} mainnet_hard_forks[] = { // version 1 from the start of the blockchain { 1, 1, 1341378000 }, @@ -81,6 +81,15 @@ static const struct { { 2, 1009827, 1442763710 }, }; +static const struct { + uint8_t version; + uint64_t height; + time_t time; +} testnet_hard_forks[] = { + // version 1 from the start of the blockchain + { 1, 1, 1341378000 }, +}; + //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_db(), m_tx_pool(tx_pool), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), @@ -288,8 +297,15 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet) m_db = db; m_hardfork = new HardFork(*db); - for (size_t n = 0; n < sizeof(hard_forks) / sizeof(hard_forks[0]); ++n) - m_hardfork->add(hard_forks[n].version, hard_forks[n].height, hard_forks[n].time); + if (testnet) { + for (size_t n = 0; n < sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); ++n) + m_hardfork->add(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].time); + } + else + { + for (size_t n = 0; n < sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); ++n) + m_hardfork->add(mainnet_hard_forks[n].version, mainnet_hard_forks[n].height, mainnet_hard_forks[n].time); + } m_hardfork->init(); // if the blockchain is new, add the genesis block From 088bc56d796bbbd8f8faace42edb1b180b0f86ff Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Sep 2015 13:25:22 +0100 Subject: [PATCH 2/7] hardfork: change window semantics to not count the newly added block This allows knowing the hard fork a block must obey in order to be added to the blockchain. The previous semantics would use that new block's version vote to determine this hard fork, which made it impossible to use the rules to validate transactions entering the tx pool (and made it impossible to validate a block before adding it to the blockchain). --- src/cryptonote_core/hardfork.cpp | 25 ++++++++++++++++++++----- tests/unit_tests/hardfork.cpp | 23 +++++++++++++---------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp index d2e95b58..f4df1f9c 100644 --- a/src/cryptonote_core/hardfork.cpp +++ b/src/cryptonote_core/hardfork.cpp @@ -43,6 +43,10 @@ HardFork::HardFork(cryptonote::BlockchainDB &db, uint8_t original_version, time_ window_size(window_size), threshold_percent(threshold_percent) { + if (window_size == 0) + throw "window_size needs to be strictly positive"; + if (threshold_percent > 100) + throw "threshold_percent needs to be between 0 and 100"; } bool HardFork::add(uint8_t version, uint64_t height, time_t time) @@ -93,6 +97,8 @@ bool HardFork::add(const cryptonote::block &block, uint64_t height) if (!do_check(block)) return false; + db.set_hard_fork_version(height, heights[current_fork_index].version); + const uint8_t version = get_effective_version(block); while (versions.size() >= window_size) { @@ -105,16 +111,15 @@ bool HardFork::add(const cryptonote::block &block, uint64_t height) last_versions[version]++; versions.push_back(version); - uint8_t voted = get_voted_fork_index(height); + uint8_t voted = get_voted_fork_index(height + 1); if (voted > current_fork_index) { for (int v = heights[current_fork_index].version + 1; v <= heights[voted].version; ++v) { - db.set_hard_fork_starting_height(v, height); + // we reached the vote threshold with this block, next one will be forked + db.set_hard_fork_starting_height(v, height + 1); } current_fork_index = voted; } - db.set_hard_fork_version(height, heights[current_fork_index].version); - return true; } @@ -159,7 +164,7 @@ bool HardFork::reorganize_from_block_height(uint64_t height) for (size_t n = 0; n < 256; ++n) last_versions[n] = 0; - const uint64_t rescan_height = height >= (window_size - 1) ? height - (window_size - 1) : 0; + const uint64_t rescan_height = height >= (window_size - 1) ? height - (window_size -1) : 0; const uint8_t start_version = height == 0 ? original_version : db.get_hard_fork_version(height); while (heights[current_fork_index].version > start_version) { db.set_hard_fork_starting_height(heights[current_fork_index].version, std::numeric_limits::max()); @@ -171,6 +176,16 @@ bool HardFork::reorganize_from_block_height(uint64_t height) last_versions[v]++; versions.push_back(v); } + + uint8_t voted = get_voted_fork_index(height + 1); + if (voted > current_fork_index) { + for (int v = heights[current_fork_index].version + 1; v <= heights[voted].version; ++v) { + // we reached the vote threshold with this block, next one will be forked + db.set_hard_fork_starting_height(v, height + 1); + } + current_fork_index = voted; + } + const uint64_t bc_height = db.height(); for (uint64_t h = height + 1; h < bc_height; ++h) { add(db.get_block_from_height(h), h); diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index ad00ed60..a476eca2 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -238,7 +238,7 @@ TEST(steps_1, Success) } for (uint64_t h = 0; h < 10; ++h) { - ASSERT_EQ(hf.get(h), h+1); + ASSERT_EQ(hf.get(h), std::max(1,(int)h)); } } @@ -265,7 +265,7 @@ TEST(reorganize, Same) for (uint64_t rh = 0; rh < 20; ++rh) { hf.reorganize_from_block_height(rh); for (int hh = 0; hh < 20; ++hh) { - uint8_t version = hh >= (history-1) ? block_versions[hh - (history-1)] : 1; + uint8_t version = hh >= history ? block_versions[hh - history] : 1; ASSERT_EQ(hf.get(hh), version); } } @@ -285,8 +285,10 @@ TEST(reorganize, Changed) ASSERT_TRUE(hf.add(9, 6, 3)); hf.init(); + // fork 4 7 9 // index 0 1 2 3 4 5 6 7 8 9 static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; + static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9 }; for (uint64_t h = 0; h < 16; ++h) { db.add_block(mkblock(block_versions[h]), 0, 0, 0, crypto::hash()); ASSERT_TRUE (hf.add(db.get_block_from_height(h), h)); @@ -295,14 +297,13 @@ TEST(reorganize, Changed) for (uint64_t rh = 0; rh < 16; ++rh) { hf.reorganize_from_block_height(rh); for (int hh = 0; hh < 16; ++hh) { - uint8_t version = hh >= (history-1) ? block_versions[hh - (history-1)] : 1; - ASSERT_EQ(hf.get(hh), version); + ASSERT_EQ(hf.get(hh), expected_versions[hh]); } } // delay a bit for 9, and go back to 1 to check it stays at 9 static const uint8_t block_versions_new[] = { 1, 1, 4, 4, 7, 7, 4, 7, 7, 7, 9, 9, 9, 9, 9, 1 }; - static const uint8_t expected_versions_new[] = { 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 7, 7, 7, 9, 9, 9 }; + static const uint8_t expected_versions_new[] = { 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 7, 7, 7, 9, 9 }; for (uint64_t h = 3; h < 16; ++h) { db.remove_block(); } @@ -336,11 +337,13 @@ TEST(voting, threshold) db.add_block(mkblock(v), 0, 0, 0, crypto::hash()); bool ret = hf.add(db.get_block_from_height(h), h); if (h >= 8 && threshold == 87) { + // for threshold 87, we reach the treshold at height 7, so from height 8, hard fork to version 2, but 8 tries to add 1 ASSERT_FALSE(ret); } else { + // for threshold 88, we never reach the threshold ASSERT_TRUE(ret); - uint8_t expected = threshold == 88 ? 1 : h < 7 ? 1 : 2; + uint8_t expected = threshold == 88 ? 1 : h < 8 ? 1 : 2; ASSERT_EQ(hf.get(h), expected); } } @@ -370,7 +373,7 @@ TEST(new_blocks, denied) ASSERT_FALSE(hf.add(mkblock(1), 9)); // so this one can't get added ASSERT_TRUE(hf.add(mkblock(2), 10)); - ASSERT_EQ(hf.get_start_height(2), 8); + ASSERT_EQ(hf.get_start_height(2), 9); } TEST(new_version, early) @@ -428,8 +431,8 @@ TEST(reorganize, changed) ADD_TRUE(3, 7); ADD_TRUE(4, 8); ADD_TRUE(4, 9); - ASSERT_EQ(hf.get_start_height(2), 3); - ASSERT_EQ(hf.get_start_height(3), 8); + ASSERT_EQ(hf.get_start_height(2), 4); // reaches threshold 2 at height 3, so height 4 forks + ASSERT_EQ(hf.get_start_height(3), 9); ASSERT_EQ(hf.get_current_version(), 3); // pop a few blocks and check current version goes back down @@ -446,7 +449,7 @@ TEST(reorganize, changed) ADD_TRUE(2, 7); ADD_TRUE(2, 8); ADD_TRUE(2, 9); - ASSERT_EQ(hf.get_start_height(2), 3); // unchanged + ASSERT_EQ(hf.get_start_height(2), 4); // unchanged ASSERT_EQ(hf.get_current_version(), 2); // we did not bump to 3 this time ASSERT_EQ(hf.get_start_height(3), std::numeric_limits::max()); // not yet } From 4bbf944df083689aac23a35f78da0147852f54af Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 22 Sep 2015 20:43:19 +0100 Subject: [PATCH 3/7] blockchain: on hardfork 2, allow miners to claim less money than allowed So they can avoid dust if they so wish --- src/cryptonote_core/blockchain.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index c6e9b768..14ee3691 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -963,10 +963,14 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl LOG_PRINT_L1("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")"); return false; } - if(base_reward + fee != money_in_use) + // From hard fork 2, we allow a miner to claim less block reward than is allowed, in case a miner wants less dust + if (m_hardfork->get_current_version() < 2) { - LOG_PRINT_L1("coinbase transaction doesn't use full amount of block reward: spent: " << money_in_use << ", block reward " << base_reward + fee << "(" << base_reward << "+" << fee << ")"); - return false; + if(base_reward + fee != money_in_use) + { + LOG_PRINT_L1("coinbase transaction doesn't use full amount of block reward: spent: " << money_in_use << ", block reward " << base_reward + fee << "(" << base_reward << "+" << fee << ")"); + return false; + } } return true; } From fec98b8952f10424cf41e3d21ad1fc2d9ad84d83 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Sep 2015 14:06:00 +0100 Subject: [PATCH 4/7] hardfork: remove use of GNU extension for initializing object --- src/cryptonote_core/hardfork.cpp | 4 ++-- src/cryptonote_core/hardfork.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp index f4df1f9c..30c5d94c 100644 --- a/src/cryptonote_core/hardfork.cpp +++ b/src/cryptonote_core/hardfork.cpp @@ -64,7 +64,7 @@ bool HardFork::add(uint8_t version, uint64_t height, time_t time) if (time <= heights.back().time) return false; } - heights.push_back({version: version, height: height, time: time}); + heights.push_back(Params(version, height, time)); return true; } @@ -239,7 +239,7 @@ HardFork::State HardFork::get_state() const uint8_t HardFork::get(uint64_t height) const { CRITICAL_REGION_LOCAL(lock); - if (height > db.height()) { + if (height >= db.height()) { assert(false); return 255; } diff --git a/src/cryptonote_core/hardfork.h b/src/cryptonote_core/hardfork.h index bdac87f2..946e5feb 100644 --- a/src/cryptonote_core/hardfork.h +++ b/src/cryptonote_core/hardfork.h @@ -197,11 +197,12 @@ namespace cryptonote uint8_t original_version; - typedef struct { + struct Params { uint8_t version; uint64_t height; time_t time; - } Params; + Params(uint8_t version, uint64_t height, time_t time): version(version), height(height), time(time) {} + }; std::vector heights; std::deque versions; /* rolling window of the last N blocks' versions */ From 0a7421b60716051359f821b2540073ad27c141d3 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Sep 2015 16:22:57 +0100 Subject: [PATCH 5/7] hardfork: rescan speedup Add a block height before which version 1 is assumed Use DB transactions --- src/cryptonote_core/blockchain.cpp | 5 +++- src/cryptonote_core/hardfork.cpp | 41 ++++++++++++++++++++++-------- src/cryptonote_core/hardfork.h | 10 +++++--- tests/unit_tests/hardfork.cpp | 16 ++++++------ 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 14ee3691..ab420b04 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -80,6 +80,7 @@ static const struct { // version 2 can start from block 1009827, setup on the 20th of september { 2, 1009827, 1442763710 }, }; +static const uint64_t mainnet_hard_fork_version_1_till = 750000; static const struct { uint8_t version; @@ -89,6 +90,7 @@ static const struct { // version 1 from the start of the blockchain { 1, 1, 1341378000 }, }; +static const uint64_t testnet_hard_fork_version_1_till = 540000; //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : @@ -296,13 +298,14 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet) m_db = db; - m_hardfork = new HardFork(*db); if (testnet) { + m_hardfork = new HardFork(*db, 1, testnet_hard_fork_version_1_till); for (size_t n = 0; n < sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); ++n) m_hardfork->add(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].time); } else { + m_hardfork = new HardFork(*db, 1, mainnet_hard_fork_version_1_till); for (size_t n = 0; n < sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); ++n) m_hardfork->add(mainnet_hard_forks[n].version, mainnet_hard_forks[n].height, mainnet_hard_forks[n].time); } diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp index 30c5d94c..4b40a4cf 100644 --- a/src/cryptonote_core/hardfork.cpp +++ b/src/cryptonote_core/hardfork.cpp @@ -35,9 +35,10 @@ using namespace cryptonote; -HardFork::HardFork(cryptonote::BlockchainDB &db, uint8_t original_version, time_t forked_time, time_t update_time, uint64_t window_size, int threshold_percent): +HardFork::HardFork(cryptonote::BlockchainDB &db, uint8_t original_version, uint64_t original_version_till_height, time_t forked_time, time_t update_time, uint64_t window_size, int threshold_percent): db(db), original_version(original_version), + original_version_till_height(original_version_till_height), forked_time(forked_time), update_time(update_time), window_size(window_size), @@ -68,9 +69,8 @@ bool HardFork::add(uint8_t version, uint64_t height, time_t time) return true; } -uint8_t HardFork::get_effective_version(const cryptonote::block &block) const +uint8_t HardFork::get_effective_version(uint8_t version) const { - uint8_t version = block.major_version; if (!heights.empty()) { uint8_t max_version = heights.back().version; if (version > max_version) @@ -79,27 +79,27 @@ uint8_t HardFork::get_effective_version(const cryptonote::block &block) const return version; } -bool HardFork::do_check(const cryptonote::block &block) const +bool HardFork::do_check(uint8_t version) const { - return block.major_version >= heights[current_fork_index].version; + return version >= heights[current_fork_index].version; } bool HardFork::check(const cryptonote::block &block) const { CRITICAL_REGION_LOCAL(lock); - return do_check(block); + return do_check(block.major_version); } -bool HardFork::add(const cryptonote::block &block, uint64_t height) +bool HardFork::add(uint8_t block_version, uint64_t height) { CRITICAL_REGION_LOCAL(lock); - if (!do_check(block)) + if (!do_check(block_version)) return false; db.set_hard_fork_version(height, heights[current_fork_index].version); - const uint8_t version = get_effective_version(block); + const uint8_t version = get_effective_version(block_version); while (versions.size() >= window_size) { const uint8_t old_version = versions.front(); @@ -123,6 +123,11 @@ bool HardFork::add(const cryptonote::block &block, uint64_t height) return true; } +bool HardFork::add(const cryptonote::block &block, uint64_t height) +{ + return add(block.major_version, height); +} + void HardFork::init() { CRITICAL_REGION_LOCAL(lock); @@ -154,12 +159,24 @@ void HardFork::init() LOG_PRINT_L1("reorganization done"); } +uint8_t HardFork::get_block_version(uint64_t height) const +{ + if (height <= original_version_till_height) + return original_version; + + const cryptonote::block &block = db.get_block_from_height(height); + return block.major_version; +} + bool HardFork::reorganize_from_block_height(uint64_t height) { CRITICAL_REGION_LOCAL(lock); if (height >= db.height()) return false; + //db.set_batch_transactions(true); + //db.batch_start(); + versions.clear(); for (size_t n = 0; n < 256; ++n) @@ -172,7 +189,7 @@ bool HardFork::reorganize_from_block_height(uint64_t height) } for (uint64_t h = rescan_height; h <= height; ++h) { cryptonote::block b = db.get_block_from_height(h); - const uint8_t v = get_effective_version(b); + const uint8_t v = get_effective_version(b.major_version); last_versions[v]++; versions.push_back(v); } @@ -188,9 +205,11 @@ bool HardFork::reorganize_from_block_height(uint64_t height) const uint64_t bc_height = db.height(); for (uint64_t h = height + 1; h < bc_height; ++h) { - add(db.get_block_from_height(h), h); + add(get_block_version(h), h); } + //db.batch_stop(); + return true; } diff --git a/src/cryptonote_core/hardfork.h b/src/cryptonote_core/hardfork.h index 946e5feb..2fcc2d53 100644 --- a/src/cryptonote_core/hardfork.h +++ b/src/cryptonote_core/hardfork.h @@ -44,6 +44,7 @@ namespace cryptonote Ready, } State; + static const uint64_t DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT = 0; // <= actual height static const time_t DEFAULT_FORKED_TIME = 31557600; // a year in seconds static const time_t DEFAULT_UPDATE_TIME = 31557600 / 2; static const uint64_t DEFAULT_WINDOW_SIZE = 50; // supermajority window check length @@ -58,7 +59,7 @@ namespace cryptonote * @param window_size the size of the window in blocks to consider for version voting * @param threshold_percent the size of the majority in percents */ - HardFork(cryptonote::BlockchainDB &db, uint8_t original_version = 1, time_t forked_time = DEFAULT_FORKED_TIME, time_t update_time = DEFAULT_UPDATE_TIME, uint64_t window_size = DEFAULT_WINDOW_SIZE, int threshold_percent = DEFAULT_THRESHOLD_PERCENT); + HardFork(cryptonote::BlockchainDB &db, uint8_t original_version = 1, uint64_t original_version_till_height = DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT, time_t forked_time = DEFAULT_FORKED_TIME, time_t update_time = DEFAULT_UPDATE_TIME, uint64_t window_size = DEFAULT_WINDOW_SIZE, int threshold_percent = DEFAULT_THRESHOLD_PERCENT); /** * @brief add a new hardfork height @@ -182,9 +183,11 @@ namespace cryptonote private: - bool do_check(const cryptonote::block &block) const; + uint8_t get_block_version(uint64_t height) const; + bool do_check(uint8_t version) const; int get_voted_fork_index(uint64_t height) const; - uint8_t get_effective_version(const cryptonote::block &block) const; + uint8_t get_effective_version(uint8_t version) const; + bool add(uint8_t block_version, uint64_t height); private: @@ -196,6 +199,7 @@ namespace cryptonote int threshold_percent; uint8_t original_version; + uint64_t original_version_till_height; struct Params { uint8_t version; diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index a476eca2..25d03b70 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -196,7 +196,7 @@ TEST(states, Success) TEST(steps_asap, Success) { TestDB db; - HardFork hf(db, 1,1,1,1); + HardFork hf(db, 1,0,1,1,1); // v h t ASSERT_TRUE(hf.add(1, 0, 0)); @@ -225,7 +225,7 @@ TEST(steps_asap, Success) TEST(steps_1, Success) { TestDB db; - HardFork hf(db, 1,1,1,1); + HardFork hf(db, 1,0,1,1,1); ASSERT_TRUE(hf.add(1, 0, 0)); for (int n = 1 ; n < 10; ++n) @@ -246,7 +246,7 @@ TEST(reorganize, Same) { for (int history = 1; history <= 12; ++history) { TestDB db; - HardFork hf(db, 1, 1, 1, history, 100); + HardFork hf(db, 1, 0, 1, 1, history, 100); // v h t ASSERT_TRUE(hf.add(1, 0, 0)); @@ -276,7 +276,7 @@ TEST(reorganize, Changed) { int history = 4; TestDB db; - HardFork hf(db, 1, 1, 1, 4, 100); + HardFork hf(db, 1, 0, 1, 1, 4, 100); // v h t ASSERT_TRUE(hf.add(1, 0, 0)); @@ -325,7 +325,7 @@ TEST(voting, threshold) { for (int threshold = 87; threshold <= 88; ++threshold) { TestDB db; - HardFork hf(db, 1, 1, 1, 8, threshold); + HardFork hf(db, 1, 0, 1, 1, 8, threshold); // v h t ASSERT_TRUE(hf.add(1, 0, 0)); @@ -353,7 +353,7 @@ TEST(voting, threshold) TEST(new_blocks, denied) { TestDB db; - HardFork hf(db, 1, 1, 1, 4, 50); + HardFork hf(db, 1, 0, 1, 1, 4, 50); // v h t ASSERT_TRUE(hf.add(1, 0, 0)); @@ -379,7 +379,7 @@ TEST(new_blocks, denied) TEST(new_version, early) { TestDB db; - HardFork hf(db, 1, 1, 1, 4, 50); + HardFork hf(db, 1, 0, 1, 1, 4, 50); // v h t ASSERT_TRUE(hf.add(1, 0, 0)); @@ -402,7 +402,7 @@ TEST(new_version, early) TEST(reorganize, changed) { TestDB db; - HardFork hf(db, 1, 1, 1, 4, 50); + HardFork hf(db, 1, 0, 1, 1, 4, 50); // v h t ASSERT_TRUE(hf.add(1, 0, 0)); From 434e0f42e71a4c064baa5df87081f6b0e49daa6b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Sep 2015 17:56:43 +0100 Subject: [PATCH 6/7] hardfork: make the voting window a week --- src/cryptonote_core/hardfork.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptonote_core/hardfork.h b/src/cryptonote_core/hardfork.h index 2fcc2d53..6b98b9fa 100644 --- a/src/cryptonote_core/hardfork.h +++ b/src/cryptonote_core/hardfork.h @@ -47,7 +47,7 @@ namespace cryptonote static const uint64_t DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT = 0; // <= actual height static const time_t DEFAULT_FORKED_TIME = 31557600; // a year in seconds static const time_t DEFAULT_UPDATE_TIME = 31557600 / 2; - static const uint64_t DEFAULT_WINDOW_SIZE = 50; // supermajority window check length + static const uint64_t DEFAULT_WINDOW_SIZE = 10080; // supermajority window check length - a week static const int DEFAULT_THRESHOLD_PERCENT = 80; /** From 33affd2d17b8b207ef50331b21e4dad08c97146d Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Sep 2015 17:57:01 +0100 Subject: [PATCH 7/7] blockchain: on hardfork 2, require mixin 2 at least if possible --- src/cryptonote_core/blockchain.cpp | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index ab420b04..3d96f6f5 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1998,6 +1998,43 @@ bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_bloc return true; } + // from hard fork 2, we require mixin at least 2 unless one output cannot mix with 2 others + // if one output cannot mix with 2 others, we accept at most 1 output that can mix + if (m_hardfork->get_current_version() >= 2) + { + size_t n_unmixable = 0, n_mixable = 0; + size_t mixin = std::numeric_limits::max(); + for (const auto& txin : tx.vin) + { + // non txin_to_key inputs will be rejected below + if (txin.type() == typeid(txin_to_key)) + { + const txin_to_key& in_to_key = boost::get(txin); + uint64_t n_outputs = m_db->get_num_outputs(in_to_key.amount); + // n_outputs includes the output we're considering + if (n_outputs <= 2) + ++n_unmixable; + else + ++n_mixable; + if (in_to_key.key_offsets.size() - 1 < mixin) + mixin = in_to_key.key_offsets.size() - 1; + } + } + if (mixin < 2) + { + if (n_unmixable == 0) + { + LOG_PRINT_L1("Tx " << get_transaction_hash(tx) << " has too low mixin (" << mixin << "), and no unmixable inputs"); + return false; + } + if (n_mixable > 1) + { + LOG_PRINT_L1("Tx " << get_transaction_hash(tx) << " has too low mixin (" << mixin << "), and more than one mixable input with unmixable inputs"); + return false; + } + } + } + auto it = m_check_txin_table.find(tx_prefix_hash); if(it == m_check_txin_table.end()) {