251 lines
9.9 KiB
C++
251 lines
9.9 KiB
C++
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
|
//
|
|
// This file is part of Bytecoin.
|
|
//
|
|
// Bytecoin is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Bytecoin is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "upgrade.h"
|
|
|
|
using namespace epee;
|
|
using namespace cryptonote;
|
|
|
|
namespace {
|
|
bool makeBlocks(std::vector<test_event_entry>& events, test_generator& generator, Block& lastBlock,
|
|
const Block& parentBlock, const cryptonote::account_base& minerAcc, size_t count,
|
|
uint8_t majorVersion, uint8_t minorVersion) {
|
|
cryptonote::Block prevBlock = parentBlock;
|
|
for (size_t i = 0; i < count; ++i) {
|
|
cryptonote::Block b;
|
|
bool r = generator.constructBlockManually(b, prevBlock, minerAcc, test_generator::bf_major_ver | test_generator::bf_minor_ver,
|
|
majorVersion, minorVersion);
|
|
if (!r) {
|
|
return false;
|
|
} else {
|
|
prevBlock = b;
|
|
events.push_back(b);
|
|
}
|
|
}
|
|
|
|
lastBlock = prevBlock;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
gen_upgrade::gen_upgrade() : m_invalidBlockIndex(0), m_checkBlockTemplateVersionCallCounter(0),
|
|
m_coinsInCirculationBeforeUpgrade(0), m_coinsInCirculationAfterUpgrade(0) {
|
|
REGISTER_CALLBACK_METHOD(gen_upgrade, markInvalidBlock);
|
|
REGISTER_CALLBACK_METHOD(gen_upgrade, checkBlockTemplateVersionIsV1);
|
|
REGISTER_CALLBACK_METHOD(gen_upgrade, checkBlockTemplateVersionIsV2);
|
|
REGISTER_CALLBACK_METHOD(gen_upgrade, checkBlockRewardEqFee);
|
|
REGISTER_CALLBACK_METHOD(gen_upgrade, checkBlockRewardIsZero);
|
|
REGISTER_CALLBACK_METHOD(gen_upgrade, rememberCoinsInCirculationBeforeUpgrade);
|
|
REGISTER_CALLBACK_METHOD(gen_upgrade, rememberCoinsInCirculationAfterUpgrade);
|
|
}
|
|
|
|
bool gen_upgrade::generate(std::vector<test_event_entry>& events) const {
|
|
const uint64_t tsStart = 1338224400;
|
|
|
|
GENERATE_ACCOUNT(minerAccount);
|
|
MAKE_GENESIS_BLOCK(events, blk0, minerAccount, tsStart);
|
|
|
|
// Vote for upgrade
|
|
Block blk1;
|
|
if (!makeBlocks(events, generator, blk1, blk0, minerAccount, m_currency.minNumberVotingBlocks(), BLOCK_MAJOR_VERSION_1, BLOCK_MINOR_VERSION_1)) {
|
|
return false;
|
|
}
|
|
|
|
if (!checkBeforeUpgrade(events, generator, blk1, minerAccount, true)) {
|
|
return false;
|
|
}
|
|
|
|
// Fill m_currency.upgradeVotingWindow()
|
|
Block blk2;
|
|
if (!makeBlocks(events, generator, blk2, blk1, minerAccount, m_currency.upgradeVotingWindow() - m_currency.minNumberVotingBlocks() - 1,
|
|
BLOCK_MAJOR_VERSION_1, BLOCK_MINOR_VERSION_0)) {
|
|
return false;
|
|
}
|
|
|
|
// Upgrade voting complete!
|
|
uint64_t votingCompleteHeight = get_block_height(blk2);
|
|
uint64_t upgradeHeight = m_currency.calculateUpgradeHeight(votingCompleteHeight);
|
|
|
|
if (!checkBeforeUpgrade(events, generator, blk2, minerAccount, true)) {
|
|
return false;
|
|
}
|
|
|
|
// Create blocks up to upgradeHeight
|
|
Block blk3;
|
|
if (!makeBlocks(events, generator, blk3, blk2, minerAccount, upgradeHeight - votingCompleteHeight - 1, BLOCK_MAJOR_VERSION_1, BLOCK_MINOR_VERSION_0)) {
|
|
return false;
|
|
}
|
|
|
|
if (!checkBeforeUpgrade(events, generator, blk3, minerAccount, false)) {
|
|
return false;
|
|
}
|
|
|
|
// Create last block with version 1.x
|
|
Block blk4;
|
|
if (!makeBlocks(events, generator, blk4, blk3, minerAccount, 1, BLOCK_MAJOR_VERSION_1, BLOCK_MINOR_VERSION_0)) {
|
|
return false;
|
|
}
|
|
|
|
generator.defaultMajorVersion = BLOCK_MAJOR_VERSION_2;
|
|
generator.defaultMinorVersion = BLOCK_MINOR_VERSION_0;
|
|
|
|
if (!checkAfterUpgrade(events, generator, blk4, minerAccount)) {
|
|
return false;
|
|
}
|
|
|
|
// Create a few blocks with version 2.0
|
|
Block blk5;
|
|
if (!makeBlocks(events, generator, blk5, blk4, minerAccount, 3, BLOCK_MAJOR_VERSION_2, BLOCK_MINOR_VERSION_0)) {
|
|
return false;
|
|
}
|
|
|
|
if (!checkAfterUpgrade(events, generator, blk5, minerAccount)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::checkBeforeUpgrade(std::vector<test_event_entry>& events, test_generator& generator,
|
|
const cryptonote::Block& parentBlock, const cryptonote::account_base& minerAcc,
|
|
bool checkReward) const {
|
|
// Checking 1: get_block_templare returns block with major version 1
|
|
DO_CALLBACK(events, "checkBlockTemplateVersionIsV1");
|
|
|
|
// Checking 2: penalty doesn't apply to transactions fee
|
|
if (checkReward) {
|
|
// Add block to the blockchain, later it become an alternative
|
|
DO_CALLBACK(events, "rememberCoinsInCirculationBeforeUpgrade");
|
|
MAKE_TX_LIST_START(events, txs, minerAcc, minerAcc, MK_COINS(1), parentBlock);
|
|
Block alternativeBlk;
|
|
if (!generator.constructMaxSizeBlock(alternativeBlk, parentBlock, minerAcc, m_currency.rewardBlocksWindow(), txs)) {
|
|
return false;
|
|
}
|
|
events.push_back(alternativeBlk);
|
|
DO_CALLBACK(events, "checkBlockRewardEqFee");
|
|
}
|
|
|
|
// Checking 3: block with version 2.0 doesn't accepted
|
|
Block badBlock;
|
|
DO_CALLBACK(events, "markInvalidBlock");
|
|
return makeBlocks(events, generator, badBlock, parentBlock, minerAcc, 1, BLOCK_MAJOR_VERSION_2, BLOCK_MINOR_VERSION_0);
|
|
}
|
|
|
|
bool gen_upgrade::checkAfterUpgrade(std::vector<test_event_entry>& events, test_generator& generator,
|
|
const cryptonote::Block& parentBlock, const cryptonote::account_base& minerAcc) const {
|
|
// Checking 1: get_block_templare returns block with major version 2
|
|
DO_CALLBACK(events, "checkBlockTemplateVersionIsV2");
|
|
|
|
// Checking 2: penalty applies to transactions fee
|
|
// Add block to the blockchain, later it become an alternative
|
|
DO_CALLBACK(events, "rememberCoinsInCirculationAfterUpgrade");
|
|
MAKE_TX_LIST_START(events, txs, minerAcc, minerAcc, MK_COINS(1), parentBlock);
|
|
Block alternativeBlk;
|
|
if (!generator.constructMaxSizeBlock(alternativeBlk, parentBlock, minerAcc, m_currency.rewardBlocksWindow(), txs)) {
|
|
return false;
|
|
}
|
|
events.push_back(alternativeBlk);
|
|
DO_CALLBACK(events, "checkBlockRewardIsZero");
|
|
|
|
// Checking 3: block with version 1.0 doesn't accepted
|
|
Block badBlock;
|
|
DO_CALLBACK(events, "markInvalidBlock");
|
|
if (!makeBlocks(events, generator, badBlock, parentBlock, minerAcc, 1, BLOCK_MAJOR_VERSION_1, BLOCK_MINOR_VERSION_0)) {
|
|
return false;
|
|
}
|
|
|
|
// Checking 2: block with version 1.1 doesn't accepted
|
|
DO_CALLBACK(events, "markInvalidBlock");
|
|
return makeBlocks(events, generator, badBlock, parentBlock, minerAcc, 1, BLOCK_MAJOR_VERSION_1, BLOCK_MINOR_VERSION_1);
|
|
}
|
|
|
|
bool gen_upgrade::check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t eventIdx, const cryptonote::Block& /*blk*/) {
|
|
if (m_invalidBlockIndex == eventIdx) {
|
|
m_invalidBlockIndex = 0;
|
|
return bvc.m_verifivation_failed;
|
|
} else {
|
|
return !bvc.m_verifivation_failed;
|
|
}
|
|
}
|
|
|
|
bool gen_upgrade::markInvalidBlock(cryptonote::core& /*c*/, size_t evIndex, const std::vector<test_event_entry>& /*events*/) {
|
|
m_invalidBlockIndex = evIndex + 1;
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::checkBlockTemplateVersionIsV1(cryptonote::core& c, size_t /*evIndex*/, const std::vector<test_event_entry>& /*events*/) {
|
|
DEFINE_TESTS_ERROR_CONTEXT("gen_upgrade::checkBlockTemplateVersionIsV1");
|
|
CHECK_TEST_CONDITION(checkBlockTemplateVersion(c, BLOCK_MAJOR_VERSION_1, BLOCK_MINOR_VERSION_1));
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::checkBlockTemplateVersionIsV2(cryptonote::core& c, size_t /*evIndex*/, const std::vector<test_event_entry>& /*events*/) {
|
|
DEFINE_TESTS_ERROR_CONTEXT("gen_upgrade::checkBlockTemplateVersionIsV2");
|
|
CHECK_TEST_CONDITION(checkBlockTemplateVersion(c, BLOCK_MAJOR_VERSION_2, BLOCK_MINOR_VERSION_0));
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::checkBlockTemplateVersion(cryptonote::core& c, uint8_t expectedMajorVersion, uint8_t expectedMinorVersion) {
|
|
DEFINE_TESTS_ERROR_CONTEXT("gen_upgrade::checkBlockTemplateVersion");
|
|
|
|
account_base account;
|
|
account.generate();
|
|
|
|
Block b;
|
|
difficulty_type diff;
|
|
uint64_t height;
|
|
CHECK_TEST_CONDITION(c.get_block_template(b, account.get_keys().m_account_address, diff, height, blobdata()));
|
|
CHECK_EQ(b.majorVersion, expectedMajorVersion);
|
|
CHECK_EQ(b.minorVersion, expectedMinorVersion);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::checkBlockRewardEqFee(cryptonote::core& c, size_t evIndex, const std::vector<test_event_entry>& events) {
|
|
DEFINE_TESTS_ERROR_CONTEXT("gen_upgrade::checkBlockRewardEqFee");
|
|
|
|
Block blk = boost::get<Block>(events[evIndex - 1]);
|
|
uint64_t blockReward = get_outs_money_amount(blk.minerTx);
|
|
CHECK_EQ(blockReward, m_currency.minimumFee());
|
|
|
|
CHECK_EQ(m_coinsInCirculationBeforeUpgrade, c.get_blockchain_storage().getCoinsInCirculation());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::checkBlockRewardIsZero(cryptonote::core& c, size_t evIndex, const std::vector<test_event_entry>& events) {
|
|
DEFINE_TESTS_ERROR_CONTEXT("gen_upgrade::checkBlockRewardIsZero");
|
|
|
|
Block blk = boost::get<Block>(events[evIndex - 1]);
|
|
uint64_t blockReward = get_outs_money_amount(blk.minerTx);
|
|
CHECK_EQ(blockReward, 0);
|
|
|
|
CHECK_EQ(m_coinsInCirculationAfterUpgrade - m_currency.minimumFee(), c.get_blockchain_storage().getCoinsInCirculation());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::rememberCoinsInCirculationBeforeUpgrade(cryptonote::core& c, size_t /*evIndex*/, const std::vector<test_event_entry>& /*events*/) {
|
|
m_coinsInCirculationBeforeUpgrade = c.get_blockchain_storage().getCoinsInCirculation();
|
|
return true;
|
|
}
|
|
|
|
bool gen_upgrade::rememberCoinsInCirculationAfterUpgrade(cryptonote::core& c, size_t /*evIndex*/, const std::vector<test_event_entry>& /*events*/) {
|
|
m_coinsInCirculationAfterUpgrade = c.get_blockchain_storage().getCoinsInCirculation();
|
|
return true;
|
|
}
|