From 01374ec620aeffaa3790dcef45340300455518f7 Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Tue, 4 Nov 2025 11:43:02 -0500 Subject: [PATCH] Add regtest option (#193) Disable checkpoints check on storage::sync_chain when regtest mode is enabled --- src/client_main.cpp | 2 +- src/db/storage.cpp | 6 +++--- src/db/storage.h | 2 +- src/scanner.cpp | 8 ++++---- src/scanner.h | 3 ++- src/server_main.cpp | 12 ++++++++++-- tests/unit/db/chain.test.cpp | 10 +++++----- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/client_main.cpp b/src/client_main.cpp index aa99899..25d6c98 100644 --- a/src/client_main.cpp +++ b/src/client_main.cpp @@ -246,7 +246,7 @@ namespace if (!users.empty()) { - static constexpr const lws::scanner_options opts{false, false}; + static constexpr const lws::scanner_options opts{false, false, false}; auto new_client = MONERO_UNWRAP(zclient.clone()); MONERO_UNWRAP(new_client.watch_scan_signals()); diff --git a/src/db/storage.cpp b/src/db/storage.cpp index 06d7eaf..6d08ebc 100644 --- a/src/db/storage.cpp +++ b/src/db/storage.cpp @@ -1729,12 +1729,12 @@ namespace db }); } - expect storage::sync_chain(block_id height, epee::span hashes) + expect storage::sync_chain(block_id height, epee::span hashes, bool regtest) { MONERO_PRECOND(!hashes.empty()); MONERO_PRECOND(db != nullptr); - return db->try_write([this, height, hashes] (MDB_txn& txn) -> expect + return db->try_write([this, height, hashes, regtest] (MDB_txn& txn) -> expect { cursor::blocks blocks_cur; MONERO_CHECK(check_cursor(txn, this->db->tables.blocks, blocks_cur)); @@ -1767,7 +1767,7 @@ namespace db if (*hash != chain.front()) { - if (current <= get_checkpoints().get_max_height()) + if (!regtest && current <= get_checkpoints().get_max_height()) { /* Either the daemon is performing an attack with a fake chain, or the daemon is still syncing. */ diff --git a/src/db/storage.h b/src/db/storage.h index 6c1c587..ef43a7f 100644 --- a/src/db/storage.h +++ b/src/db/storage.h @@ -235,7 +235,7 @@ namespace db \return True if the local blockchain is correctly synced. */ - expect sync_chain(block_id height, epee::span hashes); + expect sync_chain(block_id height, epee::span hashes, bool regtest); expect sync_pow(block_id height, epee::span hashes, epee::span pow); diff --git a/src/scanner.cpp b/src/scanner.cpp index bb284c9..ab1abd4 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -1100,7 +1100,7 @@ namespace lws } // does not validate blockchain hashes - expect sync_quick(scanner_sync& self, db::storage disk, rpc::client client) + expect sync_quick(scanner_sync& self, db::storage disk, rpc::client client, bool regtest) { MINFO("Starting blockchain sync with daemon"); @@ -1123,7 +1123,7 @@ namespace lws if (resp->hashes.size() <= 1 || resp->hashes.back() == req.known_hashes.front()) return {std::move(client)}; - MONERO_CHECK(disk.sync_chain(db::block_id(resp->start_height), epee::to_span(resp->hashes))); + MONERO_CHECK(disk.sync_chain(db::block_id(resp->start_height), epee::to_span(resp->hashes), regtest)); req.known_hashes.erase(req.known_hashes.begin(), --(req.known_hashes.end())); for (std::size_t num = 0; num < 10; ++num) @@ -1302,13 +1302,13 @@ namespace lws return store(io, disk_, client, webhook, chain, users, pow); } - expect scanner::sync(rpc::client client, const bool untrusted_daemon) + expect scanner::sync(rpc::client client, const bool untrusted_daemon, const bool regtest) { if (has_shutdown()) MONERO_THROW(common_error::kInvalidArgument, "this has shutdown"); if (untrusted_daemon) return sync_full(sync_, disk_.clone(), std::move(client)); - return sync_quick(sync_, disk_.clone(), std::move(client)); + return sync_quick(sync_, disk_.clone(), std::move(client), regtest); } void scanner::run(rpc::context ctx, std::size_t thread_count, const std::string& lws_server_addr, std::string lws_server_pass, const scanner_options& opts) diff --git a/src/scanner.h b/src/scanner.h index 746b398..265733b 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -47,6 +47,7 @@ namespace lws { bool enable_subaddresses; bool untrusted_daemon; + bool regtest; }; //! Used in `scan_loop` by server @@ -119,7 +120,7 @@ namespace lws static bool loop(scanner_sync& self, store_func store, std::optional disk, rpc::client client, std::vector users, rpc::scanner::queue& queue, const scanner_options& opts, bool leader_thread); //! Use `client` to sync blockchain data, and \return client if successful. - expect sync(rpc::client client, const bool untrusted_daemon = false); + expect sync(rpc::client client, const bool untrusted_daemon = false, const bool regtest = false); //! Poll daemon until `shutdown()` is called, using `thread_count` threads. void run(rpc::context ctx, std::size_t thread_count, const std::string& server_addr, std::string server_pass, const scanner_options&); diff --git a/src/server_main.cpp b/src/server_main.cpp index 643993a..2839d2c 100644 --- a/src/server_main.cpp +++ b/src/server_main.cpp @@ -83,6 +83,7 @@ namespace const command_line::arg_descriptor max_subaddresses; const command_line::arg_descriptor auto_accept_creation; const command_line::arg_descriptor untrusted_daemon; + const command_line::arg_descriptor regtest; static std::string get_default_zmq() { @@ -130,6 +131,7 @@ namespace , max_subaddresses{"max-subaddresses", "Maximum number of subaddresses per primary account (defaults to 0)", 0} , auto_accept_creation{"auto-accept-creation", "New account creation requests are automatically accepted", false} , untrusted_daemon{"untrusted-daemon", "Perform (expensive) chain-verification and PoW checks", false} + , regtest{"regtest", "Run in a regression testing mode", false} {} void prepare(boost::program_options::options_description& description) const @@ -165,6 +167,7 @@ namespace command_line::add_arg(description, max_subaddresses); command_line::add_arg(description, auto_accept_creation); command_line::add_arg(description, untrusted_daemon); + command_line::add_arg(description, regtest); } }; @@ -185,6 +188,7 @@ namespace std::size_t scan_threads; unsigned create_queue_max; bool untrusted_daemon; + bool regtest; }; void print_help(std::ostream& out) @@ -273,9 +277,13 @@ namespace std::chrono::minutes{command_line::get_arg(args, opts.rates_interval)}, command_line::get_arg(args, opts.scan_threads), command_line::get_arg(args, opts.create_queue_max), - command_line::get_arg(args, opts.untrusted_daemon) + command_line::get_arg(args, opts.untrusted_daemon), + command_line::get_arg(args, opts.regtest) }; + if (prog.regtest && lws::config::network != cryptonote::MAINNET) + MONERO_THROW(lws::error::configuration, "Regtest cannot be used with testnet or stagenet"); + if (!prog.lws_server_addr.empty() && (prog.rest_config.max_subaddresses || prog.untrusted_daemon)) MONERO_THROW(lws::error::configuration, "Remote scanning cannot be used with subaddresses or untrusted daemon"); @@ -316,7 +324,7 @@ namespace prog.scan_threads, std::move(prog.lws_server_addr), std::move(prog.lws_server_pass), - lws::scanner_options{enable_subaddresses, prog.untrusted_daemon} + lws::scanner_options{enable_subaddresses, prog.untrusted_daemon, prog.regtest} ); } } // anonymous diff --git a/tests/unit/db/chain.test.cpp b/tests/unit/db/chain.test.cpp index 2b12927..68ecb82 100644 --- a/tests/unit/db/chain.test.cpp +++ b/tests/unit/db/chain.test.cpp @@ -89,9 +89,9 @@ LWS_CASE("db::storage::sync_chain") }; EXPECT(db.add_account(account, view)); - EXPECT(db.sync_chain(lws::db::block_id(0), chain) == lws::error::bad_blockchain); - EXPECT(db.sync_chain(last_block.id, {chain + 1, 4}) == lws::error::bad_blockchain); - EXPECT(db.sync_chain(last_block.id, chain)); + EXPECT(db.sync_chain(lws::db::block_id(0), chain, false) == lws::error::bad_blockchain); + EXPECT(db.sync_chain(last_block.id, {chain + 1, 4}, false) == lws::error::bad_blockchain); + EXPECT(db.sync_chain(last_block.id, chain, false)); { const lws::account accounts[1] = {lws::account{get_account(), {}, {}}}; @@ -125,7 +125,7 @@ LWS_CASE("db::storage::sync_chain") crypto::rand() }; - EXPECT(db.sync_chain(last_block.id, fchain)); + EXPECT(db.sync_chain(last_block.id, fchain, false)); lws_test::test_chain(lest_env, MONERO_UNWRAP(db.start_read()), last_block.id, fchain); EXPECT(get_account().scan_height == fork_height); @@ -147,7 +147,7 @@ LWS_CASE("db::storage::sync_chain") crypto::rand() }; - const auto sync_result = db.sync_chain(lws::db::block_id(point->first), fchain); + const auto sync_result = db.sync_chain(lws::db::block_id(point->first), fchain, false); EXPECT(sync_result == lws::error::bad_blockchain); EXPECT(get_account().scan_height == scan_height);