Skip to content

Commit

Permalink
Bytecoin v.2.0.4 release
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonio Juarez committed May 25, 2017
1 parent 2edd5ac commit 918aaad
Show file tree
Hide file tree
Showing 20 changed files with 180 additions and 79 deletions.
5 changes: 5 additions & 0 deletions ReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Release notes 2.0.4

- Fixed an issue where some users experienced daemon hanging
- Fixed block difficulty calculation issue

Release notes 2.0.3

- Stability enhancement
Expand Down
4 changes: 4 additions & 0 deletions src/Common/ScopeExit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ void ScopeExit::cancel() {
m_cancelled = true;
}

void ScopeExit::resume() {
m_cancelled = false;
}

}
1 change: 1 addition & 0 deletions src/Common/ScopeExit.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ScopeExit {
ScopeExit& operator=(ScopeExit&&) = delete;

void cancel();
void resume();

private:
std::function<void()> m_handler;
Expand Down
3 changes: 2 additions & 1 deletion src/CryptoNoteConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ const CheckpointData CHECKPOINTS[] = {
{1039000, "8c9208940fc92539fac98cc658b95d240635f8729ee8bd756d6bdbab52de2c04"},
{1170000, "f48441157749e89687dfa6edec2128ff332bdaa9eb139f2330a193e3139d2980"},
{1268000, "d49fcaec1d53095e2c244913f123bfd4b26eabb6d75aca7b77a00de8aa8ac680"},
{1272000, "2fb2c50328c8345d2f0a16b3ec4ea680a8a93730358494265ada9edbb9bfa1a6"}
{1272000, "2fb2c50328c8345d2f0a16b3ec4ea680a8a93730358494265ada9edbb9bfa1a6"},
{1273000, "496a9238c654d79c48d269224aa75d61f51831bae6dc744f5e709bec11c7c9f2"}
};
} // CryptoNote

Expand Down
56 changes: 44 additions & 12 deletions src/CryptoNoteCore/DatabaseBlockchainCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ class DatabaseVersionWriteBatch: public IWriteBatch {
uint32_t schemeVersion;
};

const uint32_t CURRENT_DB_SCHEME_VERSION = 1;
const uint32_t CURRENT_DB_SCHEME_VERSION = 2;

}

Expand Down Expand Up @@ -487,6 +487,30 @@ DatabaseBlockchainCache::DatabaseBlockchainCache(const Currency& curr, IDataBase
}
}

bool DatabaseBlockchainCache::checkDBSchemeVersion(IDataBase& database, Logging::ILogger& _logger) {
Logging::LoggerRef logger(_logger, "DatabaseBlockchainCache");

DatabaseVersionReadBatch readBatch;
auto ec = database.read(readBatch);
if (ec) {
throw std::system_error(ec);
}

auto version = readBatch.getDbSchemeVersion();
if (!version) {
//DB scheme version not found. Looks like it was just created.
return true;
} else if (*version < CURRENT_DB_SCHEME_VERSION) {
logger(Logging::WARNING) << "DB scheme version is less than expected. Expected version " << CURRENT_DB_SCHEME_VERSION << ". Actual version " << *version << ". DB will be destroyed and recreated from blocks.bin file.";
return false;
} else if (*version > CURRENT_DB_SCHEME_VERSION) {
logger(Logging::ERROR) << "DB scheme version is greater than expected. Expected version " << CURRENT_DB_SCHEME_VERSION << ". Actual version " << *version << ". Please update your software.";
throw std::runtime_error("DB scheme version is greater than expected");
} else {
return true;
}
}

void DatabaseBlockchainCache::deleteClosestTimestampBlockIndex(BlockchainWriteBatch& writeBatch, uint32_t splitBlockIndex) {
auto batch = BlockchainReadBatch().requestCachedBlock(splitBlockIndex);
auto blockResult = readDatabase(batch);
Expand Down Expand Up @@ -1345,23 +1369,31 @@ std::vector<CachedBlockInfo> DatabaseBlockchainCache::getLastCachedUnits(uint32_
assert(blockIndex <= getTopBlockIndex());

std::vector<CachedBlockInfo> cachedResult;
uint32_t cacheStart = (getTopBlockIndex() + 1) - static_cast<uint32_t>(unitsCache.size());
if (cacheStart == 0 && !useGenesis) {
count = std::min(static_cast<size_t>(getTopBlockIndex()), count);
cacheStart = 1;
}
const uint32_t cacheStartIndex = (getTopBlockIndex() + 1) - static_cast<uint32_t>(unitsCache.size());

count = std::min(unitsCache.size(), count);

if (cacheStart > blockIndex || count == 0) {
if (cacheStartIndex > blockIndex || count == 0) {
return cachedResult;
}

count = std::min(blockIndex + 1, static_cast<uint32_t>(count));
uint32_t offset = std::max(static_cast<uint32_t>(blockIndex + 1 - count), cacheStart) - cacheStart;
count = std::min(blockIndex - cacheStartIndex + 1, static_cast<uint32_t>(count));
uint32_t offset = static_cast<uint32_t>(blockIndex + 1 - count) - cacheStartIndex;

assert(offset < unitsCache.size());

cachedResult.reserve(unitsCache.size() - offset - (getTopBlockIndex() - blockIndex));
for (size_t i = offset; (i + cacheStart) <= blockIndex; ++i) {
cachedResult.push_back(unitsCache[i]);
if (!useGenesis && cacheStartIndex == 0 && offset == 0) {
++offset;
--count;
}

if (offset >= unitsCache.size() || count == 0) {
return cachedResult;
}

cachedResult.reserve(count);
for (size_t i = 0; i < count; ++i) {
cachedResult.push_back(unitsCache[offset + i]);
}

return cachedResult;
Expand Down
2 changes: 2 additions & 0 deletions src/CryptoNoteCore/DatabaseBlockchainCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class DatabaseBlockchainCache : public IBlockchainCache {
DatabaseBlockchainCache(const Currency& currency, IDataBase& dataBase,
IBlockchainCacheFactory& blockchainCacheFactory, Logging::ILogger& logger);

static bool checkDBSchemeVersion(IDataBase& dataBase, Logging::ILogger& logger);

/*
* This methods splits cache, upper part (ie blocks with indexes larger than splitBlockIndex)
* is copied to new BlockchainCache. Unfortunately, implementation requires return value to be of
Expand Down
122 changes: 75 additions & 47 deletions src/CryptoNoteCore/RocksDBWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,63 +45,20 @@ void RocksDBWrapper::init(const DataBaseConfig& config) {
throw std::system_error(make_error_code(CryptoNote::error::DataBaseErrorCodes::ALREADY_INITIALIZED));
}

std::string dataDir;
if (config.getTestnet()) {
dataDir = config.getDataDir() + '/' + TESTNET_DB_NAME;
} else {
dataDir = config.getDataDir() + '/' + DB_NAME;
}
std::string dataDir = getDataDir(config);

logger(INFO) << "Opening DB in " << dataDir;

rocksdb::DB* dbPtr;

rocksdb::DBOptions dbOptions;
dbOptions.IncreaseParallelism(config.getBackgroundThreadsCount());
dbOptions.info_log_level = rocksdb::InfoLogLevel::WARN_LEVEL;
dbOptions.max_open_files = config.getMaxOpenFiles();

rocksdb::ColumnFamilyOptions fOptions;
fOptions.write_buffer_size = static_cast<size_t>(config.getWriteBufferSize());
// merge two memtables when flushing to L0
fOptions.min_write_buffer_number_to_merge = 2;
// this means we'll use 50% extra memory in the worst case, but will reduce
// write stalls.
fOptions.max_write_buffer_number = 6;
// start flushing L0->L1 as soon as possible. each file on level0 is
// (memtable_memory_budget / 2). This will flush level 0 when it's bigger than
// memtable_memory_budget.
fOptions.level0_file_num_compaction_trigger = 20;

fOptions.level0_slowdown_writes_trigger = 30;
fOptions.level0_stop_writes_trigger = 40;

// doesn't really matter much, but we don't want to create too many files
fOptions.target_file_size_base = config.getWriteBufferSize() / 10;
// make Level1 size equal to Level0 size, so that L0->L1 compactions are fast
fOptions.max_bytes_for_level_base = config.getWriteBufferSize();
fOptions.num_levels = 10;
fOptions.target_file_size_multiplier = 2;
// level style compaction
fOptions.compaction_style = rocksdb::kCompactionStyleLevel;

fOptions.compression_per_level.resize(fOptions.num_levels);
for (int i = 0; i < fOptions.num_levels; ++i) {
fOptions.compression_per_level[i] = rocksdb::kNoCompression;
}

rocksdb::BlockBasedTableOptions tableOptions;
tableOptions.block_cache = rocksdb::NewLRUCache(config.getReadCacheSize());
std::shared_ptr<rocksdb::TableFactory> tfp(NewBlockBasedTableFactory(tableOptions));
fOptions.table_factory = tfp;

rocksdb::Status status = rocksdb::DB::Open(rocksdb::Options(dbOptions, fOptions), dataDir, &dbPtr);
rocksdb::Options dbOptions = getDBOptions(config);
rocksdb::Status status = rocksdb::DB::Open(dbOptions, dataDir, &dbPtr);
if (status.ok()) {
logger(INFO) << "DB opened in " << dataDir;
} else if (!status.ok() || status.IsNotFound()) {
logger(INFO) << "DB not found in " << dataDir << ". Creating new DB...";
dbOptions.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(rocksdb::Options(dbOptions, fOptions), dataDir, &dbPtr);
rocksdb::Status status = rocksdb::DB::Open(dbOptions, dataDir, &dbPtr);
if (!status.ok()) {
logger(ERROR) << "DB Error. DB can't be created in " << dataDir << ". Error: " << status.ToString();
throw std::system_error(make_error_code(CryptoNote::error::DataBaseErrorCodes::INTERNAL_ERROR));
Expand All @@ -127,6 +84,26 @@ void RocksDBWrapper::shutdown() {
state.store(NOT_INITIALIZED);
}

void RocksDBWrapper::destoy(const DataBaseConfig& config) {
if (state.load() != NOT_INITIALIZED) {
throw std::system_error(make_error_code(CryptoNote::error::DataBaseErrorCodes::ALREADY_INITIALIZED));
}

std::string dataDir = getDataDir(config);

logger(WARNING) << "Destroying DB in " << dataDir;

rocksdb::Options dbOptions = getDBOptions(config);
rocksdb::Status status = rocksdb::DestroyDB(dataDir, dbOptions);

if (status.ok()) {
logger(WARNING) << "DB destroyed in " << dataDir;
} else {
logger(ERROR) << "DB Error. DB can't be destroyed in " << dataDir << ". Error: " << status.ToString();
throw std::system_error(make_error_code(CryptoNote::error::DataBaseErrorCodes::INTERNAL_ERROR));
}
}

std::error_code RocksDBWrapper::write(IWriteBatch& batch) {
if (state.load() != INITIALIZED) {
throw std::system_error(make_error_code(CryptoNote::error::DataBaseErrorCodes::NOT_INITIALIZED));
Expand Down Expand Up @@ -198,3 +175,54 @@ std::error_code RocksDBWrapper::read(IReadBatch& batch) {
batch.submitRawResult(values, resultStates);
return std::error_code();
}

rocksdb::Options RocksDBWrapper::getDBOptions(const DataBaseConfig& config) {
rocksdb::DBOptions dbOptions;
dbOptions.IncreaseParallelism(config.getBackgroundThreadsCount());
dbOptions.info_log_level = rocksdb::InfoLogLevel::WARN_LEVEL;
dbOptions.max_open_files = config.getMaxOpenFiles();

rocksdb::ColumnFamilyOptions fOptions;
fOptions.write_buffer_size = static_cast<size_t>(config.getWriteBufferSize());
// merge two memtables when flushing to L0
fOptions.min_write_buffer_number_to_merge = 2;
// this means we'll use 50% extra memory in the worst case, but will reduce
// write stalls.
fOptions.max_write_buffer_number = 6;
// start flushing L0->L1 as soon as possible. each file on level0 is
// (memtable_memory_budget / 2). This will flush level 0 when it's bigger than
// memtable_memory_budget.
fOptions.level0_file_num_compaction_trigger = 20;

fOptions.level0_slowdown_writes_trigger = 30;
fOptions.level0_stop_writes_trigger = 40;

// doesn't really matter much, but we don't want to create too many files
fOptions.target_file_size_base = config.getWriteBufferSize() / 10;
// make Level1 size equal to Level0 size, so that L0->L1 compactions are fast
fOptions.max_bytes_for_level_base = config.getWriteBufferSize();
fOptions.num_levels = 10;
fOptions.target_file_size_multiplier = 2;
// level style compaction
fOptions.compaction_style = rocksdb::kCompactionStyleLevel;

fOptions.compression_per_level.resize(fOptions.num_levels);
for (int i = 0; i < fOptions.num_levels; ++i) {
fOptions.compression_per_level[i] = rocksdb::kNoCompression;
}

rocksdb::BlockBasedTableOptions tableOptions;
tableOptions.block_cache = rocksdb::NewLRUCache(config.getReadCacheSize());
std::shared_ptr<rocksdb::TableFactory> tfp(NewBlockBasedTableFactory(tableOptions));
fOptions.table_factory = tfp;

return rocksdb::Options(dbOptions, fOptions);
}

std::string RocksDBWrapper::getDataDir(const DataBaseConfig& config) {
if (config.getTestnet()) {
return config.getDataDir() + '/' + TESTNET_DB_NAME;
} else {
return config.getDataDir() + '/' + DB_NAME;
}
}
4 changes: 4 additions & 0 deletions src/CryptoNoteCore/RocksDBWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class RocksDBWrapper : public IDataBase {

void init(const DataBaseConfig& config);
void shutdown();
void destoy(const DataBaseConfig& config); //Be careful with this method!

std::error_code write(IWriteBatch& batch) override;
std::error_code writeSync(IWriteBatch& batch) override;
Expand All @@ -51,6 +52,9 @@ class RocksDBWrapper : public IDataBase {
private:
std::error_code write(IWriteBatch& batch, bool sync);

rocksdb::Options getDBOptions(const DataBaseConfig& config);
std::string getDataDir(const DataBaseConfig& config);

enum State {
NOT_INITIALIZED,
INITIALIZED
Expand Down
12 changes: 12 additions & 0 deletions src/Daemon/Daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "crypto/hash.h"
#include "CryptoNoteCore/Core.h"
#include "CryptoNoteCore/Currency.h"
#include "CryptoNoteCore/DatabaseBlockchainCache.h"
#include "CryptoNoteCore/DatabaseBlockchainCacheFactory.h"
#include "CryptoNoteCore/MainChainStorage.h"
#include "CryptoNoteCore/MinerConfig.h"
Expand Down Expand Up @@ -219,6 +220,17 @@ int main(int argc, char* argv[])
database.init(dbConfig);
Tools::ScopeExit dbShutdownOnExit([&database] () { database.shutdown(); });

if (!DatabaseBlockchainCache::checkDBSchemeVersion(database, logManager))
{
dbShutdownOnExit.cancel();
database.shutdown();

database.destoy(dbConfig);

database.init(dbConfig);
dbShutdownOnExit.resume();
}

System::Dispatcher dispatcher;
logger(INFO) << "Initializing core...";
CryptoNote::Core ccore(
Expand Down
12 changes: 12 additions & 0 deletions src/PaymentGateService/PaymentGateService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "Common/ScopeExit.h"
#include "CryptoNoteCore/Core.h"
#include "CryptoNoteCore/DatabaseBlockchainCache.h"
#include "CryptoNoteCore/DatabaseBlockchainCacheFactory.h"
#include "CryptoNoteCore/DataBaseConfig.h"
#include "CryptoNoteCore/MainChainStorage.h"
Expand Down Expand Up @@ -179,6 +180,17 @@ void PaymentGateService::runInProcess(Logging::LoggerRef& log) {
database.init(dbConfig);
Tools::ScopeExit dbShutdownOnExit([&database] () { database.shutdown(); });

if (!CryptoNote::DatabaseBlockchainCache::checkDBSchemeVersion(database, logger))
{
dbShutdownOnExit.cancel();
database.shutdown();

database.destoy(dbConfig);

database.init(dbConfig);
dbShutdownOnExit.resume();
}

CryptoNote::Currency currency = currencyBuilder.currency();

log(Logging::INFO) << "initializing core";
Expand Down
2 changes: 1 addition & 1 deletion src/Platform/Linux/System/Dispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ int Dispatcher::getTimer() {
if (timers.empty()) {
timer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
epoll_event timerEvent;
timerEvent.events = 0;
timerEvent.events = EPOLLONESHOT;
timerEvent.data.ptr = nullptr;

if (epoll_ctl(getEpoll(), EPOLL_CTL_ADD, timer, &timerEvent) == -1) {
Expand Down
8 changes: 4 additions & 4 deletions src/Platform/Linux/System/TcpConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,11 @@ size_t TcpConnection::read(uint8_t* data, size_t size) {
assert(dispatcher != nullptr);
assert(contextPair.readContext != nullptr);
epoll_event connectionEvent;
connectionEvent.events = 0;
connectionEvent.events = EPOLLONESHOT;
connectionEvent.data.ptr = nullptr;

if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
throw std::runtime_error("TcpConnection::stop, epoll_ctl failed, " + lastErrorMessage());
throw std::runtime_error("TcpConnection::read, interrupt procedure, epoll_ctl failed, " + lastErrorMessage());
}

contextPair.readContext->interrupted = true;
Expand Down Expand Up @@ -200,11 +200,11 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) {
assert(dispatcher != nullptr);
assert(contextPair.writeContext != nullptr);
epoll_event connectionEvent;
connectionEvent.events = 0;
connectionEvent.events = EPOLLONESHOT;
connectionEvent.data.ptr = nullptr;

if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) {
throw std::runtime_error("TcpConnection::stop, epoll_ctl failed, " + lastErrorMessage());
throw std::runtime_error("TcpConnection::write, interrupt procedure, epoll_ctl failed, " + lastErrorMessage());
}

contextPair.writeContext->interrupted = true;
Expand Down
Loading

0 comments on commit 918aaad

Please sign in to comment.