Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Building Bitcedi
## Building Citadel

### On *nix:

Expand Down
6 changes: 6 additions & 0 deletions ReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Release notes 3.1.0-beta

- Messages 2.0 core support
- Messages API for simplewallet
- Basic access authentication

Release notes 0.1.0

- New industrial type wallet for services: walletd
Expand Down
4 changes: 2 additions & 2 deletions include/IWalletLegacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ class IWalletLegacy {
virtual bool getDeposit(DepositId depositId, Deposit& deposit) = 0;
virtual std::vector<Payments> getTransactionsByPaymentIds(const std::vector<PaymentId>& paymentIds) const = 0;

virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, const std::vector<TransactionMessage>& messages = std::vector<TransactionMessage>()) = 0;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, const std::vector<TransactionMessage>& messages = std::vector<TransactionMessage>()) = 0;
virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, const std::vector<TransactionMessage>& messages = std::vector<TransactionMessage>(), uint64_t ttl = 0) = 0;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, const std::vector<TransactionMessage>& messages = std::vector<TransactionMessage>(), uint64_t ttl = 0) = 0;
virtual TransactionId deposit(uint32_t term, uint64_t amount, uint64_t fee, uint64_t mixIn = 0) = 0;
virtual TransactionId withdrawDeposits(const std::vector<DepositId>& depositIds, uint64_t fee) = 0;
virtual std::error_code cancelTransaction(size_t transferId) = 0;
Expand Down
8 changes: 2 additions & 6 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ add_definitions(-DSTATICLIB)

file(GLOB_RECURSE BlockchainExplorer BlockchainExplorer/*)
file(GLOB_RECURSE Common Common/*)
file(GLOB_RECURSE ConnectivityTool ConnectivityTool/*)
file(GLOB_RECURSE Crypto crypto/*)
file(GLOB_RECURSE CryptoNoteCore CryptoNoteCore/* CryptoNoteConfig.h)
file(GLOB_RECURSE CryptoNoteProtocol CryptoNoteProtocol/*)
Expand Down Expand Up @@ -32,7 +31,7 @@ file(GLOB_RECURSE PaymentGate PaymentGate/*)
file(GLOB_RECURSE PaymentGateService PaymentGateService/*)
file(GLOB_RECURSE Miner Miner/*)

source_group("" FILES $${Common} ${ConnectivityTool} ${Crypto} ${CryptoNoteCore} ${CryptoNoteProtocol} ${Daemon} ${JsonRpcServer} ${Http} ${Logging} ${NodeRpcProxy} ${P2p} ${Rpc} ${Serialization} ${SimpleWallet} ${System} ${Transfers} ${Wallet} ${WalletLegacy})
source_group("" FILES $${Common} ${Crypto} ${CryptoNoteCore} ${CryptoNoteProtocol} ${Daemon} ${JsonRpcServer} ${Http} ${Logging} ${NodeRpcProxy} ${P2p} ${Rpc} ${Serialization} ${SimpleWallet} ${System} ${Transfers} ${Wallet} ${WalletLegacy})

add_library(BlockchainExplorer ${BlockchainExplorer})
add_library(Common ${Common})
Expand All @@ -51,7 +50,6 @@ add_library(Wallet ${Wallet} ${WalletLegacy})
add_library(PaymentGate ${PaymentGate})
add_library(JsonRpcServer ${JsonRpcServer})

add_executable(ConnectivityTool ${ConnectivityTool})
add_executable(Daemon ${Daemon})
add_executable(SimpleWallet ${SimpleWallet})
add_executable(PaymentGateService ${PaymentGateService})
Expand All @@ -61,21 +59,19 @@ if (MSVC)
target_link_libraries(System ws2_32)
endif ()

target_link_libraries(ConnectivityTool CryptoNoteCore Common Logging Crypto P2P Rpc Http Serialization System ${Boost_LIBRARIES})
target_link_libraries(CryptoNoteCore Common Logging Crypto P2P Rpc Http Serialization System ${Boost_LIBRARIES})
target_link_libraries(Daemon CryptoNoteCore P2P Rpc Serialization System Http Logging Common Crypto upnpc-static BlockchainExplorer ${Boost_LIBRARIES})
target_link_libraries(SimpleWallet Wallet NodeRpcProxy Transfers Rpc Http Serialization CryptoNoteCore System Logging Common Crypto ${Boost_LIBRARIES})
target_link_libraries(PaymentGateService PaymentGate JsonRpcServer Wallet NodeRpcProxy Transfers CryptoNoteCore Crypto P2P Rpc Http Serialization System Logging Common InProcessNode upnpc-static BlockchainExplorer ${Boost_LIBRARIES})
target_link_libraries(Miner CryptoNoteCore Rpc Serialization System Http Logging Common Crypto ${Boost_LIBRARIES})

add_dependencies(Rpc version)

add_dependencies(ConnectivityTool version)
add_dependencies(Daemon version)
add_dependencies(SimpleWallet version)
add_dependencies(PaymentGateService version)
add_dependencies(P2P version)

set_property(TARGET ConnectivityTool PROPERTY OUTPUT_NAME "connectivity_tool")
set_property(TARGET SimpleWallet PROPERTY OUTPUT_NAME "bitcediwallet")
set_property(TARGET PaymentGateService PROPERTY OUTPUT_NAME "walletd")
set_property(TARGET Miner PROPERTY OUTPUT_NAME "miner")
Expand Down
18 changes: 9 additions & 9 deletions src/Common/Base58.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ namespace Tools
uint64_t res = 0;
switch (9 - size)
{
case 1: res |= *data++;
case 2: res <<= 8; res |= *data++;
case 3: res <<= 8; res |= *data++;
case 4: res <<= 8; res |= *data++;
case 5: res <<= 8; res |= *data++;
case 6: res <<= 8; res |= *data++;
case 7: res <<= 8; res |= *data++;
case 8: res <<= 8; res |= *data; break;
default: assert(false);
case 1: res |= *data++; /* FALLTHRU */
case 2: res <<= 8; res |= *data++; /* FALLTHRU */
case 3: res <<= 8; res |= *data++; /* FALLTHRU */
case 4: res <<= 8; res |= *data++; /* FALLTHRU */
case 5: res <<= 8; res |= *data++; /* FALLTHRU */
case 6: res <<= 8; res |= *data++; /* FALLTHRU */
case 7: res <<= 8; res |= *data++; /* FALLTHRU */
case 8: res <<= 8; res |= *data; break;
default: assert(false);
}

return res;
Expand Down
37 changes: 34 additions & 3 deletions src/Common/ConsoleHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,40 @@ bool ConsoleHandler::runCommand(const std::vector<std::string>& cmdAndArgs) {
}

void ConsoleHandler::handleCommand(const std::string& cmd) {
std::vector<std::string> args;
boost::split(args, cmd, boost::is_any_of(" "), boost::token_compress_on);
runCommand(args);
bool parseString = false;
std::string arg;
std::vector<std::string> argList;

for (auto ch : cmd) {
switch (ch) {
case ' ':
if (parseString) {
arg += ch;
} else if (!arg.empty()) {
argList.emplace_back(std::move(arg));
arg.clear();
}
break;

case '"':
if (!arg.empty()) {
argList.emplace_back(std::move(arg));
arg.clear();
}

parseString = !parseString;
break;

default:
arg += ch;
}
}

if (!arg.empty()) {
argList.emplace_back(std::move(arg));
}

runCommand(argList);
}

void ConsoleHandler::handlerThread() {
Expand Down
5 changes: 2 additions & 3 deletions src/Common/JsonValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,9 +638,8 @@ std::ostream& operator<<(std::ostream& out, const JsonValue& jsonValue) {
namespace {

char readChar(std::istream& in) {
char c;

if (!(in >> c)) {
char c = static_cast<char>(in.get());
if (!in) {
throw std::runtime_error("Unable to parse: unexpected end of stream");
}

Expand Down
19 changes: 11 additions & 8 deletions src/CryptoNoteConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
namespace CryptoNote {
namespace parameters {

const uint64_t DIFFICULTY_TARGET = 240; // seconds
const uint64_t CRYPTONOTE_MAX_BLOCK_NUMBER = 500000000;
const size_t CRYPTONOTE_MAX_BLOCK_BLOB_SIZE = 500000000;
const size_t CRYPTONOTE_MAX_TX_SIZE = 1000000000;
const uint64_t CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0xd7; // addresses start with "0xc"
const size_t CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW = 6;
const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT = 60 * 60 * 2;

const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT = DIFFICULTY_TARGET * 3;
const size_t BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW = 30;

const uint64_t MONEY_SUPPLY = UINT64_C(858986905600000000);
Expand All @@ -31,10 +31,11 @@ const uint64_t COIN = UINT64_C(10000000
const uint64_t MINIMUM_FEE = UINT64_C(100000); // pow(10, 5)
const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(100000); // pow(10, 5)
//const uint64_t GENESIS_BLOCK_REWARD = UINT64_C(0);
const uint64_t MAX_TX_MIXIN_SIZE = 50;

const uint64_t DIFFICULTY_TARGET = 240; // seconds
const uint64_t EXPECTED_NUMBER_OF_BLOCKS_PER_DAY = 24 * 60 * 60 / DIFFICULTY_TARGET;
const size_t DIFFICULTY_WINDOW = 240; // blocks
const size_t DIFFICULTY_WINDOW_V2 = 60; // blocks
const size_t DIFFICULTY_CUT = 30; // timestamps to cut after sorting
const size_t DIFFICULTY_LAG = 15;
static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Bad DIFFICULTY_WINDOW or DIFFICULTY_CUT");
Expand Down Expand Up @@ -63,7 +64,8 @@ const size_t FUSION_TX_MAX_SIZE = CRYPTONOTE_BLOCK_
const size_t FUSION_TX_MIN_INPUT_COUNT = 12;
const size_t FUSION_TX_MIN_IN_OUT_COUNT_RATIO = 4;

const uint64_t UPGRADE_HEIGHT = 1;
const uint32_t UPGRADE_HEIGHT_V2 = 1;
const uint32_t UPGRADE_HEIGHT_V3 = 170500;
const unsigned UPGRADE_VOTING_THRESHOLD = 90; // percent
const size_t UPGRADE_VOTING_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks
const size_t UPGRADE_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks
Expand All @@ -83,14 +85,15 @@ const uint64_t START_BLOCK_REWARD = (UINT64_C(80) * p
const uint64_t MIN_BLOCK_REWARD = (UINT64_C(5) * parameters::COIN);
const uint64_t REWARD_HALVING_INTERVAL = (UINT64_C(66000));

const char CRYPTONOTE_NAME[] = "bitcedi";
const char CRYPTONOTE_NAME[] = "citadel";
const char GENESIS_COINBASE_TX_HEX[] = "010601ff000180a0d9e61d029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121019e2d1a633f2a54ff1a415e0051d5a699461d9c95479f67c8568446581c2e3782";
const uint32_t GENESIS_NONCE = 70;

const uint8_t TRANSACTION_VERSION_1 = 1;
const uint8_t TRANSACTION_VERSION_2 = 2;
const uint8_t BLOCK_MAJOR_VERSION_1 = 1;
const uint8_t BLOCK_MAJOR_VERSION_2 = 2;
const uint8_t BLOCK_MAJOR_VERSION_3 = 3;
const uint8_t BLOCK_MINOR_VERSION_0 = 0;
const uint8_t BLOCK_MINOR_VERSION_1 = 1;

Expand All @@ -117,9 +120,9 @@ const size_t P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT = 5000; //
const char P2P_STAT_TRUSTED_PUB_KEY[] = "85ae8734f90bc1ee295ceb0ec05a49852d4dbbc9d1c27a619b5f4bdf26a0196e";

const std::initializer_list<const char*> SEED_NODES = {
"seed0.bitcedi.org:55008",
"seed1.bitcedi.org:55008",
"seed2.bitcedi.org:55008"
"173.230.155.185:55008",
"172.104.240.101:55008",
"45.33.53.50:55008"
};

struct CheckpointData {
Expand Down
61 changes: 45 additions & 16 deletions src/CryptoNoteCore/Blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,8 @@ m_tx_pool(tx_pool),
m_current_block_cumul_sz_limit(0),
m_is_in_checkpoint_zone(false),
m_checkpoints(logger),
m_upgradeDetector(currency, m_blocks, BLOCK_MAJOR_VERSION_2, logger) {
m_upgradeDetectorV2(currency, m_blocks, BLOCK_MAJOR_VERSION_2, logger),
m_upgradeDetectorV3(currency, m_blocks, BLOCK_MAJOR_VERSION_3, logger) {

m_outputs.set_deleted_key(0);
m_multisignatureOutputs.set_deleted_key(0);
Expand Down Expand Up @@ -449,7 +450,12 @@ bool Blockchain::init(const std::string& config_folder, bool load_existing) {
}
}

if (!m_upgradeDetector.init()) {
if (!m_upgradeDetectorV2.init()) {
logger(ERROR, BRIGHT_RED) << "Failed to initialize upgrade detector";
return false;
}

if (!m_upgradeDetectorV3.init()) {
logger(ERROR, BRIGHT_RED) << "Failed to initialize upgrade detector";
return false;
}
Expand Down Expand Up @@ -651,7 +657,8 @@ difficulty_type Blockchain::getDifficultyForNextBlock() {
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> commulative_difficulties;
size_t offset = m_blocks.size() - std::min(m_blocks.size(), static_cast<uint64_t>(m_currency.difficultyBlocksCount()));
uint8_t BlockMajorVersion = m_blocks.size() >= m_upgradeDetectorV3.upgradeHeight() ? m_upgradeDetectorV3.targetVersion() : BLOCK_MAJOR_VERSION_1;
size_t offset = m_blocks.size() - std::min(m_blocks.size(), static_cast<uint64_t>((BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount())));
if (offset == 0) {
++offset;
}
Expand All @@ -661,7 +668,12 @@ difficulty_type Blockchain::getDifficultyForNextBlock() {
commulative_difficulties.push_back(m_blocks[offset].cumulative_difficulty);
}

return m_currency.nextDifficulty(timestamps, commulative_difficulties);
return m_currency.nextDifficulty(BlockMajorVersion, timestamps, commulative_difficulties);
}

uint64_t Blockchain::getBlockTimestamp(uint32_t height) {
assert(height < m_blocks.size());
return m_blocks[height].bl.timestamp;
}

uint64_t Blockchain::getCoinsInCirculation() {
Expand Down Expand Up @@ -690,7 +702,13 @@ difficulty_type Blockchain::difficultyAtHeight(uint64_t height) {
}

uint8_t Blockchain::get_block_major_version_for_height(uint64_t height) const {
return height > m_upgradeDetector.upgradeHeight() ? m_upgradeDetector.targetVersion() : BLOCK_MAJOR_VERSION_1;
if (height > m_upgradeDetectorV3.upgradeHeight()) {
return m_upgradeDetectorV3.targetVersion();
} else if (height > m_upgradeDetectorV2.upgradeHeight()) {
return m_upgradeDetectorV2.targetVersion();
} else {
return BLOCK_MAJOR_VERSION_1;
}
}

bool Blockchain::rollback_blockchain_switching(std::list<Block> &original_chain, size_t rollback_height) {
Expand Down Expand Up @@ -797,10 +815,13 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, BlockEntry& bei) {
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> commulative_difficulties;
if (alt_chain.size() < m_currency.difficultyBlocksCount()) {
uint8_t BlockMajorVersion = m_blocks.size() >= m_upgradeDetectorV3.upgradeHeight() ? m_upgradeDetectorV3.targetVersion() : BLOCK_MAJOR_VERSION_1;
if (alt_chain.size() < (BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount())) {
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);
size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front()->second.height : bei.height;
size_t main_chain_count = m_currency.difficultyBlocksCount() - std::min(m_currency.difficultyBlocksCount(), alt_chain.size());
size_t main_chain_count = (BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 :
m_currency.difficultyBlocksCount()) - std::min((BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 :
m_currency.difficultyBlocksCount()), alt_chain.size());
main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;

Expand All @@ -811,30 +832,30 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
commulative_difficulties.push_back(m_blocks[main_chain_start_offset].cumulative_difficulty);
}

if (!((alt_chain.size() + timestamps.size()) <= m_currency.difficultyBlocksCount())) {
if (!((alt_chain.size() + timestamps.size()) <= (BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount()))) {
logger(ERROR, BRIGHT_RED) << "Internal error, alt_chain.size()[" << alt_chain.size() << "] + timestamps.size()[" << timestamps.size() <<
"] NOT <= m_currency.difficultyBlocksCount()[" << m_currency.difficultyBlocksCount() << ']'; return false;
"] NOT <= m_currency.difficultyBlocksCount()[" << (BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount()) << ']'; return false;
}
for (auto it : alt_chain) {
timestamps.push_back(it->second.bl.timestamp);
commulative_difficulties.push_back(it->second.cumulative_difficulty);
}
} else {
timestamps.resize(std::min(alt_chain.size(), m_currency.difficultyBlocksCount()));
commulative_difficulties.resize(std::min(alt_chain.size(), m_currency.difficultyBlocksCount()));
timestamps.resize(std::min(alt_chain.size(), (BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount())));
commulative_difficulties.resize(std::min(alt_chain.size(), (BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount())));
size_t count = 0;
size_t max_i = timestamps.size() - 1;
BOOST_REVERSE_FOREACH(auto it, alt_chain) {
timestamps[max_i - count] = it->second.bl.timestamp;
commulative_difficulties[max_i - count] = it->second.cumulative_difficulty;
count++;
if (count >= m_currency.difficultyBlocksCount()) {
if (count >= (BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount())) {
break;
}
}
}

return m_currency.nextDifficulty(timestamps, commulative_difficulties);
return m_currency.nextDifficulty(BlockMajorVersion, timestamps, commulative_difficulties);
}

bool Blockchain::prevalidate_miner_transaction(const Block& b, uint32_t height) {
Expand Down Expand Up @@ -1449,6 +1470,12 @@ bool Blockchain::checkTransactionInputs(const Transaction& tx, const Crypto::Has
for (const auto& txin : tx.inputs) {
assert(inputIndex < tx.signatures.size());
if (txin.type() == typeid(KeyInput)) {
uint64_t txMixin = boost::get<KeyInput>(txin).outputIndexes.size();
if (txMixin > CryptoNote::parameters::MAX_TX_MIXIN_SIZE) {
logger(DEBUGGING, BRIGHT_WHITE) << "Transaction << " << transactionHash << " hast too large mixin count.";
return false;
}

const KeyInput& in_to_key = boost::get<KeyInput>(txin);
if (!(!in_to_key.outputIndexes.empty())) { logger(ERROR, BRIGHT_RED) << "empty in_to_key.outputIndexes in transaction with id " << getObjectHash(tx); return false; }

Expand Down Expand Up @@ -1790,7 +1817,7 @@ bool Blockchain::pushBlock(const Block& blockData, const std::vector<Transaction
} else {
if (!m_currency.checkProofOfWork(m_cn_context, blockData, currentDifficulty, proof_of_work)) {
logger(INFO, BRIGHT_WHITE) <<
"Block " << blockHash << ", has too weak proof of work: " << proof_of_work << ", expected difficulty: " << currentDifficulty;
"Block " << blockHash << ", has too weak proof of work: " << Common::podToHex(proof_of_work) << ", expected difficulty: " << currentDifficulty << " MajorVersion: " << std::to_string(blockData.majorVersion);
bvc.m_verifivation_failed = true;
return false;
}
Expand Down Expand Up @@ -1896,7 +1923,8 @@ bool Blockchain::pushBlock(const Block& blockData, const std::vector<Transaction

bvc.m_added_to_main_chain = true;

m_upgradeDetector.blockPushed();
m_upgradeDetectorV2.blockPushed();
m_upgradeDetectorV3.blockPushed();
update_next_comulative_size_limit();

return true;
Expand Down Expand Up @@ -1984,7 +2012,8 @@ void Blockchain::popBlock(const Crypto::Hash& blockHash) {

assert(m_blockIndex.size() == m_blocks.size());

m_upgradeDetector.blockPopped();
m_upgradeDetectorV2.blockPopped();
m_upgradeDetectorV3.blockPopped();
}

bool Blockchain::pushTransaction(BlockEntry& block, const Crypto::Hash& transactionHash, TransactionIndex transactionIndex) {
Expand Down
Loading