diff --git a/README.md b/README.md index f79bab2a..9a335bdc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![image](https://github.com/ConcealNetwork/conceal-assets/blob/master/splash.png) # Conceal Core (CLI) -Latest Release: v5.1.7 +Latest Release: v5.1.9 Maintained by The Circle Team. ## Information diff --git a/include/IWallet.h b/include/IWallet.h index 7ab49c88..37f6480b 100644 --- a/include/IWallet.h +++ b/include/IWallet.h @@ -138,6 +138,7 @@ class IWallet { virtual std::string createAddress(const Crypto::PublicKey& spendPublicKey) = 0; virtual void deleteAddress(const std::string& address) = 0; + virtual uint64_t getActualBalance() const = 0; virtual uint64_t getActualBalance(const std::string& address) const = 0; virtual uint64_t getPendingBalance() const = 0; diff --git a/include/IWalletLegacy.h b/include/IWalletLegacy.h index acc57d61..d4cb3a2c 100644 --- a/include/IWalletLegacy.h +++ b/include/IWalletLegacy.h @@ -123,6 +123,7 @@ class IWalletLegacy { virtual std::string getAddress() = 0; virtual uint64_t actualBalance() = 0; + virtual uint64_t dustBalance() = 0; virtual uint64_t pendingBalance() = 0; virtual uint64_t actualDepositBalance() = 0; diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index cadfe80b..f3cbf5ef 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -12,109 +12,104 @@ namespace CryptoNote { namespace parameters { -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 = 0x7ad4; // addresses start with "ccx7" -const size_t CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW = 10; // 20m unlock -const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT = 60 * 60 * 2; // was 2 hours, not 3 * T -const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V1 = 360; // LWMA3 -const uint64_t CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE = 10; // 20m unlock - -const size_t BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW = 30; -const size_t BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V1 = 11; // LWMA3 - -const uint64_t MONEY_SUPPLY = UINT64_C(200000000000000); // max supply: 200M (Consensus II) - -const uint32_t ZAWY_DIFFICULTY_BLOCK_INDEX = 0; -const size_t ZAWY_DIFFICULTY_FIX = 1; -const uint8_t ZAWY_DIFFICULTY_BLOCK_VERSION = 0; - -const size_t CRYPTONOTE_REWARD_BLOCKS_WINDOW = 100; -const size_t CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE = 100000; // size of block (bytes): after which reward is calculated using block size -const size_t CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE = 600; -const size_t CRYPTONOTE_DISPLAY_DECIMAL_POINT = 6; - -// COIN - number of smallest units in one coin -const uint64_t POINT = UINT64_C(1000); // pow(10, 3) -const uint64_t COIN = UINT64_C(1000000); // pow(10, 6) -const uint64_t MINIMUM_FEE = UINT64_C(10); // pow(10, 1) -const uint64_t MINIMUM_FEE_V1 = UINT64_C(100); // fee increase -const uint64_t MINIMUM_FEE_BANKING = UINT64_C(1000); // fee increase -const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(10); // pow(10, 1) - -const uint64_t DIFFICULTY_TARGET = 120; // seconds = 2m -const uint64_t EXPECTED_NUMBER_OF_BLOCKS_PER_DAY = 24 * 60 * 60 / DIFFICULTY_TARGET; -const size_t DIFFICULTY_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks -const size_t DIFFICULTY_WINDOW_V1 = DIFFICULTY_WINDOW; -const size_t DIFFICULTY_WINDOW_V2 = DIFFICULTY_WINDOW; -const size_t DIFFICULTY_WINDOW_V3 = 60; // LWMA3 -const size_t DIFFICULTY_BLOCKS_COUNT = DIFFICULTY_WINDOW_V3 + 1; // LWMA3 -const size_t DIFFICULTY_CUT = 60; // timestamps to cut after sorting -const size_t DIFFICULTY_CUT_V1 = DIFFICULTY_CUT; -const size_t DIFFICULTY_CUT_V2 = DIFFICULTY_CUT; -const size_t DIFFICULTY_LAG = 15; -const size_t DIFFICULTY_LAG_V1 = DIFFICULTY_LAG; -const size_t DIFFICULTY_LAG_V2 = DIFFICULTY_LAG; +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 = 0x7ad4; /* ccx7 address prefix */ +const size_t CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW = 10; /* 20 minutes */ +const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT = 60 * 60 * 2; /* two hours */ +const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V1 = 360; /* changed for LWMA3 */ +const uint64_t CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE = 10; /* 20 minutes */ + +const size_t BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW = 30; +const size_t BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V1 = 11; /* changed for LWMA3 */ + +const uint64_t MONEY_SUPPLY = UINT64_C(200000000000000); /* max supply: 200M (Consensus II) */ + +const uint32_t ZAWY_DIFFICULTY_BLOCK_INDEX = 0; +const size_t ZAWY_DIFFICULTY_FIX = 1; +const uint8_t ZAWY_DIFFICULTY_BLOCK_VERSION = 0; + +const size_t CRYPTONOTE_REWARD_BLOCKS_WINDOW = 100; +const size_t CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE = 100000; /* size of block in bytes, after which reward is calculated using block size */ +const size_t CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE = 600; +const size_t CRYPTONOTE_DISPLAY_DECIMAL_POINT = 6; + +const uint64_t POINT = UINT64_C(1000); +const uint64_t COIN = UINT64_C(1000000); /* smallest atomic unit */ +const uint64_t MINIMUM_FEE = UINT64_C(10); /* 0.000010 CCX */ +const uint64_t MINIMUM_FEE_V1 = UINT64_C(100); /* 0.000100 CCX */ +const uint64_t MINIMUM_FEE_BANKING = UINT64_C(1000); /* 0.001000 CCX */ +const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(10); /* 0.000010 CCX */ + +const uint64_t DIFFICULTY_TARGET = 120; /* two minutes */ +const uint64_t EXPECTED_NUMBER_OF_BLOCKS_PER_DAY = 24 * 60 * 60 / DIFFICULTY_TARGET; /* 720 blocks */ +const size_t DIFFICULTY_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; +const size_t DIFFICULTY_WINDOW_V1 = DIFFICULTY_WINDOW; +const size_t DIFFICULTY_WINDOW_V2 = DIFFICULTY_WINDOW; +const size_t DIFFICULTY_WINDOW_V3 = 60; /* changed for LWMA3 */ +const size_t DIFFICULTY_BLOCKS_COUNT = DIFFICULTY_WINDOW_V3 + 1; /* added for LWMA3 */ +const size_t DIFFICULTY_CUT = 60; /* timestamps to cut after sorting */ +const size_t DIFFICULTY_CUT_V1 = DIFFICULTY_CUT; +const size_t DIFFICULTY_CUT_V2 = DIFFICULTY_CUT; +const size_t DIFFICULTY_LAG = 15; +const size_t DIFFICULTY_LAG_V1 = DIFFICULTY_LAG; +const size_t DIFFICULTY_LAG_V2 = DIFFICULTY_LAG; static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Bad DIFFICULTY_WINDOW or DIFFICULTY_CUT"); -const uint64_t DEPOSIT_MIN_AMOUNT = 1 * COIN; // minimun mmount for a valid deposit -const uint32_t DEPOSIT_MIN_TERM = 5040; // ~1 week -const uint32_t DEPOSIT_MAX_TERM = 1 * 12 * 21900; // ~1 year -const uint32_t DEPOSIT_MAX_TERM_V1 = 64800 * 20; // ~5 year -const uint64_t DEPOSIT_MIN_TOTAL_RATE_FACTOR = 0; // rate is constant -const uint64_t DEPOSIT_MAX_TOTAL_RATE = 4; // percentage rate for DEPOSIT_MAX_TERM +const uint64_t DEPOSIT_MIN_AMOUNT = 1 * COIN; +const uint32_t DEPOSIT_MIN_TERM = 5040; /* one week */ +const uint32_t DEPOSIT_MAX_TERM = 1 * 12 * 21900; /* legacy deposts - one year */ +const uint32_t DEPOSIT_MAX_TERM_V1 = 64800 * 20; /* five years */ +const uint64_t DEPOSIT_MIN_TOTAL_RATE_FACTOR = 0; /* constant rate */ +const uint64_t DEPOSIT_MAX_TOTAL_RATE = 4; /* legacy deposits */ static_assert(DEPOSIT_MIN_TERM > 0, "Bad DEPOSIT_MIN_TERM"); static_assert(DEPOSIT_MIN_TERM <= DEPOSIT_MAX_TERM, "Bad DEPOSIT_MAX_TERM"); static_assert(DEPOSIT_MIN_TERM * DEPOSIT_MAX_TOTAL_RATE > DEPOSIT_MIN_TOTAL_RATE_FACTOR, "Bad DEPOSIT_MIN_TOTAL_RATE_FACTOR or DEPOSIT_MAX_TOTAL_RATE"); -const uint64_t MULTIPLIER_FACTOR = 100; -const uint32_t END_MULTIPLIER_BLOCK = 12750; +const uint64_t MULTIPLIER_FACTOR = 100; /* legacy deposits */ +const uint32_t END_MULTIPLIER_BLOCK = 12750; /* legacy deposits */ -const size_t MAX_BLOCK_SIZE_INITIAL = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE * 10; -const uint64_t MAX_BLOCK_SIZE_GROWTH_SPEED_NUMERATOR = 100 * 1024; -const uint64_t MAX_BLOCK_SIZE_GROWTH_SPEED_DENOMINATOR = 365 * 24 * 60 * 60 / DIFFICULTY_TARGET; +const size_t MAX_BLOCK_SIZE_INITIAL = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE * 10; +const uint64_t MAX_BLOCK_SIZE_GROWTH_SPEED_NUMERATOR = 100 * 1024; +const uint64_t MAX_BLOCK_SIZE_GROWTH_SPEED_DENOMINATOR = 365 * 24 * 60 * 60 / DIFFICULTY_TARGET; -const uint64_t CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS = 1; -const uint64_t CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS = DIFFICULTY_TARGET * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS; +const uint64_t CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS = 1; +const uint64_t CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS = DIFFICULTY_TARGET * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS; -const size_t CRYPTONOTE_MAX_TX_SIZE_LIMIT = (CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE / 4) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; -const size_t CRYPTONOTE_OPTIMIZE_SIZE = 100; // proportional to CRYPTONOTE_MAX_TX_SIZE_LIMIT +const size_t CRYPTONOTE_MAX_TX_SIZE_LIMIT = (CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE / 4) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; /* maximum transaction size */ +const size_t CRYPTONOTE_OPTIMIZE_SIZE = 100; /* proportional to CRYPTONOTE_MAX_TX_SIZE_LIMIT */ -const uint64_t CRYPTONOTE_MEMPOOL_TX_LIVETIME = (60 * 60 * 12); // seconds, 12 hours -const uint64_t CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME = (60 * 60 * 24); // seconds, 1 day -const uint64_t CRYPTONOTE_NUMBER_OF_PERIODS_TO_FORGET_TX_DELETED_FROM_POOL = 7; // CRYPTONOTE_NUMBER_OF_PERIODS_TO_FORGET_TX_DELETED_FROM_POOL * CRYPTONOTE_MEMPOOL_TX_LIVETIME = time to forget tx +const uint64_t CRYPTONOTE_MEMPOOL_TX_LIVETIME = (60 * 60 * 12); /* 12 hours in seconds */ +const uint64_t CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME = (60 * 60 * 24); /* 23 hours in seconds */ +const uint64_t CRYPTONOTE_NUMBER_OF_PERIODS_TO_FORGET_TX_DELETED_FROM_POOL = 7; /* CRYPTONOTE_NUMBER_OF_PERIODS_TO_FORGET_TX_DELETED_FROM_POOL * CRYPTONOTE_MEMPOOL_TX_LIVETIME = time to forget tx */ -const size_t FUSION_TX_MAX_SIZE = CRYPTONOTE_MAX_TX_SIZE_LIMIT * 2; -const size_t FUSION_TX_MIN_INPUT_COUNT = 12; -const size_t FUSION_TX_MIN_IN_OUT_COUNT_RATIO = 4; +const size_t FUSION_TX_MAX_SIZE = CRYPTONOTE_MAX_TX_SIZE_LIMIT * 2; +const size_t FUSION_TX_MIN_INPUT_COUNT = 12; +const size_t FUSION_TX_MIN_IN_OUT_COUNT_RATIO = 4; -static constexpr uint64_t POISSON_CHECK_TRIGGER = 10; // Reorg size that triggers poisson timestamp check -static constexpr uint64_t POISSON_CHECK_DEPTH = 60; // Main-chain depth of the poisson check. The attacker will have to tamper 50% of those blocks -static constexpr double POISSON_LOG_P_REJECT = -75.0; // Reject reorg if the probablity that the timestamps are genuine is below e^x, -75 = 10^-33 - -const uint64_t UPGRADE_HEIGHT = 1; -const uint64_t UPGRADE_HEIGHT_V2 = 1; -const uint64_t UPGRADE_HEIGHT_V3 = 12750; // CN Fast fork -const uint64_t UPGRADE_HEIGHT_V4 = 45000; // Mixin >2 fork -const uint64_t UPGRADE_HEIGHT_V5 = 98160; // Deposits 2.0, Investments 1.0 -const uint64_t UPGRADE_HEIGHT_V6 = 104200; // LWMA3 -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 +const uint64_t UPGRADE_HEIGHT = 1; +const uint64_t UPGRADE_HEIGHT_V2 = 1; +const uint64_t UPGRADE_HEIGHT_V3 = 12750; /* Cryptonight-Fast */ +const uint64_t UPGRADE_HEIGHT_V4 = 45000; /* MixIn 2 */ +const uint64_t UPGRADE_HEIGHT_V5 = 98160; /* Deposits 2.0, Investments 1.0 */ +const uint64_t UPGRADE_HEIGHT_V6 = 104200; /* LWMA3 */ +const unsigned UPGRADE_VOTING_THRESHOLD = 90; // percent +const size_t UPGRADE_VOTING_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; +const size_t UPGRADE_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; static_assert(0 < UPGRADE_VOTING_THRESHOLD && UPGRADE_VOTING_THRESHOLD <= 100, "Bad UPGRADE_VOTING_THRESHOLD"); static_assert(UPGRADE_VOTING_WINDOW > 1, "Bad UPGRADE_VOTING_WINDOW"); -const char CRYPTONOTE_BLOCKS_FILENAME[] = "blocks.dat"; -const char CRYPTONOTE_BLOCKINDEXES_FILENAME[] = "blockindexes.dat"; -const char CRYPTONOTE_BLOCKSCACHE_FILENAME[] = "blockscache.dat"; -const char CRYPTONOTE_POOLDATA_FILENAME[] = "poolstate.bin"; -const char P2P_NET_DATA_FILENAME[] = "p2pstate.bin"; -const char CRYPTONOTE_BLOCKCHAIN_INDICES_FILENAME[] = "blockchainindices.dat"; -const char MINER_CONFIG_FILE_NAME[] = "miner_conf.json"; +const char CRYPTONOTE_BLOCKS_FILENAME[] = "blocks.dat"; +const char CRYPTONOTE_BLOCKINDEXES_FILENAME[] = "blockindexes.dat"; +const char CRYPTONOTE_BLOCKSCACHE_FILENAME[] = "blockscache.dat"; +const char CRYPTONOTE_POOLDATA_FILENAME[] = "poolstate.bin"; +const char P2P_NET_DATA_FILENAME[] = "p2pstate.bin"; +const char CRYPTONOTE_BLOCKCHAIN_INDICES_FILENAME[] = "blockchainindices.dat"; +const char MINER_CONFIG_FILE_NAME[] = "miner_conf.json"; } // parameters @@ -147,7 +142,7 @@ const int RPC_DEFAULT_PORT = 16000; const size_t P2P_LOCAL_WHITE_PEERLIST_LIMIT = 1000; const size_t P2P_LOCAL_GRAY_PEERLIST_LIMIT = 5000; -const size_t P2P_CONNECTION_MAX_WRITE_BUFFER_SIZE = 64 * 1024 * 1024; // 16MB +const size_t P2P_CONNECTION_MAX_WRITE_BUFFER_SIZE = 64 * 1024 * 1024; // 64MB const uint32_t P2P_DEFAULT_CONNECTIONS_COUNT = 8; const size_t P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT = 70; // percent const uint32_t P2P_DEFAULT_HANDSHAKE_INTERVAL = 60; // seconds @@ -207,11 +202,12 @@ const std::initializer_list CHECKPOINTS = { {115000, "6000e495db0cdf043f474949e3e708a8c670f99f1232711be4789fecffbfb4d8"}, {120000, "f621bd615716b75716eb89714d60481077a16b1df4046bf829f6d09b1c8e58a6"}, {125000, "0a783373ed67adbd3bc3904496e813bc481018e9f5a91681ff74416de0f805e4"}, - {128844, "32995417568bdeb9c24ba9bbcfd6124882c8acae0fd10e9f8d052637bbafcc19"}, - {128850, "7b8c9784d2639d61d41149095d4a9cd23ab579b780e42b45bc77863a457ac84e"}, {130000, "deb2514d03e2faf1c63b55f707b1524665ca4bd71cace3f4e8f0de58f32ecc41"}, {135000, "466d509486fe791b7af6d222c026eba29848b66302c6fd44dd26386d98acaa5a"}, - {140000, "c439524c13187bb6008acb1e9999317aa44e8d1cd75c96faae78831f6b961bac"} + {140000, "c439524c13187bb6008acb1e9999317aa44e8d1cd75c96faae78831f6b961bac"}, + {145000, "9e1c4319e40a2c61abc5d405399f2add93a1394d77eb8eeaf4115f41a06e1d7b"}, + {150000, "90cc70379ea81d47df998e8b9928ba9191968035ae79ec1cb429c64a55497e03"}, + {155000, "c2f913d25d0367927419c85d28c934bdc56cd8f951e638f1dc50c3a125def561"} }; } // CryptoNote diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index c4c57102..98eba11c 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -457,6 +457,15 @@ bool Blockchain::init(const std::string& config_folder, bool load_existing) { } } + /* If the currrent checkpoint is invalid, then rollback the chain to the last + valid checkpoint and try again. */ + uint32_t lastValidCheckpointHeight = 0; + if (!checkCheckpoints(lastValidCheckpointHeight)) { + logger(WARNING, BRIGHT_YELLOW) << "Invalid checkpoint. Rollback blockchain to last valid checkpoint at height " << lastValidCheckpointHeight; + rollbackBlockchainTo(lastValidCheckpointHeight); + } + + if (!m_upgradeDetectorV2.init()) { logger(ERROR, BRIGHT_RED) << "<< Blockchain.cpp << " << "Failed to initialize upgrade detector"; return false; @@ -487,6 +496,23 @@ bool Blockchain::init(const std::string& config_folder, bool load_existing) { return true; } +bool Blockchain::checkCheckpoints(uint32_t& lastValidCheckpointHeight) { + std::vector checkpointHeights = m_checkpoints.getCheckpointHeights(); + for (const auto& checkpointHeight : checkpointHeights) { + if (m_blocks.size() <= checkpointHeight) { + return true; + } + + if(m_checkpoints.check_block(checkpointHeight, getBlockIdByHeight(checkpointHeight))) { + lastValidCheckpointHeight = checkpointHeight; + } else { + return false; + } + } + + return true; +} + void Blockchain::rebuildCache() { logger(INFO, BRIGHT_WHITE) << "<< Blockchain.cpp << " << "Rebuilding cache"; @@ -2440,6 +2466,37 @@ bool Blockchain::validateInput(const MultisignatureInput& input, const Crypto::H return true; } +bool Blockchain::rollbackBlockchainTo(uint32_t height) { + logger(INFO) << "Rolling back blockchain to " << height; + while (height + 1 < m_blocks.size()) { + removeLastBlock(); + } + logger(INFO) << "Rollback complete. Synchronization will resume."; + return true; +} + +bool Blockchain::removeLastBlock() { + if (m_blocks.empty()) { + logger(ERROR, BRIGHT_RED) << + "Attempt to pop block from empty blockchain."; + return false; + } + + logger(DEBUGGING) << "Removing last block with height " << m_blocks.back().height; + popTransactions(m_blocks.back(), getObjectHash(m_blocks.back().bl.baseTransaction)); + + Crypto::Hash blockHash = getBlockIdByHeight(m_blocks.back().height); + m_timestampIndex.remove(m_blocks.back().bl.timestamp, blockHash); + m_generatedTransactionsIndex.remove(m_blocks.back().bl); + + m_blocks.pop_back(); + m_blockIndex.pop(); + + assert(m_blockIndex.size() == m_blocks.size()); + return true; +} + + bool Blockchain::getLowerBound(uint64_t timestamp, uint64_t startOffset, uint32_t& height) { std::lock_guard lk(m_blockchain_lock); diff --git a/src/CryptoNoteCore/Blockchain.h b/src/CryptoNoteCore/Blockchain.h index 94ab8f9a..8d391ece 100644 --- a/src/CryptoNoteCore/Blockchain.h +++ b/src/CryptoNoteCore/Blockchain.h @@ -184,6 +184,8 @@ namespace CryptoNote { } }; +bool rollbackBlockchainTo(uint32_t height); + private: struct MultisignatureOutputUsage { @@ -308,7 +310,8 @@ namespace CryptoNote { void popTransaction(const Transaction& transaction, const Crypto::Hash& transactionHash); void popTransactions(const BlockEntry& block, const Crypto::Hash& minerTransactionHash); bool validateInput(const MultisignatureInput& input, const Crypto::Hash& transactionHash, const Crypto::Hash& transactionPrefixHash, const std::vector& transactionSignatures); - + bool removeLastBlock(); + bool checkCheckpoints(uint32_t& lastValidCheckpointHeight); bool storeBlockchainIndices(); bool loadBlockchainIndices(); diff --git a/src/CryptoNoteCore/Checkpoints.cpp b/src/CryptoNoteCore/Checkpoints.cpp index 0423c12b..5b5d12e2 100644 --- a/src/CryptoNoteCore/Checkpoints.cpp +++ b/src/CryptoNoteCore/Checkpoints.cpp @@ -92,6 +92,16 @@ bool Checkpoints::is_alternative_block_allowed(uint32_t blockchain_height, uint //--------------------------------------------------------------------------- +std::vector Checkpoints::getCheckpointHeights() const { + std::vector checkpointHeights; + checkpointHeights.reserve(m_points.size()); + for (const auto& it : m_points) { + checkpointHeights.push_back(it.first); + } + + return checkpointHeights; +} + bool Checkpoints::load_checkpoints_from_dns() { std::string domain("checkpoints.conceal.id"); diff --git a/src/CryptoNoteCore/Checkpoints.h b/src/CryptoNoteCore/Checkpoints.h index f9b3760c..c4056aed 100644 --- a/src/CryptoNoteCore/Checkpoints.h +++ b/src/CryptoNoteCore/Checkpoints.h @@ -22,7 +22,8 @@ namespace CryptoNote bool check_block(uint32_t height, const Crypto::Hash& h) const; bool check_block(uint32_t height, const Crypto::Hash& h, bool& is_a_checkpoint) const; bool is_alternative_block_allowed(uint32_t blockchain_height, uint32_t block_height) const; - + std::vector getCheckpointHeights() const; + private: std::map m_points; Logging::LoggerRef logger; diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index af8fe9fd..b5b62a6d 100644 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -101,10 +101,15 @@ void core::get_blockchain_top(uint32_t& height, Crypto::Hash& top_id) { top_id = m_blockchain.getTailId(height); } +bool core::rollback_chain_to(uint32_t height) { + return m_blockchain.rollbackBlockchainTo(height); +} + bool core::get_blocks(uint32_t start_offset, uint32_t count, std::list& blocks, std::list& txs) { return m_blockchain.getBlocks(start_offset, count, blocks, txs); } + bool core::get_blocks(uint32_t start_offset, uint32_t count, std::list& blocks) { return m_blockchain.getBlocks(start_offset, count, blocks); } diff --git a/src/CryptoNoteCore/Core.h b/src/CryptoNoteCore/Core.h index b80bbfe4..4ef27265 100644 --- a/src/CryptoNoteCore/Core.h +++ b/src/CryptoNoteCore/Core.h @@ -89,6 +89,7 @@ namespace CryptoNote { virtual void get_blockchain_top(uint32_t& height, Crypto::Hash& top_id) override; bool get_blocks(uint32_t start_offset, uint32_t count, std::list& blocks, std::list& txs); bool get_blocks(uint32_t start_offset, uint32_t count, std::list& blocks); + bool rollback_chain_to(uint32_t height); template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) { diff --git a/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp b/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp index 02c4ec5a..6779401f 100644 --- a/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp +++ b/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp @@ -18,6 +18,7 @@ #include "CryptoNoteSerialization.h" #include "TransactionExtra.h" #include "CryptoNoteTools.h" +#include "Currency.h" #include "CryptoNoteConfig.h" @@ -530,4 +531,12 @@ Hash get_tx_tree_hash(const Block& b) { return get_tx_tree_hash(txs_ids); } +bool is_valid_decomposed_amount(uint64_t amount) { + auto it = std::lower_bound(Currency::PRETTY_AMOUNTS.begin(), Currency::PRETTY_AMOUNTS.end(), amount); + if (it == Currency::PRETTY_AMOUNTS.end() || amount != *it) { + return false; + } + return true; +} + } diff --git a/src/CryptoNoteCore/CryptoNoteFormatUtils.h b/src/CryptoNoteCore/CryptoNoteFormatUtils.h index 08b43b5c..f4ea1644 100644 --- a/src/CryptoNoteCore/CryptoNoteFormatUtils.h +++ b/src/CryptoNoteCore/CryptoNoteFormatUtils.h @@ -124,5 +124,7 @@ void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, cons void get_tx_tree_hash(const std::vector& tx_hashes, Crypto::Hash& h); Crypto::Hash get_tx_tree_hash(const std::vector& tx_hashes); Crypto::Hash get_tx_tree_hash(const Block& b); +bool is_valid_decomposed_amount(uint64_t amount); + } diff --git a/src/CryptoNoteCore/Currency.h b/src/CryptoNoteCore/Currency.h index 33078ed0..6feff0bd 100644 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -21,6 +21,8 @@ class AccountBase; class Currency { public: + static const std::vector PRETTY_AMOUNTS; + uint64_t maxBlockHeight() const { return m_maxBlockHeight; } size_t maxBlockBlobSize() const { return m_maxBlockBlobSize; } size_t maxTxSize() const { return m_maxTxSize; } @@ -251,7 +253,6 @@ class Currency { std::string m_txPoolFileName; std::string m_blockchinIndicesFileName; - static const std::vector PRETTY_AMOUNTS; static const std::vector REWARD_INCREASING_FACTOR; bool m_testnet; diff --git a/src/Daemon/DaemonCommandsHandler.cpp b/src/Daemon/DaemonCommandsHandler.cpp index 2457cb4a..0dbe4b9f 100644 --- a/src/Daemon/DaemonCommandsHandler.cpp +++ b/src/Daemon/DaemonCommandsHandler.cpp @@ -27,6 +27,7 @@ DaemonCommandsHandler::DaemonCommandsHandler(CryptoNote::core& core, CryptoNote: m_consoleHandler.setHandler("exit", boost::bind(&DaemonCommandsHandler::exit, this, _1), "Shutdown the daemon"); m_consoleHandler.setHandler("help", boost::bind(&DaemonCommandsHandler::help, this, _1), "Show this help"); m_consoleHandler.setHandler("print_pl", boost::bind(&DaemonCommandsHandler::print_pl, this, _1), "Print peer list"); + m_consoleHandler.setHandler("rollback_chain", boost::bind(&DaemonCommandsHandler::rollback_chain, this, _1), "Rollback chain to specific height, rollback_chain "); m_consoleHandler.setHandler("print_cn", boost::bind(&DaemonCommandsHandler::print_cn, this, _1), "Print connections"); m_consoleHandler.setHandler("print_bc", boost::bind(&DaemonCommandsHandler::print_bc, this, _1), "Print blockchain info in a given blocks range, print_bc []"); m_consoleHandler.setHandler("print_block", boost::bind(&DaemonCommandsHandler::print_block, this, _1), "Print block, print_block | "); @@ -193,6 +194,26 @@ bool DaemonCommandsHandler::print_block_by_height(uint32_t height) return true; } + +//-------------------------------------------------------------------------------- +bool DaemonCommandsHandler::rollback_chain(const std::vector &args) { + if (args.empty()) { + std::cout << "expected: rollback_chain " << std::endl; + return true; + } + + const std::string &arg = args.front(); + uint32_t height = boost::lexical_cast(arg); + rollbackchainto(height); + return true; +} + +//-------------------------------------------------------------------------------- +bool DaemonCommandsHandler::rollbackchainto(uint32_t height) +{ + m_core.rollback_chain_to(height); + return true; +} //-------------------------------------------------------------------------------- bool DaemonCommandsHandler::print_block_by_hash(const std::string& arg) { diff --git a/src/Daemon/DaemonCommandsHandler.h b/src/Daemon/DaemonCommandsHandler.h index 13a0fe70..1ed5a996 100644 --- a/src/Daemon/DaemonCommandsHandler.h +++ b/src/Daemon/DaemonCommandsHandler.h @@ -48,6 +48,8 @@ class DaemonCommandsHandler bool print_pl(const std::vector& args); bool show_hr(const std::vector& args); bool hide_hr(const std::vector& args); + bool rollbackchainto(uint32_t height); + bool rollback_chain(const std::vector& args); bool print_bc_outs(const std::vector& args); bool print_cn(const std::vector& args); bool print_bc(const std::vector& args); @@ -58,6 +60,7 @@ class DaemonCommandsHandler bool print_pool(const std::vector& args); bool print_pool_sh(const std::vector& args); bool print_stat(const std::vector& args); + bool start_mining(const std::vector& args); bool stop_mining(const std::vector& args); }; diff --git a/src/SimpleWallet/SimpleWallet.cpp b/src/SimpleWallet/SimpleWallet.cpp index f49dcad5..c2ddf340 100644 --- a/src/SimpleWallet/SimpleWallet.cpp +++ b/src/SimpleWallet/SimpleWallet.cpp @@ -647,8 +647,6 @@ simple_wallet::simple_wallet(System::Dispatcher& dispatcher, const CryptoNote::C m_refresh_progress_reporter(*this), m_initResultPromise(nullptr), m_walletSynchronized(false) { -// m_consoleHandler.setHandler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining [] - Start mining in daemon"); -// m_consoleHandler.setHandler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon"); m_consoleHandler.setHandler("create_integrated", boost::bind(&simple_wallet::create_integrated, this, _1), "create_integrated - Create an integrated address with a payment ID"); m_consoleHandler.setHandler("export_keys", boost::bind(&simple_wallet::export_keys, this, _1), "Show the secret keys of the current wallet"); m_consoleHandler.setHandler("balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance"); @@ -656,6 +654,7 @@ simple_wallet::simple_wallet(System::Dispatcher& dispatcher, const CryptoNote::C m_consoleHandler.setHandler("list_transfers", boost::bind(&simple_wallet::listTransfers, this, _1), "list_transfers - Show all known transfers from a certain (optional) block height"); m_consoleHandler.setHandler("payments", boost::bind(&simple_wallet::show_payments, this, _1), "payments [ ... ] - Show payments , ... "); m_consoleHandler.setHandler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height"); + m_consoleHandler.setHandler("show_dust", boost::bind(&simple_wallet::show_dust, this, _1), "Show the number of unmixable dust outputs"); m_consoleHandler.setHandler("outputs", boost::bind(&simple_wallet::show_num_unlocked_outputs, this, _1), "Show the number of unlocked outputs available for a transaction"); m_consoleHandler.setHandler("optimize", boost::bind(&simple_wallet::optimize_outputs, this, _1), "Combine many available outputs into a few by sending a transaction to self"); m_consoleHandler.setHandler("optimize_all", boost::bind(&simple_wallet::optimize_all_outputs, this, _1), "Optimize your wallet several times so you can send large transactions"); @@ -670,6 +669,14 @@ simple_wallet::simple_wallet(System::Dispatcher& dispatcher, const CryptoNote::C m_consoleHandler.setHandler("help", boost::bind(&simple_wallet::help, this, _1), "Show this help"); m_consoleHandler.setHandler("exit", boost::bind(&simple_wallet::exit, this, _1), "Close wallet"); } + +/* This function shows the number of outputs in the wallet + that are below the dust threshold */ +bool simple_wallet::show_dust(const std::vector& args) { + logger(INFO, BRIGHT_WHITE) << "Dust outputs: " << m_wallet->dustBalance() << std::endl; + return true; +} + //---------------------------------------------------------------------------------------------------- bool simple_wallet::set_log(const std::vector &args) { if (args.size() != 1) { @@ -1491,7 +1498,7 @@ bool simple_wallet::optimize_outputs(const std::vector& args) { std::vector transfers; std::vector messages; std::string extraString; - uint64_t fee = CryptoNote::parameters::MINIMUM_FEE_V1; + uint64_t fee = CryptoNote::parameters::MINIMUM_FEE; uint64_t mixIn = 0; uint64_t unlockTimestamp = 0; uint64_t ttl = 0; @@ -1559,7 +1566,7 @@ bool simple_wallet::optimize_all_outputs(const std::vector& args) { std::vector transfers; std::vector messages; std::string extraString; - uint64_t fee = CryptoNote::parameters::MINIMUM_FEE_V1; + uint64_t fee = CryptoNote::parameters::MINIMUM_FEE; uint64_t mixIn = 0; uint64_t unlockTimestamp = 0; uint64_t ttl = 0; diff --git a/src/SimpleWallet/SimpleWallet.h b/src/SimpleWallet/SimpleWallet.h index b1902653..88b6665c 100644 --- a/src/SimpleWallet/SimpleWallet.h +++ b/src/SimpleWallet/SimpleWallet.h @@ -70,6 +70,7 @@ namespace CryptoNote bool help(const std::vector &args = std::vector()); bool exit(const std::vector &args); bool start_mining(const std::vector &args); + bool show_dust(const std::vector &args); bool stop_mining(const std::vector &args); bool show_balance(const std::vector &args = std::vector()); bool export_keys(const std::vector &args = std::vector()); diff --git a/src/WalletLegacy/WalletLegacy.cpp b/src/WalletLegacy/WalletLegacy.cpp index 67404b41..1ab892e9 100644 --- a/src/WalletLegacy/WalletLegacy.cpp +++ b/src/WalletLegacy/WalletLegacy.cpp @@ -622,6 +622,26 @@ TransactionId WalletLegacy::withdrawDeposits(const std::vector& depos return txId; } +/* go through all unlocked outputs and return a total of + everything below the dust threshold */ +uint64_t WalletLegacy::dustBalance() { + std::unique_lock lock(m_cacheMutex); + throwIfNotInitialised(); + std::vector outputs; + m_transferDetails->getOutputs(outputs, ITransfersContainer::IncludeKeyUnlocked); + uint64_t money = 0; + for (size_t i = 0; i < outputs.size(); ++i) { + const auto& out = outputs[i]; + if (!m_transactionsCache.isUsed(out)) { + if (out.amount < m_currency.defaultDustThreshold()) { + money += out.amount; + } + } + } + return money; +} + + void WalletLegacy::sendTransactionCallback(WalletRequest::Callback callback, std::error_code ec) { ContextCounterHolder counterHolder(m_asyncContextCounter); std::deque > events; diff --git a/src/WalletLegacy/WalletLegacy.h b/src/WalletLegacy/WalletLegacy.h index 3a42f143..939ace7d 100644 --- a/src/WalletLegacy/WalletLegacy.h +++ b/src/WalletLegacy/WalletLegacy.h @@ -135,6 +135,7 @@ class WalletLegacy : uint64_t calculateActualInvestmentBalance(); uint64_t calculatePendingDepositBalance(); uint64_t calculatePendingInvestmentBalance(); + uint64_t dustBalance(); uint64_t calculateActualBalance(); uint64_t calculatePendingBalance(); diff --git a/src/version.h.in b/src/version.h.in index e2e375f7..e9e82324 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define BUILD_COMMIT_ID "@VERSION@" -#define PROJECT_VERSION "5.1.7" -#define PROJECT_VERSION_BUILD_NO "Steganos 15" +#define PROJECT_VERSION "5.1.9" +#define PROJECT_VERSION_BUILD_NO "Steganos 16" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"