add --regtest and --fixed-difficulty for regression testing

on_generateblocks RPC call combines functionality from the on_getblocktemplate and on_submitblock RPC calls to allow rapid block creation. Difficulty is set permanently to 1 for regtest.
Makes use of FAKECHAIN network type, but takes hard fork heights from mainchain
Default reserve_size in generate_blocks RPC call is now 1. If it is 0, the following error occurs 'Failed to calculate offset for'.
Queries hard fork heights info of other network types
release-v0.5.1
victorsintnicolaas 6 years ago
parent 149da420e9
commit 34cb6b4b70

@ -1213,6 +1213,11 @@ std::vector<std::string> BlockchainBDB::get_filenames() const
return full_paths;
}
bool BlockchainBDB::remove_data_file(const std::string& folder)
{
return true;
}
std::string BlockchainBDB::get_db_name() const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);

@ -244,6 +244,8 @@ public:
virtual std::vector<std::string> get_filenames() const;
virtual bool remove_data_file(const std::string& folder);
virtual std::string get_db_name() const;
virtual bool lock();

@ -654,6 +654,20 @@ public:
*/
virtual std::vector<std::string> get_filenames() const = 0;
/**
* @brief remove file(s) storing the database
*
* This function is for resetting the database (for core tests, functional tests, etc).
* The function reset() is not usable because it needs to open the database file first
* which can fail if the existing database file is in an incompatible format.
* As such, this function needs to be called before calling open().
*
* @param folder The path of the folder containing the database file(s) which must not end with slash '/'.
*
* @return true if the operation is succesfull
*/
virtual bool remove_data_file(const std::string& folder) const = 0;
// return the name of the folder the db's file(s) should reside in
/**
* @brief gets the name of the folder the BlockchainDB's file(s) should be in

@ -1465,6 +1465,21 @@ std::vector<std::string> BlockchainLMDB::get_filenames() const
return filenames;
}
bool BlockchainLMDB::remove_data_file(const std::string& folder) const
{
const std::string filename = folder + "/data.mdb";
try
{
boost::filesystem::remove(filename);
}
catch (const std::exception &e)
{
MERROR("Failed to remove " << filename << ": " << e.what());
return false;
}
return true;
}
std::string BlockchainLMDB::get_db_name() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);

@ -181,6 +181,8 @@ public:
virtual std::vector<std::string> get_filenames() const;
virtual bool remove_data_file(const std::string& folder) const;
virtual std::string get_db_name() const;
virtual bool lock();

@ -220,6 +220,14 @@ namespace cryptonote
*/
uint64_t get_window_size() const { return window_size; }
struct Params {
uint8_t version;
uint8_t threshold;
uint64_t height;
time_t time;
Params(uint8_t version, uint64_t height, uint8_t threshold, time_t time): version(version), threshold(threshold), height(height), time(time) {}
};
private:
uint8_t get_block_version(uint64_t height) const;
@ -244,13 +252,6 @@ namespace cryptonote
uint8_t original_version;
uint64_t original_version_till_height;
struct Params {
uint8_t version;
uint8_t threshold;
uint64_t height;
time_t time;
Params(uint8_t version, uint64_t height, uint8_t threshold, time_t time): version(version), threshold(threshold), height(height), time(time) {}
};
std::vector<Params> heights;
std::deque<uint8_t> versions; /* rolling window of the last N blocks' versions */

@ -329,7 +329,7 @@ uint64_t Blockchain::get_current_blockchain_height() const
//------------------------------------------------------------------
//FIXME: possibly move this into the constructor, to avoid accidentally
// dereferencing a null BlockchainDB pointer
bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options)
bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty)
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_tx_pool);
@ -351,6 +351,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
m_nettype = test_options != NULL ? FAKECHAIN : nettype;
m_offline = offline;
m_fixed_difficulty = fixed_difficulty;
if (m_hardfork == nullptr)
{
if (m_nettype == FAKECHAIN || m_nettype == STAGENET)
@ -805,6 +806,11 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
// less blocks than desired if there aren't enough.
difficulty_type Blockchain::get_difficulty_for_next_block()
{
if (m_fixed_difficulty)
{
return m_db->height() ? m_fixed_difficulty : 1;
}
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_difficulty_lock);
@ -1007,6 +1013,11 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
// an alternate chain.
difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, block_extended_info& bei) const
{
if (m_fixed_difficulty)
{
return m_db->height() ? m_fixed_difficulty : 1;
}
LOG_PRINT_L3("Blockchain::" << __func__);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> cumulative_difficulties;
@ -4374,6 +4385,39 @@ HardFork::State Blockchain::get_hard_fork_state() const
return m_hardfork->get_state();
}
const std::vector<HardFork::Params>& Blockchain::get_hard_fork_heights(network_type nettype)
{
static const std::vector<HardFork::Params> mainnet_heights = []()
{
std::vector<HardFork::Params> heights;
for (const auto& i : mainnet_hard_forks)
heights.emplace_back(i.version, i.height, i.threshold, i.time);
return heights;
}();
static const std::vector<HardFork::Params> testnet_heights = []()
{
std::vector<HardFork::Params> heights;
for (const auto& i : testnet_hard_forks)
heights.emplace_back(i.version, i.height, i.threshold, i.time);
return heights;
}();
static const std::vector<HardFork::Params> stagenet_heights = []()
{
std::vector<HardFork::Params> heights;
for (const auto& i : stagenet_hard_forks)
heights.emplace_back(i.version, i.height, i.threshold, i.time);
return heights;
}();
static const std::vector<HardFork::Params> dummy;
switch (nettype)
{
case MAINNET: return mainnet_heights;
case TESTNET: return testnet_heights;
case STAGENET: return stagenet_heights;
default: return dummy;
}
}
bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
{
return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);

@ -114,10 +114,11 @@ namespace cryptonote
* @param nettype network type
* @param offline true if running offline, else false
* @param test_options test parameters
* @param fixed_difficulty fixed difficulty for testing purposes; 0 means disabled
*
* @return true on success, false if any initialization steps fail
*/
bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL);
bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0);
/**
* @brief Initialize the Blockchain state
@ -754,6 +755,13 @@ namespace cryptonote
*/
HardFork::State get_hard_fork_state() const;
/**
* @brief gets the hardfork heights of given network
*
* @return the HardFork object
*/
static const std::vector<HardFork::Params>& get_hard_fork_heights(network_type nettype);
/**
* @brief gets the current hardfork version in use/voted for
*
@ -1033,6 +1041,7 @@ namespace cryptonote
network_type m_nettype;
bool m_offline;
difficulty_type m_fixed_difficulty;
std::atomic<bool> m_cancel;

@ -76,6 +76,16 @@ namespace cryptonote
, "Run on stagenet. The wallet must be launched with --stagenet flag."
, false
};
const command_line::arg_descriptor<bool> arg_regtest_on = {
"regtest"
, "Run in a regression testing mode."
, false
};
const command_line::arg_descriptor<difficulty_type> arg_fixed_difficulty = {
"fixed-difficulty"
, "Fixed difficulty used for testing."
, 0
};
const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir = {
"data-dir"
, "Specify data directory"
@ -252,6 +262,8 @@ namespace cryptonote
command_line::add_arg(desc, arg_testnet_on);
command_line::add_arg(desc, arg_stagenet_on);
command_line::add_arg(desc, arg_regtest_on);
command_line::add_arg(desc, arg_fixed_difficulty);
command_line::add_arg(desc, arg_dns_checkpoints);
command_line::add_arg(desc, arg_prep_blocks_threads);
command_line::add_arg(desc, arg_fast_block_sync);
@ -374,7 +386,8 @@ namespace cryptonote
{
start_time = std::time(nullptr);
if (test_options != NULL)
const bool regtest = command_line::get_arg(vm, arg_regtest_on);
if (test_options != NULL || regtest)
{
m_nettype = FAKECHAIN;
}
@ -431,6 +444,16 @@ namespace cryptonote
blockchain_db_sync_mode sync_mode = db_defaultsync;
uint64_t blocks_per_sync = 1;
if (m_nettype == FAKECHAIN)
{
// reset the db by removing the database file before opening it
if (!db->remove_data_file(filename))
{
MERROR("Failed to remove data file in " << filename);
return false;
}
}
try
{
uint64_t db_flags = 0;
@ -508,7 +531,12 @@ namespace cryptonote
m_blockchain_storage.set_user_options(blocks_threads,
blocks_per_sync, sync_mode, fast_sync);
r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, test_options);
const std::pair<uint8_t, uint64_t> regtest_hard_forks[3] = {std::make_pair(1, 0), std::make_pair(Blockchain::get_hard_fork_heights(MAINNET).back().version, 1), std::make_pair(0, 0)};
const cryptonote::test_options regtest_test_options = {
regtest_hard_forks
};
const difficulty_type fixed_difficulty = command_line::get_arg(vm, arg_fixed_difficulty);
r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty);
r = m_mempool.init(max_txpool_size);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");

@ -61,6 +61,8 @@ namespace cryptonote
extern const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir;
extern const command_line::arg_descriptor<bool, false> arg_testnet_on;
extern const command_line::arg_descriptor<bool, false> arg_stagenet_on;
extern const command_line::arg_descriptor<bool, false> arg_regtest_on;
extern const command_line::arg_descriptor<difficulty_type> arg_fixed_difficulty;
extern const command_line::arg_descriptor<bool> arg_offline;
/************************************************************************/

@ -77,9 +77,10 @@ public:
const auto testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
const auto stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
const auto regtest = command_line::get_arg(vm, cryptonote::arg_regtest_on);
const auto restricted = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc);
const auto main_rpc_port = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port);
rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, main_rpc_port, "core"});
rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : regtest ? cryptonote::FAKECHAIN : cryptonote::MAINNET, main_rpc_port, "core"});
auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
if(!command_line::is_arg_defaulted(vm, restricted_rpc_port_arg))

@ -162,9 +162,10 @@ int main(int argc, char const * argv[])
const bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
const bool stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
if (testnet && stagenet)
const bool regtest = command_line::get_arg(vm, cryptonote::arg_regtest_on);
if (testnet + stagenet + regtest > 1)
{
std::cerr << "Can't specify more than one of --tesnet and --stagenet" << ENDL;
std::cerr << "Can't specify more than one of --tesnet and --stagenet and --regtest" << ENDL;
return 1;
}

@ -382,6 +382,9 @@ namespace nodetool
full_addrs.insert("162.210.173.150:38080");
full_addrs.insert("162.210.173.151:38080");
}
else if (nettype == cryptonote::FAKECHAIN)
{
}
else
{
full_addrs.insert("107.152.130.98:18080");

@ -1209,6 +1209,68 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_generateblocks);
CHECK_CORE_READY();
res.status = CORE_RPC_STATUS_OK;
if(m_core.get_nettype() != FAKECHAIN)
{
error_resp.code = CORE_RPC_ERROR_CODE_REGTEST_REQUIRED;
error_resp.message = "Regtest required when generating blocks";
return false;
}
COMMAND_RPC_GETBLOCKTEMPLATE::request template_req;
COMMAND_RPC_GETBLOCKTEMPLATE::response template_res;
COMMAND_RPC_SUBMITBLOCK::request submit_req;
COMMAND_RPC_SUBMITBLOCK::response submit_res;
template_req.reserve_size = 1;
template_req.wallet_address = req.wallet_address;
submit_req.push_back(boost::value_initialized<std::string>());
res.height = m_core.get_blockchain_storage().get_current_blockchain_height();
bool r;
for(size_t i = 0; i < req.amount_of_blocks; i++)
{
r = on_getblocktemplate(template_req, template_res, error_resp);
res.status = template_res.status;
if (!r) return false;
blobdata blockblob;
if(!string_tools::parse_hexstr_to_binbuff(template_res.blocktemplate_blob, blockblob))
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
error_resp.message = "Wrong block blob";
return false;
}
block b = AUTO_VAL_INIT(b);
if(!parse_and_validate_block_from_blob(blockblob, b))
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
error_resp.message = "Wrong block blob";
return false;
}
miner::find_nonce_for_given_block(b, template_res.difficulty, template_res.height);
submit_req.front() = string_tools::buff_to_hex_nodelimer(block_to_blob(b));
r = on_submitblock(submit_req, submit_res, error_resp);
res.status = submit_res.status;
if (!r) return false;
res.height = template_res.height;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
uint64_t core_rpc_server::get_block_reward(const block& blk)
{
uint64_t reward = 0;

@ -129,6 +129,7 @@ namespace cryptonote
MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE)
MAP_JON_RPC_WE("submit_block", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
MAP_JON_RPC_WE_IF("generateblocks", on_generateblocks, COMMAND_RPC_GENERATEBLOCKS, !m_restricted)
MAP_JON_RPC_WE("get_last_block_header", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER)
MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER)
MAP_JON_RPC_WE("get_block_header_by_hash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH)
@ -196,6 +197,7 @@ namespace cryptonote
bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp);
bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp);
bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp);
bool on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp);
bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp);
bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp);
bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp);

@ -1149,6 +1149,31 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_GENERATEBLOCKS
{
struct request
{
uint64_t amount_of_blocks;
std::string wallet_address;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount_of_blocks)
KV_SERIALIZE(wallet_address)
END_KV_SERIALIZE_MAP()
};
struct response
{
uint64_t height;
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
};
struct block_header_response
{

@ -42,5 +42,6 @@
#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE -10
#define CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC -11
#define CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS -12
#define CORE_RPC_ERROR_CODE_REGTEST_REQUIRED -13

@ -50,6 +50,7 @@ public:
virtual void safesyncmode(const bool onoff) {}
virtual void reset() {}
virtual std::vector<std::string> get_filenames() const { return std::vector<std::string>(); }
virtual bool remove_data_file(const std::string& folder) const { return true; }
virtual std::string get_db_name() const { return std::string(); }
virtual bool lock() { return true; }
virtual void unlock() { }

Loading…
Cancel
Save