diff --git a/src/blockchain_converter/fake_core.h b/src/blockchain_converter/fake_core.h index 175cb466..f82b05d0 100644 --- a/src/blockchain_converter/fake_core.h +++ b/src/blockchain_converter/fake_core.h @@ -29,8 +29,10 @@ #pragma once #include -#include "cryptonote_core/blockchain.h" // BlockchainDB and LMDB +#include "cryptonote_core/blockchain.h" // BlockchainDB #include "cryptonote_core/blockchain_storage.h" // in-memory DB +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" using namespace cryptonote; @@ -53,7 +55,27 @@ struct fake_core_lmdb #endif { m_pool.init(path.string()); - m_storage.init(path.string(), use_testnet, mdb_flags); + + BlockchainDB* db = new BlockchainLMDB(); + + boost::filesystem::path folder(path); + + folder /= db->get_db_name(); + + LOG_PRINT_L0("Loading blockchain from folder " << folder.c_str() << " ..."); + + const std::string filename = folder.string(); + try + { + db->open(filename, mdb_flags); + } + catch (const std::exception& e) + { + LOG_PRINT_L0("Error opening database: " << e.what()); + throw; + } + + m_storage.init(db, use_testnet); if (do_batch) m_storage.get_db().set_batch_transactions(do_batch); support_batch = true; diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp index 786c13b0..4b254500 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ b/src/blockchain_db/berkeleydb/db_bdb.cpp @@ -724,13 +724,6 @@ void BlockchainBDB::open(const std::string& filename, const int db_flags) m_open = true; } -// unused for now, create will happen on open if doesn't exist -void BlockchainBDB::create(const std::string& filename) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - throw DB_CREATE_FAILURE("create() is not implemented for this BlockchainDB, open() will create files if needed."); -} - void BlockchainBDB::close() { LOG_PRINT_L3("BlockchainBDB::" << __func__); diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h index b68ed287..d4eb5434 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.h +++ b/src/blockchain_db/berkeleydb/db_bdb.h @@ -95,8 +95,6 @@ public: virtual void open(const std::string& filename, const int db_flags); - virtual void create(const std::string& filename); - virtual void close(); virtual void sync(); @@ -279,7 +277,6 @@ private: Db* m_spent_keys; - bool m_open; uint64_t m_height; uint64_t m_num_outputs; std::string m_folder; diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index 8b08d380..d648be44 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -129,6 +129,11 @@ void BlockchainDB::pop_block(block& blk, std::vector& txs) } } +bool BlockchainDB::is_open() +{ + return m_open; +} + void BlockchainDB::remove_transaction(const crypto::hash& tx_hash) { transaction tx = get_tx(tx_hash); diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 7b6b55a4..04d9c538 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -62,6 +62,7 @@ * * General: * open() + * is_open() * close() * sync() * reset() @@ -328,8 +329,8 @@ public: // open the db at location , or create it if there isn't one. virtual void open(const std::string& filename, const int db_flags = 0) = 0; - // make sure implementation has a create function as well - virtual void create(const std::string& filename) = 0; + // returns true of the db is open/ready, else false + bool is_open(); // close and sync the db virtual void close() = 0; @@ -482,6 +483,7 @@ public: // returns true if key image is present in spent key images storage virtual bool has_key_image(const crypto::key_image& img) const = 0; + bool m_open; }; // class BlockchainDB diff --git a/src/blockchain_db/db_types.h b/src/blockchain_db/db_types.h new file mode 100644 index 00000000..b13007df --- /dev/null +++ b/src/blockchain_db/db_types.h @@ -0,0 +1,40 @@ +// Copyright (c) 2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#pragma once + +namespace cryptonote +{ + + const std::unordered_set blockchain_db_types = + { "lmdb" + , "berkeley" + }; + +} // namespace cryptonote diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 524a1c26..8e09dfab 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -733,13 +733,6 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) // from here, init should be finished } -// unused for now, create will happen on open if doesn't exist -void BlockchainLMDB::create(const std::string& filename) -{ - LOG_PRINT_L3("BlockchainLMDB::" << __func__); - throw DB_CREATE_FAILURE("create() is not implemented for this BlockchainDB, open() will create files if needed."); -} - void BlockchainLMDB::close() { LOG_PRINT_L3("BlockchainLMDB::" << __func__); diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index c3c7ce43..8f1e07e0 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -24,6 +24,7 @@ // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#pragma once #include "blockchain_db/blockchain_db.h" #include "cryptonote_protocol/blobdatatype.h" // for type blobdata @@ -116,8 +117,6 @@ public: virtual void open(const std::string& filename, const int mdb_flags=0); - virtual void create(const std::string& filename); - virtual void close(); virtual void sync(); @@ -302,7 +301,6 @@ private: MDB_dbi m_spent_keys; - bool m_open; uint64_t m_height; uint64_t m_num_outputs; std::string m_folder; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 57934b3f..0261a561 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -39,7 +39,6 @@ #include "tx_pool.h" #include "blockchain.h" #include "blockchain_db/blockchain_db.h" -#include "blockchain_db/lmdb/db_lmdb.h" #include "cryptonote_format_utils.h" #include "cryptonote_boost_serialization.h" #include "cryptonote_config.h" @@ -65,8 +64,7 @@ using epee::string_tools::pod_to_hex; DISABLE_VS_WARNINGS(4267) //------------------------------------------------------------------ -// TODO: initialize m_db with a concrete implementation of BlockchainDB -Blockchain::Blockchain(tx_memory_pool& tx_pool):m_db(), m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false), m_testnet(false), m_enforce_dns_checkpoints(false) +Blockchain::Blockchain(tx_memory_pool& tx_pool):m_db(), m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false) { LOG_PRINT_L3("Blockchain::" << __func__); } @@ -226,43 +224,24 @@ 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(const std::string& config_folder, const bool testnet, const int db_flags) +bool Blockchain::init(BlockchainDB* db, const bool testnet) { LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_blockchain_lock); - // TODO: make this configurable - m_db = new BlockchainLMDB(); - - m_config_folder = config_folder; - m_testnet = testnet; - - boost::filesystem::path folder(m_config_folder); - - folder /= m_db->get_db_name(); - - LOG_PRINT_L0("Loading blockchain from folder " << folder.c_str() << " ..."); - - const std::string filename = folder.string(); - try + if (db == nullptr) { - m_db->open(filename, db_flags); + LOG_ERROR("Attempted to init Blockchain with null DB"); + return false; } - catch (const DB_OPEN_FAILURE& e) + if (!db->is_open()) { - LOG_PRINT_L0("No blockchain file found, attempting to create one."); - try - { - m_db->create(filename); - } - catch (const DB_CREATE_FAILURE& db_create_error) - { - LOG_PRINT_L0("Unable to create BlockchainDB! This is not good..."); - //TODO: make sure whatever calls this handles the return value properly - return false; - } + LOG_ERROR("Attempted to init Blockchain with unopened DB"); + return false; } + m_db = db; + // if the blockchain is new, add the genesis block // this feels kinda kludgy to do it this way, but can be looked at later. // TODO: add function to create and store genesis block, diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index dc98a56a..bc13901d 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -81,7 +81,7 @@ namespace cryptonote Blockchain(tx_memory_pool& tx_pool); - bool init(const std::string& config_folder, const bool testnet = false, const int db_flags = 0); + bool init(BlockchainDB* db, const bool testnet = false); bool deinit(); void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; } @@ -180,11 +180,9 @@ namespace cryptonote outputs_container m_outputs; - std::string m_config_folder; checkpoints m_checkpoints; std::atomic m_is_in_checkpoint_zone; std::atomic m_is_blockchain_storing; - bool m_testnet; bool m_enforce_dns_checkpoints; bool switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain); diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index f9b2b19f..7864b55c 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -44,6 +44,9 @@ using namespace epee; #include #include "daemon/command_line_args.h" #include "cryptonote_core/checkpoints_create.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "blockchain_db/berkeleydb/db_bdb.h" DISABLE_VS_WARNINGS(4355) @@ -194,7 +197,45 @@ namespace cryptonote r = m_mempool.init(m_config_folder); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool"); +#if BLOCKCHAIN_DB == DB_LMDB + std::string db_type = command_line::get_arg(vm, daemon_args::arg_db_type); + + BlockchainDB* db = nullptr; + if (db_type == "lmdb") + { + db = new BlockchainLMDB(); + } + else if (db_type == "berkeley") + { + db = new BlockchainBDB(); + } + else + { + LOG_ERROR("Attempted to use non-existant database type"); + return false; + } + + boost::filesystem::path folder(m_config_folder); + + folder /= db->get_db_name(); + + LOG_PRINT_L0("Loading blockchain from folder " << folder.c_str() << " ..."); + + const std::string filename = folder.string(); + try + { + db->open(filename); + } + catch (const DB_ERROR& e) + { + LOG_PRINT_L0("Error opening database: " << e.what()); + return false; + } + + r = m_blockchain_storage.init(db, m_testnet); +#else r = m_blockchain_storage.init(m_config_folder, m_testnet); +#endif CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); // load json & DNS checkpoints, and verify them diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h index bcf59912..2bd91847 100644 --- a/src/daemon/command_line_args.h +++ b/src/daemon/command_line_args.h @@ -70,6 +70,11 @@ namespace daemon_args , "checkpoints from DNS server will be enforced" , false }; + const command_line::arg_descriptor arg_db_type = { + "db-type" + , "Specify database type" + , "lmdb" + }; } // namespace daemon_args diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 5d8baf49..3bad7037 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -42,6 +42,7 @@ #include "rpc/core_rpc_server.h" #include #include "daemon/command_line_args.h" +#include "blockchain_db/db_types.h" namespace po = boost::program_options; namespace bf = boost::filesystem; @@ -78,6 +79,7 @@ int main(int argc, char const * argv[]) command_line::add_arg(core_settings, daemon_args::arg_log_level); command_line::add_arg(core_settings, daemon_args::arg_testnet_on); command_line::add_arg(core_settings, daemon_args::arg_dns_checkpoints); + command_line::add_arg(core_settings, daemon_args::arg_db_type); daemonizer::init_options(hidden_options, visible_options); daemonize::t_executor::init_options(core_settings); @@ -128,6 +130,19 @@ int main(int argc, char const * argv[]) return 0; } + std::string db_type = command_line::get_arg(vm, daemon_args::arg_db_type); + + // verify that blockchaindb type is valid + if(cryptonote::blockchain_db_types.count(db_type) == 0) + { + std::cout << "Invalid database type (" << db_type << "), available types are:" << std::endl; + for (const auto& type : cryptonote::blockchain_db_types) + { + std::cout << "\t" << type << std::endl; + } + return 0; + } + bool testnet_mode = command_line::get_arg(vm, daemon_args::arg_testnet_on); auto data_dir_arg = testnet_mode ? command_line::arg_testnet_data_dir : command_line::arg_data_dir;