From fba49fa056417f834785122932111b820d6a47ec Mon Sep 17 00:00:00 2001 From: xdn-project Date: Mon, 30 May 2016 15:40:39 +0000 Subject: [PATCH 01/26] Messages 2.0 --- ReleaseNotes.txt | 6 ++ include/IWalletLegacy.h | 4 +- src/Common/JsonValue.cpp | 5 +- src/CryptoNoteCore/CryptoNoteFormatUtils.cpp | 5 ++ src/CryptoNoteCore/CryptoNoteFormatUtils.h | 4 +- src/CryptoNoteCore/TransactionExtra.cpp | 25 +++++++ src/CryptoNoteCore/TransactionExtra.h | 8 ++- src/CryptoNoteCore/TransactionPool.cpp | 70 +++++++++++++++++-- src/CryptoNoteCore/TransactionPool.h | 1 + src/Wallet/WalletRpcServer.cpp | 46 +++++++++++- src/Wallet/WalletRpcServer.h | 5 ++ .../WalletRpcServerCommandsDefinitions.h | 42 +++++++++++ src/WalletLegacy/WalletLegacy.cpp | 10 +-- src/WalletLegacy/WalletLegacy.h | 6 +- .../WalletSendTransactionContext.h | 1 + src/WalletLegacy/WalletTransactionSender.cpp | 10 +-- src/WalletLegacy/WalletTransactionSender.h | 3 +- 17 files changed, 224 insertions(+), 27 deletions(-) diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 6d69f68..ba61a57 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -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 diff --git a/include/IWalletLegacy.h b/include/IWalletLegacy.h index 8360020..1bf2869 100644 --- a/include/IWalletLegacy.h +++ b/include/IWalletLegacy.h @@ -133,8 +133,8 @@ class IWalletLegacy { virtual bool getDeposit(DepositId depositId, Deposit& deposit) = 0; virtual std::vector getTransactionsByPaymentIds(const std::vector& 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& messages = std::vector()) = 0; - virtual TransactionId sendTransaction(const std::vector& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, const std::vector& messages = std::vector()) = 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& messages = std::vector(), uint64_t ttl = 0) = 0; + virtual TransactionId sendTransaction(const std::vector& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, const std::vector& messages = std::vector(), 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& depositIds, uint64_t fee) = 0; virtual std::error_code cancelTransaction(size_t transferId) = 0; diff --git a/src/Common/JsonValue.cpp b/src/Common/JsonValue.cpp index eecd478..0445c07 100644 --- a/src/Common/JsonValue.cpp +++ b/src/Common/JsonValue.cpp @@ -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(in.get()); + if (!in) { throw std::runtime_error("Unable to parse: unexpected end of stream"); } diff --git a/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp b/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp index 758da84..ccdb99f 100644 --- a/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp +++ b/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp @@ -75,6 +75,7 @@ bool constructTransaction( const std::vector& sources, const std::vector& destinations, const std::vector& messages, + uint64_t ttl, std::vector extra, Transaction& tx, uint64_t unlock_time, @@ -197,6 +198,10 @@ bool constructTransaction( } } + if (ttl != 0) { + appendTTLToExtra(tx.extra, ttl); + } + //generate ring signatures Hash tx_prefix_hash; getObjectHash(*static_cast(&tx), tx_prefix_hash); diff --git a/src/CryptoNoteCore/CryptoNoteFormatUtils.h b/src/CryptoNoteCore/CryptoNoteFormatUtils.h index 999cff5..81a365a 100644 --- a/src/CryptoNoteCore/CryptoNoteFormatUtils.h +++ b/src/CryptoNoteCore/CryptoNoteFormatUtils.h @@ -51,7 +51,7 @@ bool constructTransaction( const std::vector& sources, const std::vector& destinations, const std::vector& messages, - std::vector extra, Transaction& transaction, uint64_t unlock_time, Logging::ILogger& log); + uint64_t ttl, std::vector extra, Transaction& transaction, uint64_t unlock_time, Logging::ILogger& log); inline bool constructTransaction( const AccountKeys& sender_account_keys, @@ -59,7 +59,7 @@ inline bool constructTransaction( const std::vector& destinations, std::vector extra, Transaction& tx, uint64_t unlock_time, Logging::ILogger& log) { - return constructTransaction(sender_account_keys, sources, destinations, std::vector(), extra, tx, unlock_time, log); + return constructTransaction(sender_account_keys, sources, destinations, std::vector(), 0, extra, tx, unlock_time, log); } bool is_out_to_acc(const AccountKeys& acc, const KeyOutput& out_key, const Crypto::PublicKey& tx_pub_key, size_t keyIndex); diff --git a/src/CryptoNoteCore/TransactionExtra.cpp b/src/CryptoNoteCore/TransactionExtra.cpp index 7bd67ef..d986a0f 100644 --- a/src/CryptoNoteCore/TransactionExtra.cpp +++ b/src/CryptoNoteCore/TransactionExtra.cpp @@ -9,6 +9,7 @@ #include "Common/MemoryInputStream.h" #include "Common/StreamTools.h" #include "Common/StringTools.h" +#include "Common/Varint.h" #include "CryptoNoteTools.h" #include "Serialization/BinaryOutputStreamSerializer.h" #include "Serialization/BinaryInputStreamSerializer.h" @@ -81,6 +82,15 @@ bool parseTransactionExtra(const std::vector &transactionExtra, std::ve transactionExtraFields.push_back(message); break; } + + case TX_EXTRA_TTL: { + uint8_t size; + readVarint(iss, size); + TransactionExtraTTL ttl; + readVarint(iss, ttl.ttl); + transactionExtraFields.push_back(ttl); + break; + } } } } catch (std::exception &) { @@ -119,6 +129,11 @@ struct ExtraSerializerVisitor : public boost::static_visitor { bool operator()(const tx_extra_message& t) { return append_message_to_extra(extra, t); } + + bool operator()(const TransactionExtraTTL& t) { + appendTTLToExtra(extra, t.ttl); + return true; + } }; bool writeTransactionExtra(std::vector& tx_extra, const std::vector& tx_extra_fields) { @@ -221,6 +236,16 @@ std::vector get_messages_from_extra(const std::vector &ext return result; } +void appendTTLToExtra(std::vector& tx_extra, uint64_t ttl) { + std::string ttlData = Tools::get_varint_data(ttl); + std::string extraFieldSize = Tools::get_varint_data(ttlData.size()); + + tx_extra.reserve(tx_extra.size() + 1 + extraFieldSize.size() + ttlData.size()); + tx_extra.push_back(TX_EXTRA_TTL); + std::copy(extraFieldSize.begin(), extraFieldSize.end(), std::back_inserter(tx_extra)); + std::copy(ttlData.begin(), ttlData.end(), std::back_inserter(tx_extra)); +} + void setPaymentIdToTransactionExtraNonce(std::vector& extra_nonce, const Hash& payment_id) { extra_nonce.clear(); extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID); diff --git a/src/CryptoNoteCore/TransactionExtra.h b/src/CryptoNoteCore/TransactionExtra.h index fa5f2f2..aa6bc61 100644 --- a/src/CryptoNoteCore/TransactionExtra.h +++ b/src/CryptoNoteCore/TransactionExtra.h @@ -19,6 +19,7 @@ #define TX_EXTRA_NONCE 0x02 #define TX_EXTRA_MERGE_MINING_TAG 0x03 #define TX_EXTRA_MESSAGE_TAG 0x04 +#define TX_EXTRA_TTL 0x05 #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 @@ -52,11 +53,15 @@ struct tx_extra_message { bool serialize(ISerializer& serializer); }; +struct TransactionExtraTTL { + uint64_t ttl; +}; + // tx_extra_field format, except tx_extra_padding and tx_extra_pub_key: // varint tag; // varint size; // varint data[]; -typedef boost::variant TransactionExtraField; +typedef boost::variant TransactionExtraField; @@ -83,6 +88,7 @@ bool getPaymentIdFromTransactionExtraNonce(const BinaryArray& extra_nonce, Crypt bool appendMergeMiningTagToExtra(std::vector& tx_extra, const TransactionExtraMergeMiningTag& mm_tag); bool append_message_to_extra(std::vector& tx_extra, const tx_extra_message& message); std::vector get_messages_from_extra(const std::vector& extra, const Crypto::PublicKey &txkey, const Crypto::SecretKey *recepient_secret_key); +void appendTTLToExtra(std::vector& tx_extra, uint64_t ttl); bool createTxExtraWithPaymentId(const std::string& paymentIdString, std::vector& extra); //returns false if payment id is not found or parse error diff --git a/src/CryptoNoteCore/TransactionPool.cpp b/src/CryptoNoteCore/TransactionPool.cpp index 594499e..36072c4 100644 --- a/src/CryptoNoteCore/TransactionPool.cpp +++ b/src/CryptoNoteCore/TransactionPool.cpp @@ -22,6 +22,7 @@ #include "CryptoNoteFormatUtils.h" #include "CryptoNoteTools.h" #include "CryptoNoteConfig.h" +#include "TransactionExtra.h" using namespace Logging; @@ -115,9 +116,29 @@ namespace CryptoNote { return false; } + std::vector txExtraFields; + parseTransactionExtra(tx.extra, txExtraFields); + TransactionExtraTTL ttl; + if (!findTransactionExtraFieldByType(txExtraFields, ttl)) { + ttl.ttl = 0; + } + + uint64_t now = static_cast(time(nullptr)); + if (ttl.ttl != 0) { + if (ttl.ttl <= now) { + logger(INFO, BRIGHT_WHITE) << "Transaction TTL has already expired: tx = " << id << ", ttl = " << ttl.ttl; + tvc.m_verifivation_failed = true; + return false; + } else if (ttl.ttl - now > m_currency.mempoolTxLiveTime() + m_currency.blockFutureTimeLimit()) { + logger(INFO, BRIGHT_WHITE) << "Transaction TTL is out of range: tx = " << id << ", ttl = " << ttl.ttl; + tvc.m_verifivation_failed = true; + return false; + } + } + const uint64_t fee = inputs_amount - outputs_amount; bool isFusionTransaction = fee == 0 && m_currency.isFusionTransaction(tx, blobSize); - if (!keptByBlock && !isFusionTransaction && fee < m_currency.minimumFee()) { + if (!keptByBlock && !isFusionTransaction && ttl.ttl == 0 && fee < m_currency.minimumFee()) { logger(INFO) << "transaction fee is not enough: " << m_currency.formatAmount(fee) << ", minimum fee: " << m_currency.formatAmount(m_currency.minimumFee()); tvc.m_verifivation_failed = true; @@ -192,10 +213,13 @@ namespace CryptoNote { m_paymentIdIndex.add(txd.tx); m_timestampIndex.add(txd.receiveTime, txd.id); + if (ttl.ttl != 0) { + m_ttlIndex.emplace(std::make_pair(id, ttl.ttl)); + } } tvc.m_added_to_pool = true; - tvc.m_should_be_relayed = inputsValid && (fee > 0 || isFusionTransaction); + tvc.m_should_be_relayed = inputsValid && (fee > 0 || isFusionTransaction || ttl.ttl != 0); tvc.m_verifivation_failed = true; if (!addTransactionInputs(id, tx, keptByBlock)) @@ -328,7 +352,15 @@ namespace CryptoNote { << "max_used_block_id: " << txd.maxUsedBlock.id << std::endl << "last_failed_height: " << txd.lastFailedBlock.height << std::endl << "last_failed_id: " << txd.lastFailedBlock.id << std::endl - << "received: " << std::ctime(&txd.receiveTime) << std::endl; + << "received: " << std::ctime(&txd.receiveTime); + + auto ttlIt = m_ttlIndex.find(txd.id); + if (ttlIt != m_ttlIndex.end()) { + // ctime() returns string that ends with new line + ss << "TTL: " << std::ctime(reinterpret_cast(&ttlIt->second)); + } + + ss << std::endl; } return ss.str(); @@ -349,6 +381,10 @@ namespace CryptoNote { for (auto it = m_fee_index.rbegin(); it != m_fee_index.rend() && it->fee == 0; ++it) { const auto& txd = *it; + if (m_ttlIndex.count(txd.id) > 0) { + continue; + } + if (m_currency.fusionTxMaxSize() < total_size + txd.blobSize) { continue; } @@ -362,6 +398,10 @@ namespace CryptoNote { for (auto i = m_fee_index.begin(); i != m_fee_index.end(); ++i) { const auto& txd = *i; + if (m_ttlIndex.count(txd.id) > 0) { + continue; + } + size_t blockSizeLimit = (txd.fee == 0) ? median_size : max_total_size; if (blockSizeLimit < total_size + txd.blobSize) { continue; @@ -404,6 +444,7 @@ namespace CryptoNote { m_paymentIdIndex.clear(); m_timestampIndex.clear(); + m_ttlIndex.clear(); } else { buildIndices(); } @@ -428,6 +469,7 @@ namespace CryptoNote { m_paymentIdIndex.clear(); m_timestampIndex.clear(); + m_ttlIndex.clear(); return true; } @@ -498,8 +540,16 @@ namespace CryptoNote { uint64_t txAge = now - it->receiveTime; bool remove = txAge > (it->keptByBlock ? m_currency.mempoolTxFromAltBlockLiveTime() : m_currency.mempoolTxLiveTime()); - if (remove) { - logger(TRACE) << "Tx " << it->id << " removed from tx pool due to outdated, age: " << txAge; + auto ttlIt = m_ttlIndex.find(it->id); + bool ttlExpired = (ttlIt != m_ttlIndex.end() && ttlIt->second <= now); + + if (remove || ttlExpired) { + if (ttlExpired) { + logger(TRACE) << "Tx " << it->id << " removed from tx pool due to expired TTL, TTL : " << ttlIt->second; + } else { + logger(TRACE) << "Tx " << it->id << " removed from tx pool due to outdated, age: " << txAge; + } + m_recentlyDeletedTransactions.emplace(it->id, now); it = removeTransaction(it); somethingRemoved = true; @@ -520,6 +570,7 @@ namespace CryptoNote { removeTransactionInputs(i->id, i->tx, i->keptByBlock); m_paymentIdIndex.remove(i->tx); m_timestampIndex.remove(i->receiveTime, i->id); + m_ttlIndex.erase(i->id); return m_transactions.erase(i); } @@ -618,6 +669,15 @@ namespace CryptoNote { for (auto it = m_transactions.begin(); it != m_transactions.end(); it++) { m_paymentIdIndex.add(it->tx); m_timestampIndex.add(it->receiveTime, it->id); + + std::vector txExtraFields; + parseTransactionExtra(it->tx.extra, txExtraFields); + TransactionExtraTTL ttl; + if (findTransactionExtraFieldByType(txExtraFields, ttl)) { + if (ttl.ttl != 0) { + m_ttlIndex.emplace(std::make_pair(it->id, ttl.ttl)); + } + } } } diff --git a/src/CryptoNoteCore/TransactionPool.h b/src/CryptoNoteCore/TransactionPool.h index bfb7f99..35a097b 100644 --- a/src/CryptoNoteCore/TransactionPool.h +++ b/src/CryptoNoteCore/TransactionPool.h @@ -203,6 +203,7 @@ namespace CryptoNote { PaymentIdIndex m_paymentIdIndex; TimestampTransactionsIndex m_timestampIndex; + std::unordered_map m_ttlIndex; }; } diff --git a/src/Wallet/WalletRpcServer.cpp b/src/Wallet/WalletRpcServer.cpp index b32adfc..80b0afc 100644 --- a/src/Wallet/WalletRpcServer.cpp +++ b/src/Wallet/WalletRpcServer.cpp @@ -24,10 +24,14 @@ namespace Tools { const command_line::arg_descriptor wallet_rpc_server::arg_rpc_bind_port = { "rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server", 0, true }; const command_line::arg_descriptor wallet_rpc_server::arg_rpc_bind_ip = { "rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1" }; +const command_line::arg_descriptor wallet_rpc_server::arg_rpc_user = { "rpc-user", "Username to use the rpc server. If authorization is not required, leave it empty", "" }; +const command_line::arg_descriptor wallet_rpc_server::arg_rpc_password = { "rpc-password", "Password to use the rpc server. If authorization is not required, leave it empty", "" }; void wallet_rpc_server::init_options(boost::program_options::options_description& desc) { command_line::add_arg(desc, arg_rpc_bind_ip); command_line::add_arg(desc, arg_rpc_bind_port); + command_line::add_arg(desc, arg_rpc_user); + command_line::add_arg(desc, arg_rpc_password); } //------------------------------------------------------------------------------------------------------------------------------ wallet_rpc_server::wallet_rpc_server( @@ -49,7 +53,7 @@ wallet_rpc_server::wallet_rpc_server( } //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::run() { - start(m_bind_ip, m_port); + start(m_bind_ip, m_port, m_rpcUser, m_rpcPassword); m_stopComplete.wait(); return true; } @@ -66,6 +70,8 @@ void wallet_rpc_server::send_stop_signal() { bool wallet_rpc_server::handle_command_line(const boost::program_options::variables_map& vm) { m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip); m_port = command_line::get_arg(vm, arg_rpc_bind_port); + m_rpcUser = command_line::get_arg(vm, arg_rpc_user); + m_rpcPassword = command_line::get_arg(vm, arg_rpc_password); return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -93,6 +99,7 @@ void wallet_rpc_server::processRequest(const CryptoNote::HttpRequest& request, C { "getbalance", makeMemberMethod(&wallet_rpc_server::on_getbalance) }, { "transfer", makeMemberMethod(&wallet_rpc_server::on_transfer) }, { "store", makeMemberMethod(&wallet_rpc_server::on_store) }, + { "get_messages", makeMemberMethod(&wallet_rpc_server::on_get_messages) }, { "get_payments", makeMemberMethod(&wallet_rpc_server::on_get_payments) }, { "get_transfers", makeMemberMethod(&wallet_rpc_server::on_get_transfers) }, { "get_height", makeMemberMethod(&wallet_rpc_server::on_get_height) }, @@ -126,11 +133,16 @@ bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE: //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res) { std::vector transfers; + std::vector messages; for (auto it = req.destinations.begin(); it != req.destinations.end(); it++) { CryptoNote::WalletLegacyTransfer transfer; transfer.address = it->address; transfer.amount = it->amount; transfers.push_back(transfer); + + if (!it->message.empty()) { + messages.emplace_back(CryptoNote::TransactionMessage{ it->message, it->address }); + } } std::vector extra; @@ -151,18 +163,22 @@ bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::requ } } - std::vector messages; for (auto& rpc_message : req.messages) { messages.emplace_back(CryptoNote::TransactionMessage{ rpc_message.message, rpc_message.address }); } + uint64_t ttl = 0; + if (req.ttl != 0) { + ttl = static_cast(time(nullptr)) + req.ttl; + } + std::string extraString; std::copy(extra.begin(), extra.end(), std::back_inserter(extraString)); try { CryptoNote::WalletHelper::SendCompleteResultObserver sent; WalletHelper::IWalletRemoveObserverGuard removeGuard(m_wallet, sent); - CryptoNote::TransactionId tx = m_wallet.sendTransaction(transfers, req.fee, extraString, req.mixin, req.unlock_time, messages); + CryptoNote::TransactionId tx = m_wallet.sendTransaction(transfers, req.fee, extraString, req.mixin, req.unlock_time, messages, ttl); if (tx == WALLET_LEGACY_INVALID_TRANSACTION_ID) { throw std::runtime_error("Couldn't send transaction"); } @@ -194,6 +210,30 @@ bool wallet_rpc_server::on_store(const wallet_rpc::COMMAND_RPC_STORE::request& r return true; } //------------------------------------------------------------------------------------------------------------------------------ +bool wallet_rpc_server::on_get_messages(const wallet_rpc::COMMAND_RPC_GET_MESSAGES::request& req, wallet_rpc::COMMAND_RPC_GET_MESSAGES::response& res) { + res.total_tx_count = m_wallet.getTransactionCount(); + + for (uint64_t i = req.first_tx_id; i < res.total_tx_count && res.tx_messages.size() < req.tx_limit; ++i) { + WalletLegacyTransaction tx; + if (!m_wallet.getTransaction(static_cast(i), tx)) { + throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR, "Failed to get transaction"); + } + + if (!tx.messages.empty()) { + wallet_rpc::transaction_messages tx_messages; + tx_messages.tx_hash = Common::podToHex(tx.hash); + tx_messages.tx_id = i; + tx_messages.block_height = tx.blockHeight; + tx_messages.timestamp = tx.timestamp; + std::copy(tx.messages.begin(), tx.messages.end(), std::back_inserter(tx_messages.messages)); + + res.tx_messages.emplace_back(std::move(tx_messages)); + } + } + + return true; +} +//------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res) { PaymentId expectedPaymentId; CryptoNote::BinaryArray payment_id_blob; diff --git a/src/Wallet/WalletRpcServer.h b/src/Wallet/WalletRpcServer.h index ef35a07..a9aed7d 100644 --- a/src/Wallet/WalletRpcServer.h +++ b/src/Wallet/WalletRpcServer.h @@ -41,6 +41,8 @@ namespace Tools static const command_line::arg_descriptor arg_rpc_bind_port; static const command_line::arg_descriptor arg_rpc_bind_ip; + static const command_line::arg_descriptor arg_rpc_user; + static const command_line::arg_descriptor arg_rpc_password; private: @@ -50,6 +52,7 @@ namespace Tools bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res); bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res); bool on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res); + bool on_get_messages(const wallet_rpc::COMMAND_RPC_GET_MESSAGES::request& req, wallet_rpc::COMMAND_RPC_GET_MESSAGES::response& res); bool on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res); bool on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res); bool on_get_height(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res); @@ -62,6 +65,8 @@ namespace Tools CryptoNote::INode& m_node; uint16_t m_port; std::string m_bind_ip; + std::string m_rpcUser; + std::string m_rpcPassword; CryptoNote::Currency& m_currency; const std::string m_walletFilename; diff --git a/src/Wallet/WalletRpcServerCommandsDefinitions.h b/src/Wallet/WalletRpcServerCommandsDefinitions.h index e0df18e..9b907fd 100644 --- a/src/Wallet/WalletRpcServerCommandsDefinitions.h +++ b/src/Wallet/WalletRpcServerCommandsDefinitions.h @@ -44,10 +44,12 @@ using CryptoNote::ISerializer; { uint64_t amount; std::string address; + std::string message; void serialize(ISerializer& s) { KV_MEMBER(amount) KV_MEMBER(address) + KV_MEMBER(message) } }; @@ -71,6 +73,7 @@ using CryptoNote::ISerializer; uint64_t unlock_time; std::string payment_id; std::list messages; + uint64_t ttl = 0; void serialize(ISerializer& s) { KV_MEMBER(destinations) @@ -79,6 +82,7 @@ using CryptoNote::ISerializer; KV_MEMBER(unlock_time) KV_MEMBER(payment_id) KV_MEMBER(messages) + KV_MEMBER(ttl) } }; @@ -98,6 +102,44 @@ using CryptoNote::ISerializer; typedef CryptoNote::EMPTY_STRUCT response; }; + struct transaction_messages { + std::string tx_hash; + uint64_t tx_id; + uint32_t block_height; + uint64_t timestamp; + std::list messages; + + void serialize(ISerializer& s) { + KV_MEMBER(tx_hash); + KV_MEMBER(tx_id); + KV_MEMBER(block_height); + KV_MEMBER(timestamp); + KV_MEMBER(messages); + } + }; + + struct COMMAND_RPC_GET_MESSAGES { + struct request { + uint64_t first_tx_id = 0; + uint32_t tx_limit = std::numeric_limits::max(); + + void serialize(ISerializer& s) { + KV_MEMBER(first_tx_id); + KV_MEMBER(tx_limit); + } + }; + + struct response { + uint64_t total_tx_count; + std::list tx_messages; + + void serialize(ISerializer& s) { + KV_MEMBER(total_tx_count); + KV_MEMBER(tx_messages); + } + }; + }; + struct payment_details { std::string tx_hash; diff --git a/src/WalletLegacy/WalletLegacy.cpp b/src/WalletLegacy/WalletLegacy.cpp index b6f9984..9c6132e 100644 --- a/src/WalletLegacy/WalletLegacy.cpp +++ b/src/WalletLegacy/WalletLegacy.cpp @@ -464,12 +464,13 @@ TransactionId WalletLegacy::sendTransaction(const WalletLegacyTransfer& transfer const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp, - const std::vector& messages) { + const std::vector& messages, + uint64_t ttl) { std::vector transfers; transfers.push_back(transfer); throwIfNotInitialised(); - return sendTransaction(transfers, fee, extra, mixIn, unlockTimestamp, messages); + return sendTransaction(transfers, fee, extra, mixIn, unlockTimestamp, messages, ttl); } TransactionId WalletLegacy::sendTransaction(const std::vector& transfers, @@ -477,7 +478,8 @@ TransactionId WalletLegacy::sendTransaction(const std::vector& messages) { + const std::vector& messages, + uint64_t ttl) { TransactionId txId = 0; std::unique_ptr request; std::deque> events; @@ -485,7 +487,7 @@ TransactionId WalletLegacy::sendTransaction(const std::vector lock(m_cacheMutex); - request = m_sender->makeSendRequest(txId, events, transfers, fee, extra, mixIn, unlockTimestamp, messages); + request = m_sender->makeSendRequest(txId, events, transfers, fee, extra, mixIn, unlockTimestamp, messages, ttl); } notifyClients(events); diff --git a/src/WalletLegacy/WalletLegacy.h b/src/WalletLegacy/WalletLegacy.h index 4723139..77c523d 100644 --- a/src/WalletLegacy/WalletLegacy.h +++ b/src/WalletLegacy/WalletLegacy.h @@ -77,13 +77,15 @@ class WalletLegacy : const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, - const std::vector& messages = std::vector()) override; + const std::vector& messages = std::vector(), + uint64_t ttl = 0) override; virtual TransactionId sendTransaction(const std::vector& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, - const std::vector& messages = std::vector()) override; + const std::vector& messages = std::vector(), + uint64_t ttl = 0) override; virtual TransactionId deposit(uint32_t term, uint64_t amount, uint64_t fee, uint64_t mixIn = 0) override; virtual TransactionId withdrawDeposits(const std::vector& depositIds, uint64_t fee) override; virtual std::error_code cancelTransaction(size_t transactionId) override; diff --git a/src/WalletLegacy/WalletSendTransactionContext.h b/src/WalletLegacy/WalletSendTransactionContext.h index 1c0ea81..2d9131c 100644 --- a/src/WalletLegacy/WalletSendTransactionContext.h +++ b/src/WalletLegacy/WalletSendTransactionContext.h @@ -33,6 +33,7 @@ struct SendTransactionContext TxDustPolicy dustPolicy; uint64_t mixIn; std::vector messages; + uint64_t ttl; uint32_t depositTerm; }; diff --git a/src/WalletLegacy/WalletTransactionSender.cpp b/src/WalletLegacy/WalletTransactionSender.cpp index 9e1815e..e1fab61 100644 --- a/src/WalletLegacy/WalletTransactionSender.cpp +++ b/src/WalletLegacy/WalletTransactionSender.cpp @@ -51,13 +51,13 @@ void createChangeDestinations(const AccountPublicAddress& address, uint64_t need } void constructTx(const AccountKeys keys, const std::vector& sources, const std::vector& splittedDests, - const std::string& extra, uint64_t unlockTimestamp, uint64_t sizeLimit, Transaction& tx, const std::vector& messages) { + const std::string& extra, uint64_t unlockTimestamp, uint64_t sizeLimit, Transaction& tx, const std::vector& messages, uint64_t ttl) { std::vector extraVec; extraVec.reserve(extra.size()); std::for_each(extra.begin(), extra.end(), [&extraVec] (const char el) { extraVec.push_back(el);}); Logging::LoggerGroup nullLog; - bool r = constructTransaction(keys, sources, splittedDests, messages, extraVec, tx, unlockTimestamp, nullLog); + bool r = constructTransaction(keys, sources, splittedDests, messages, ttl, extraVec, tx, unlockTimestamp, nullLog); throwIf(!r, error::INTERNAL_WALLET_ERROR); throwIf(getObjectBinarySize(tx) >= sizeLimit, error::TRANSACTION_SIZE_TOO_BIG); @@ -181,7 +181,8 @@ std::unique_ptr WalletTransactionSender::makeSendRequest(Transact const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp, - const std::vector& messages) { + const std::vector& messages, + uint64_t ttl) { throwIf(transfers.empty(), error::ZERO_DESTINATION); validateTransfersAddresses(transfers); uint64_t neededMoney = countNeededMoney(fee, transfers); @@ -194,6 +195,7 @@ std::unique_ptr WalletTransactionSender::makeSendRequest(Transact transactionId = m_transactionsCache.addNewTransaction(neededMoney, fee, extra, transfers, unlockTimestamp, messages); context->transactionId = transactionId; context->mixIn = mixIn; + context->ttl = ttl; for (const TransactionMessage& message : messages) { AccountPublicAddress address; @@ -331,7 +333,7 @@ std::unique_ptr WalletTransactionSender::doSendTransaction(std::s splitDestinations(transaction.firstTransferId, transaction.transferCount, changeDts, context->dustPolicy, splittedDests); Transaction tx; - constructTx(m_keys, sources, splittedDests, transaction.extra, transaction.unlockTime, m_upperTransactionSizeLimit, tx, context->messages); + constructTx(m_keys, sources, splittedDests, transaction.extra, transaction.unlockTime, m_upperTransactionSizeLimit, tx, context->messages, context->ttl); getObjectHash(tx, transaction.hash); diff --git a/src/WalletLegacy/WalletTransactionSender.h b/src/WalletLegacy/WalletTransactionSender.h index 0eacf39..6367060 100644 --- a/src/WalletLegacy/WalletTransactionSender.h +++ b/src/WalletLegacy/WalletTransactionSender.h @@ -32,7 +32,8 @@ class WalletTransactionSender const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0, - const std::vector& messages = std::vector()); + const std::vector& messages = std::vector(), + uint64_t ttl = 0); std::unique_ptr makeDepositRequest(TransactionId& transactionId, std::deque>& events, From c2369c462efc1ffac97c11ae8a7712bc26f094c4 Mon Sep 17 00:00:00 2001 From: xdn-project Date: Tue, 31 May 2016 14:32:48 +0000 Subject: [PATCH 02/26] Simplewallet console message sending --- src/Common/ConsoleHandler.cpp | 37 ++++++++++++++++++++-- src/CryptoNoteCore/TransactionPool.cpp | 32 +++++++++++-------- src/SimpleWallet/SimpleWallet.cpp | 44 ++++++++++++++++++++++++-- src/version.h.in | 4 +-- 4 files changed, 97 insertions(+), 20 deletions(-) diff --git a/src/Common/ConsoleHandler.cpp b/src/Common/ConsoleHandler.cpp index a9b96f7..a274c0f 100644 --- a/src/Common/ConsoleHandler.cpp +++ b/src/Common/ConsoleHandler.cpp @@ -192,9 +192,40 @@ bool ConsoleHandler::runCommand(const std::vector& cmdAndArgs) { } void ConsoleHandler::handleCommand(const std::string& cmd) { - std::vector args; - boost::split(args, cmd, boost::is_any_of(" "), boost::token_compress_on); - runCommand(args); + bool parseString = false; + std::string arg; + std::vector 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() { diff --git a/src/CryptoNoteCore/TransactionPool.cpp b/src/CryptoNoteCore/TransactionPool.cpp index 36072c4..4fa880c 100644 --- a/src/CryptoNoteCore/TransactionPool.cpp +++ b/src/CryptoNoteCore/TransactionPool.cpp @@ -123,19 +123,6 @@ namespace CryptoNote { ttl.ttl = 0; } - uint64_t now = static_cast(time(nullptr)); - if (ttl.ttl != 0) { - if (ttl.ttl <= now) { - logger(INFO, BRIGHT_WHITE) << "Transaction TTL has already expired: tx = " << id << ", ttl = " << ttl.ttl; - tvc.m_verifivation_failed = true; - return false; - } else if (ttl.ttl - now > m_currency.mempoolTxLiveTime() + m_currency.blockFutureTimeLimit()) { - logger(INFO, BRIGHT_WHITE) << "Transaction TTL is out of range: tx = " << id << ", ttl = " << ttl.ttl; - tvc.m_verifivation_failed = true; - return false; - } - } - const uint64_t fee = inputs_amount - outputs_amount; bool isFusionTransaction = fee == 0 && m_currency.isFusionTransaction(tx, blobSize); if (!keptByBlock && !isFusionTransaction && ttl.ttl == 0 && fee < m_currency.minimumFee()) { @@ -146,6 +133,25 @@ namespace CryptoNote { return false; } + if (ttl.ttl != 0 && !keptByBlock) { + uint64_t now = static_cast(time(nullptr)); + if (ttl.ttl <= now) { + logger(WARNING, BRIGHT_YELLOW) << "Transaction TTL has already expired: tx = " << id << ", ttl = " << ttl.ttl; + tvc.m_verifivation_failed = true; + return false; + } else if (ttl.ttl - now > m_currency.mempoolTxLiveTime() + m_currency.blockFutureTimeLimit()) { + logger(WARNING, BRIGHT_YELLOW) << "Transaction TTL is out of range: tx = " << id << ", ttl = " << ttl.ttl; + tvc.m_verifivation_failed = true; + return false; + } + + if (fee != 0) { + logger(WARNING, BRIGHT_YELLOW) << "Transaction with TTL has non-zero fee: tx = " << id << ", fee = " << m_currency.formatAmount(fee); + tvc.m_verifivation_failed = true; + return false; + } + } + //check key images for transaction if it is not kept by block if (!keptByBlock) { std::lock_guard lock(m_transactions_lock); diff --git a/src/SimpleWallet/SimpleWallet.cpp b/src/SimpleWallet/SimpleWallet.cpp index 7211adf..2179908 100644 --- a/src/SimpleWallet/SimpleWallet.cpp +++ b/src/SimpleWallet/SimpleWallet.cpp @@ -137,9 +137,11 @@ struct TransferCommand { std::vector extra; uint64_t fee; std::map> aliases; + std::vector messages; + uint64_t ttl; TransferCommand(const CryptoNote::Currency& currency) : - m_currency(currency), fake_outs_count(0), fee(currency.minimumFee()) { + m_currency(currency), fake_outs_count(0), fee(currency.minimumFee()), ttl(0) { } bool parseArguments(LoggerRef& logger, const std::vector &args) { @@ -155,6 +157,8 @@ struct TransferCommand { return false; } + bool feeFound = false; + bool ttlFound = false; while (!ar.eof()) { auto arg = ar.next(); @@ -169,6 +173,13 @@ struct TransferCommand { return false; } } else if (arg == "-f") { + feeFound = true; + + if (ttlFound) { + logger(ERROR, BRIGHT_RED) << "Transaction with TTL can not have fee"; + return false; + } + bool ok = m_currency.parseAmount(value, fee); if (!ok) { logger(ERROR, BRIGHT_RED) << "Fee value is invalid: " << value; @@ -179,6 +190,23 @@ struct TransferCommand { logger(ERROR, BRIGHT_RED) << "Fee value is less than minimum: " << m_currency.minimumFee(); return false; } + } else if (arg == "-m") { + messages.emplace_back(value); + } else if (arg == "-ttl") { + ttlFound = true; + + if (feeFound) { + logger(ERROR, BRIGHT_RED) << "Transaction with fee can not have TTL"; + return false; + } else { + fee = 0; + } + + if (!Common::fromString(value, ttl) || ttl < 1 || ttl * 60 > m_currency.mempoolTxLiveTime()) { + logger(ERROR, BRIGHT_RED) << "TTL has invalid format: \"" << value << "\", " << + "enter time from 1 to " << (m_currency.mempoolTxLiveTime() / 60) << " minutes"; + return false; + } } } else { WalletLegacyTransfer destination; @@ -1113,6 +1141,18 @@ bool simple_wallet::transfer(const std::vector &args) { } } + std::vector messages; + for (auto dst : cmd.dsts) { + for (auto msg : cmd.messages) { + messages.emplace_back(TransactionMessage{ msg, dst.address }); + } + } + + uint64_t ttl = 0; + if (cmd.ttl != 0) { + ttl = static_cast(time(nullptr)) + cmd.ttl; + } + CryptoNote::WalletHelper::SendCompleteResultObserver sent; std::string extraString; @@ -1120,7 +1160,7 @@ bool simple_wallet::transfer(const std::vector &args) { WalletHelper::IWalletRemoveObserverGuard removeGuard(*m_wallet, sent); - CryptoNote::TransactionId tx = m_wallet->sendTransaction(cmd.dsts, cmd.fee, extraString, cmd.fake_outs_count, 0); + CryptoNote::TransactionId tx = m_wallet->sendTransaction(cmd.dsts, cmd.fee, extraString, cmd.fake_outs_count, 0, messages, ttl); if (tx == WALLET_LEGACY_INVALID_TRANSACTION_ID) { fail_msg_writer() << "Can't send money"; return true; diff --git a/src/version.h.in b/src/version.h.in index 802686f..2090301 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define BUILD_COMMIT_ID "@VERSION@" -#define PROJECT_VERSION "0.1.1" -#define PROJECT_VERSION_BUILD_NO "cedi0010" +#define PROJECT_VERSION "0.1.2" +#define PROJECT_VERSION_BUILD_NO "cedi0011" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")" From 95f2f301a0404575c2e584cb5ba479e58958db7d Mon Sep 17 00:00:00 2001 From: aivve Date: Sat, 21 Apr 2018 18:07:51 +0300 Subject: [PATCH 03/26] Block upgrade --- src/CryptoNoteConfig.h | 4 +- src/CryptoNoteCore/Blockchain.cpp | 24 +++- src/CryptoNoteCore/Blockchain.h | 3 +- src/CryptoNoteCore/Core.cpp | 14 ++- src/CryptoNoteCore/Currency.cpp | 16 ++- src/CryptoNoteCore/Currency.h | 22 ++-- src/CryptoNoteCore/UpgradeDetector.h | 143 ++++++++++++++-------- tests/CoreTests/BlockValidation.cpp | 2 +- tests/CoreTests/BlockValidation.h | 6 +- tests/CoreTests/Deposit.h | 6 +- tests/CoreTests/DoubleSpend.cpp | 2 +- tests/CoreTests/TransactionValidation.cpp | 4 +- tests/CoreTests/Upgrade.cpp | 7 +- tests/UnitTests/TestUpgradeDetector.cpp | 7 +- 14 files changed, 168 insertions(+), 92 deletions(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index cc3b163..ac6354a 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -63,7 +63,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 = 4294967294; 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 @@ -91,6 +92,7 @@ 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; diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index a19618f..feed621 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -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); @@ -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; } @@ -690,7 +696,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 &original_chain, size_t rollback_height) { @@ -1896,7 +1908,8 @@ bool Blockchain::pushBlock(const Block& blockData, const std::vector(); b.majorVersion = m_blockchain.get_block_major_version_for_height(height); - if (BLOCK_MAJOR_VERSION_1 == b.majorVersion) { - b.minorVersion = BLOCK_MINOR_VERSION_1; - } else if (BLOCK_MAJOR_VERSION_2 == b.majorVersion) { - b.minorVersion = BLOCK_MINOR_VERSION_0; - } + if (b.majorVersion < BLOCK_MAJOR_VERSION_3) { + if (b.majorVersion == BLOCK_MAJOR_VERSION_1) { + b.minorVersion = m_currency.upgradeHeight(BLOCK_MAJOR_VERSION_2) == UpgradeDetectorBase::UNDEF_HEIGHT ? BLOCK_MINOR_VERSION_1 : BLOCK_MINOR_VERSION_0; + } else { + b.minorVersion = m_currency.upgradeHeight(BLOCK_MAJOR_VERSION_3) == UpgradeDetectorBase::UNDEF_HEIGHT ? BLOCK_MINOR_VERSION_1 : BLOCK_MINOR_VERSION_0; + } + } else { + b.minorVersion = BLOCK_MINOR_VERSION_0; + } b.previousBlockHash = get_tail_id(); b.timestamp = time(NULL); diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 478bf1c..dbc5c51 100644 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -60,7 +60,8 @@ bool Currency::init() { } if (isTestnet()) { - m_upgradeHeight = 0; + m_upgradeHeightV2 = 0; + m_upgradeHeightV3 = static_cast(-1); m_blocksFileName = "testnet_" + m_blocksFileName; m_blocksCacheFileName = "testnet_" + m_blocksCacheFileName; m_blockIndexesFileName = "testnet_" + m_blockIndexesFileName; @@ -106,6 +107,16 @@ uint64_t Currency::baseRewardFunction(uint64_t alreadyGeneratedCoins, uint32_t h return base_reward; } +uint32_t Currency::upgradeHeight(uint8_t majorVersion) const { + if (majorVersion == BLOCK_MAJOR_VERSION_2) { + return m_upgradeHeightV2; + } else if (majorVersion == BLOCK_MAJOR_VERSION_3) { + return m_upgradeHeightV3; + } else { + return static_cast(-1); + } +} + bool Currency::getBlockReward(size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins, uint64_t fee, uint32_t height, uint64_t& reward, int64_t& emissionChange) const { assert(alreadyGeneratedCoins <= m_moneySupply); @@ -567,7 +578,8 @@ CurrencyBuilder::CurrencyBuilder(Logging::ILogger& log) : m_currency(log) { mempoolTxFromAltBlockLiveTime(parameters::CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME); numberOfPeriodsToForgetTxDeletedFromPool(parameters::CRYPTONOTE_NUMBER_OF_PERIODS_TO_FORGET_TX_DELETED_FROM_POOL); - upgradeHeight(parameters::UPGRADE_HEIGHT); + upgradeHeightV2(parameters::UPGRADE_HEIGHT_V2); + upgradeHeightV3(parameters::UPGRADE_HEIGHT_V3); upgradeVotingThreshold(parameters::UPGRADE_VOTING_THRESHOLD); upgradeVotingWindow(parameters::UPGRADE_VOTING_WINDOW); upgradeWindow(parameters::UPGRADE_WINDOW); diff --git a/src/CryptoNoteCore/Currency.h b/src/CryptoNoteCore/Currency.h index 350a458..ca34cb8 100644 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -66,13 +66,13 @@ class Currency { uint64_t mempoolTxFromAltBlockLiveTime() const { return m_mempoolTxFromAltBlockLiveTime; } uint64_t numberOfPeriodsToForgetTxDeletedFromPool() const { return m_numberOfPeriodsToForgetTxDeletedFromPool; } - uint64_t upgradeHeight() const { return m_upgradeHeight; } + uint32_t upgradeHeight(uint8_t majorVersion) const; unsigned int upgradeVotingThreshold() const { return m_upgradeVotingThreshold; } - size_t upgradeVotingWindow() const { return m_upgradeVotingWindow; } - size_t upgradeWindow() const { return m_upgradeWindow; } - size_t minNumberVotingBlocks() const { return (m_upgradeVotingWindow * m_upgradeVotingThreshold + 99) / 100; } - uint64_t maxUpgradeDistance() const { return static_cast(m_upgradeWindow); } - uint64_t calculateUpgradeHeight(uint64_t voteCompleteHeight) const { return voteCompleteHeight + m_upgradeWindow; } + uint32_t upgradeVotingWindow() const { return m_upgradeVotingWindow; } + uint32_t upgradeWindow() const { return m_upgradeWindow; } + uint32_t minNumberVotingBlocks() const { return (m_upgradeVotingWindow * m_upgradeVotingThreshold + 99) / 100; } + uint32_t maxUpgradeDistance() const { return 7 * m_upgradeWindow; } + uint32_t calculateUpgradeHeight(uint32_t voteCompleteHeight) const { return voteCompleteHeight + m_upgradeWindow; } size_t fusionTxMaxSize() const { return m_fusionTxMaxSize; } size_t fusionTxMinInputCount() const { return m_fusionTxMinInputCount; } @@ -176,10 +176,11 @@ class Currency { uint64_t m_mempoolTxFromAltBlockLiveTime; uint64_t m_numberOfPeriodsToForgetTxDeletedFromPool; - uint64_t m_upgradeHeight; + uint32_t m_upgradeHeightV2; + uint32_t m_upgradeHeightV3; unsigned int m_upgradeVotingThreshold; - size_t m_upgradeVotingWindow; - size_t m_upgradeWindow; + uint32_t m_upgradeVotingWindow; + uint32_t m_upgradeWindow; size_t m_fusionTxMaxSize; size_t m_fusionTxMinInputCount; @@ -261,7 +262,8 @@ class CurrencyBuilder : boost::noncopyable { CurrencyBuilder& mempoolTxFromAltBlockLiveTime(uint64_t val) { m_currency.m_mempoolTxFromAltBlockLiveTime = val; return *this; } CurrencyBuilder& numberOfPeriodsToForgetTxDeletedFromPool(uint64_t val) { m_currency.m_numberOfPeriodsToForgetTxDeletedFromPool = val; return *this; } - CurrencyBuilder& upgradeHeight(uint64_t val) { m_currency.m_upgradeHeight = val; return *this; } + CurrencyBuilder& upgradeHeightV2(uint64_t val) { m_currency.m_upgradeHeightV2 = val; return *this; } + CurrencyBuilder& upgradeHeightV3(uint64_t val) { m_currency.m_upgradeHeightV3 = val; return *this; } CurrencyBuilder& upgradeVotingThreshold(unsigned int val); CurrencyBuilder& upgradeVotingWindow(size_t val) { m_currency.m_upgradeVotingWindow = val; return *this; } CurrencyBuilder& upgradeWindow(size_t val); diff --git a/src/CryptoNoteCore/UpgradeDetector.h b/src/CryptoNoteCore/UpgradeDetector.h index 46c840a..e42d977 100644 --- a/src/CryptoNoteCore/UpgradeDetector.h +++ b/src/CryptoNoteCore/UpgradeDetector.h @@ -1,5 +1,5 @@ // Copyright (c) 2011-2016 The Cryptonote developers -// Copyright (c) 2014-2016 SDN developers +// Copyright (c) 2014-2016 XDN-project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +9,9 @@ #include #include +#include "Common/StringTools.h" +#include "CryptoNoteCore/CryptoNoteBasicImpl.h" +#include "CryptoNoteCore/CryptoNoteFormatUtils.h" #include "CryptoNoteCore/Currency.h" #include "CryptoNoteConfig.h" #include @@ -16,12 +19,12 @@ namespace CryptoNote { class UpgradeDetectorBase { public: - enum : uint64_t { - UNDEF_HEIGHT = static_cast(-1), + enum : uint32_t { + UNDEF_HEIGHT = static_cast(-1), }; }; - static_assert(CryptoNote::UpgradeDetectorBase::UNDEF_HEIGHT == UINT64_C(0xFFFFFFFFFFFFFFFF), "UpgradeDetectorBase::UNDEF_HEIGHT has invalid value"); + static_assert(CryptoNote::UpgradeDetectorBase::UNDEF_HEIGHT == UINT32_C(0xFFFFFFFF), "UpgradeDetectorBase::UNDEF_HEIGHT has invalid value"); template class BasicUpgradeDetector : public UpgradeDetectorBase { @@ -31,10 +34,12 @@ namespace CryptoNote { m_blockchain(blockchain), m_targetVersion(targetVersion), m_votingCompleteHeight(UNDEF_HEIGHT), - logger(log, "upgrade") { } + logger(log, "upgrade") { + } bool init() { - if (m_currency.upgradeHeight() == UNDEF_HEIGHT) { + uint32_t upgradeHeight = m_currency.upgradeHeight(m_targetVersion); + if (upgradeHeight == UNDEF_HEIGHT) { if (m_blockchain.empty()) { m_votingCompleteHeight = UNDEF_HEIGHT; @@ -44,51 +49,73 @@ namespace CryptoNote { } else if (m_targetVersion <= m_blockchain.back().bl.majorVersion) { auto it = std::lower_bound(m_blockchain.begin(), m_blockchain.end(), m_targetVersion, [](const typename BC::value_type& b, uint8_t v) { return b.bl.majorVersion < v; }); - if (!(it != m_blockchain.end() && it->bl.majorVersion == m_targetVersion)) { logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: upgrade height isn't found"; return false; } - uint64_t upgradeHeight = it - m_blockchain.begin(); - m_votingCompleteHeight = findVotingCompleteHeight(upgradeHeight); - if (!(m_votingCompleteHeight != UNDEF_HEIGHT)) { logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: voting complete height isn't found, upgrade height = " << upgradeHeight; return false; } + if (it == m_blockchain.end() || it->bl.majorVersion != m_targetVersion) { + logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: upgrade height isn't found"; + return false; + } + uint32_t upgradeHeight = it - m_blockchain.begin(); + m_votingCompleteHeight = findVotingCompleteHeight(upgradeHeight); + if (m_votingCompleteHeight == UNDEF_HEIGHT) { + logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: voting complete height isn't found, upgrade height = " << upgradeHeight; + return false; + } } else { m_votingCompleteHeight = UNDEF_HEIGHT; } } else if (!m_blockchain.empty()) { - if (m_blockchain.size() <= m_currency.upgradeHeight() + 1) { - if (!(m_blockchain.back().bl.majorVersion == m_targetVersion - 1)) { logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: block at height " << (m_blockchain.size() - 1) << " has invalid version " << - static_cast(m_blockchain.back().bl.majorVersion) << ", expected " << static_cast(m_targetVersion); return false; } + if (m_blockchain.size() <= upgradeHeight + 1) { + if (m_blockchain.back().bl.majorVersion >= m_targetVersion) { + logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: block at height " << (m_blockchain.size() - 1) << + " has invalid version " << static_cast(m_blockchain.back().bl.majorVersion) << + ", expected " << static_cast(m_targetVersion - 1) << " or less"; + return false; + } } else { - int blockVersionAtUpgradeHeight = m_blockchain[m_currency.upgradeHeight()].bl.majorVersion; - if (!(blockVersionAtUpgradeHeight == m_targetVersion - 1)) { logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: block at height " << m_currency.upgradeHeight() << " has invalid version " << - blockVersionAtUpgradeHeight << ", expected " << static_cast(m_targetVersion - 1); return false; } + int blockVersionAtUpgradeHeight = m_blockchain[upgradeHeight].bl.majorVersion; + if (blockVersionAtUpgradeHeight != m_targetVersion - 1) { + logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: block at height " << upgradeHeight << + " has invalid version " << blockVersionAtUpgradeHeight << + ", expected " << static_cast(m_targetVersion - 1); + return false; + } - int blockVersionAfterUpgradeHeight = m_blockchain[m_currency.upgradeHeight() + 1].bl.majorVersion; - if (!(blockVersionAfterUpgradeHeight == m_targetVersion)) { logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: block at height " << (m_currency.upgradeHeight() + 1) << " has invalid version " << - blockVersionAfterUpgradeHeight << ", expected " << static_cast(m_targetVersion); return false; } + int blockVersionAfterUpgradeHeight = m_blockchain[upgradeHeight + 1].bl.majorVersion; + if (blockVersionAfterUpgradeHeight != m_targetVersion) { + logger(Logging::ERROR, Logging::BRIGHT_RED) << "Internal error: block at height " << (upgradeHeight + 1) << + " has invalid version " << blockVersionAfterUpgradeHeight << + ", expected " << static_cast(m_targetVersion); + return false; + } } } return true; } - uint8_t targetVersion() const { return m_targetVersion; } - uint64_t votingCompleteHeight() const { return m_votingCompleteHeight; } + uint8_t targetVersion() const { + return m_targetVersion; + } + uint32_t votingCompleteHeight() const { + return m_votingCompleteHeight; + } - uint64_t upgradeHeight() const { - if (m_currency.upgradeHeight() == UNDEF_HEIGHT) { + uint32_t upgradeHeight() const { + if (m_currency.upgradeHeight(m_targetVersion) == UNDEF_HEIGHT) { return m_votingCompleteHeight == UNDEF_HEIGHT ? UNDEF_HEIGHT : m_currency.calculateUpgradeHeight(m_votingCompleteHeight); } else { - return m_currency.upgradeHeight(); + return m_currency.upgradeHeight(m_targetVersion); } } void blockPushed() { assert(!m_blockchain.empty()); - if (m_currency.upgradeHeight() != UNDEF_HEIGHT) { - if (m_blockchain.size() <= m_currency.upgradeHeight() + 1) { - assert(m_blockchain.back().bl.majorVersion == m_targetVersion - 1); + if (m_currency.upgradeHeight(m_targetVersion) != UNDEF_HEIGHT) { + if (m_blockchain.size() <= m_currency.upgradeHeight(m_targetVersion) + 1) { + assert(m_blockchain.back().bl.majorVersion <= m_targetVersion - 1); } else { - assert(m_blockchain.back().bl.majorVersion == m_targetVersion); + assert(m_blockchain.back().bl.majorVersion >= m_targetVersion); } } else if (m_votingCompleteHeight != UNDEF_HEIGHT) { @@ -98,33 +125,41 @@ namespace CryptoNote { assert(m_blockchain.back().bl.majorVersion == m_targetVersion - 1); if (m_blockchain.size() % (60 * 60 / m_currency.difficultyTarget()) == 0) { - logger(Logging::TRACE, Logging::BRIGHT_GREEN) << "###### UPGRADE is going to happen after height " << upgradeHeight() << "!"; + auto interval = m_currency.difficultyTarget() * (upgradeHeight() - m_blockchain.size() + 2); + time_t upgradeTimestamp = time(nullptr) + static_cast(interval); + struct tm* upgradeTime = localtime(&upgradeTimestamp);; + char upgradeTimeStr[40]; + strftime(upgradeTimeStr, 40, "%H:%M:%S %Y.%m.%d", upgradeTime); + + logger(Logging::TRACE, Logging::BRIGHT_GREEN) << "###### UPGRADE is going to happen after block index " << upgradeHeight() << " at about " << + upgradeTimeStr << " (in " << Common::timeIntervalToString(interval) << ")! Current last block index " << (m_blockchain.size() - 1) << + ", hash " << get_block_hash(m_blockchain.back().bl); } } else if (m_blockchain.size() == upgradeHeight() + 1) { assert(m_blockchain.back().bl.majorVersion == m_targetVersion - 1); - logger(Logging::TRACE, Logging::BRIGHT_GREEN) << "###### UPGRADE has happened! Starting from height " << (upgradeHeight() + 1) << + logger(Logging::TRACE, Logging::BRIGHT_GREEN) << "###### UPGRADE has happened! Starting from block index " << (upgradeHeight() + 1) << " blocks with major version below " << static_cast(m_targetVersion) << " will be rejected!"; } else { assert(m_blockchain.back().bl.majorVersion == m_targetVersion); } } else { - uint64_t lastBlockHeight = m_blockchain.size() - 1; + uint32_t lastBlockHeight = m_blockchain.size() - 1; if (isVotingComplete(lastBlockHeight)) { m_votingCompleteHeight = lastBlockHeight; - logger(Logging::TRACE, Logging::BRIGHT_GREEN) << "###### UPGRADE voting complete at height " << m_votingCompleteHeight << - "! UPGRADE is going to happen after height " << upgradeHeight() << "!"; + logger(Logging::TRACE, Logging::BRIGHT_GREEN) << "###### UPGRADE voting complete at block index " << m_votingCompleteHeight << + "! UPGRADE is going to happen after block index " << upgradeHeight() << "!"; } } } void blockPopped() { if (m_votingCompleteHeight != UNDEF_HEIGHT) { - assert(m_currency.upgradeHeight() == UNDEF_HEIGHT); + assert(m_currency.upgradeHeight(m_targetVersion) == UNDEF_HEIGHT); if (m_blockchain.size() == m_votingCompleteHeight) { - logger(Logging::TRACE, Logging::BRIGHT_YELLOW) << "###### UPGRADE after height " << upgradeHeight() << " has been cancelled!"; + logger(Logging::TRACE, Logging::BRIGHT_YELLOW) << "###### UPGRADE after block index " << upgradeHeight() << " has been canceled!"; m_votingCompleteHeight = UNDEF_HEIGHT; } else { assert(m_blockchain.size() > m_votingCompleteHeight); @@ -132,12 +167,25 @@ namespace CryptoNote { } } + size_t getNumberOfVotes(uint32_t height) { + if (height < m_currency.upgradeVotingWindow() - 1) { + return 0; + } + + size_t voteCounter = 0; + for (size_t i = height + 1 - m_currency.upgradeVotingWindow(); i <= height; ++i) { + const auto& b = m_blockchain[i].bl; + voteCounter += (b.majorVersion == m_targetVersion - 1) && (b.minorVersion == BLOCK_MINOR_VERSION_1) ? 1 : 0; + } + + return voteCounter; + } + private: - uint64_t findVotingCompleteHeight(uint64_t probableUpgradeHeight) { - assert(m_currency.upgradeHeight() == UNDEF_HEIGHT); + uint32_t findVotingCompleteHeight(uint32_t probableUpgradeHeight) { + assert(m_currency.upgradeHeight(m_targetVersion) == UNDEF_HEIGHT); - uint64_t probableVotingCompleteHeight = probableUpgradeHeight > m_currency.maxUpgradeDistance() ? - probableUpgradeHeight - m_currency.maxUpgradeDistance() : 0; + uint32_t probableVotingCompleteHeight = probableUpgradeHeight > m_currency.maxUpgradeDistance() ? probableUpgradeHeight - m_currency.maxUpgradeDistance() : 0; for (size_t i = probableVotingCompleteHeight; i <= probableUpgradeHeight; ++i) { if (isVotingComplete(i)) { return i; @@ -147,21 +195,12 @@ namespace CryptoNote { return UNDEF_HEIGHT; } - bool isVotingComplete(uint64_t height) { - assert(m_currency.upgradeHeight() == UNDEF_HEIGHT); + bool isVotingComplete(uint32_t height) { + assert(m_currency.upgradeHeight(m_targetVersion) == UNDEF_HEIGHT); assert(m_currency.upgradeVotingWindow() > 1); assert(m_currency.upgradeVotingThreshold() > 0 && m_currency.upgradeVotingThreshold() <= 100); - if (height < static_cast(m_currency.upgradeVotingWindow()) - 1) { - return false; - } - - unsigned int voteCounter = 0; - for (size_t i = height + 1 - m_currency.upgradeVotingWindow(); i <= height; ++i) { - const auto& b = m_blockchain[i].bl; - voteCounter += (b.majorVersion == m_targetVersion - 1) && (b.minorVersion == BLOCK_MINOR_VERSION_1) ? 1 : 0; - } - + size_t voteCounter = getNumberOfVotes(height); return m_currency.upgradeVotingThreshold() * m_currency.upgradeVotingWindow() <= 100 * voteCounter; } @@ -170,6 +209,6 @@ namespace CryptoNote { const Currency& m_currency; BC& m_blockchain; uint8_t m_targetVersion; - uint64_t m_votingCompleteHeight; + uint32_t m_votingCompleteHeight; }; } diff --git a/tests/CoreTests/BlockValidation.cpp b/tests/CoreTests/BlockValidation.cpp index dcaa79b..c02e72d 100644 --- a/tests/CoreTests/BlockValidation.cpp +++ b/tests/CoreTests/BlockValidation.cpp @@ -583,7 +583,7 @@ gen_block_invalid_binary_format::gen_block_invalid_binary_format(uint8_t blockMa m_corrupt_blocks_begin_idx(0), m_blockMajorVersion(blockMajorVersion) { CryptoNote::CurrencyBuilder currencyBuilder(m_logger); - currencyBuilder.upgradeHeight(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : 0); + currencyBuilder.upgradeHeightV2(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : 0); m_currency = currencyBuilder.currency(); REGISTER_CALLBACK("check_all_blocks_purged", gen_block_invalid_binary_format::check_all_blocks_purged); diff --git a/tests/CoreTests/BlockValidation.h b/tests/CoreTests/BlockValidation.h index 7618b37..7994b63 100644 --- a/tests/CoreTests/BlockValidation.h +++ b/tests/CoreTests/BlockValidation.h @@ -17,7 +17,7 @@ class CheckBlockPurged : public test_chain_unit_base { assert(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 || blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_2); CryptoNote::CurrencyBuilder currencyBuilder(m_logger); - currencyBuilder.upgradeHeight(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : UINT64_C(0)); + currencyBuilder.upgradeHeightV2(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : UINT64_C(0)); m_currency = currencyBuilder.currency(); REGISTER_CALLBACK("check_block_purged", CheckBlockPurged::check_block_purged); @@ -60,7 +60,7 @@ struct CheckBlockAccepted : public test_chain_unit_base { assert(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 || blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_2); CryptoNote::CurrencyBuilder currencyBuilder(m_logger); - currencyBuilder.upgradeHeight(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : UINT64_C(0)); + currencyBuilder.upgradeHeightV2(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : UINT64_C(0)); m_currency = currencyBuilder.currency(); REGISTER_CALLBACK("check_block_accepted", CheckBlockAccepted::check_block_accepted); @@ -287,7 +287,7 @@ struct gen_block_is_too_big : public CheckBlockPurged gen_block_is_too_big(uint8_t blockMajorVersion) : CheckBlockPurged(1, blockMajorVersion) { CryptoNote::CurrencyBuilder currencyBuilder(m_logger); - currencyBuilder.upgradeHeight(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : UINT64_C(0)); + currencyBuilder.upgradeHeightV2(blockMajorVersion == CryptoNote::BLOCK_MAJOR_VERSION_1 ? UNDEF_HEIGHT : UINT64_C(0)); currencyBuilder.maxBlockSizeInitial(std::numeric_limits::max() / 2); m_currency = currencyBuilder.currency(); } diff --git a/tests/CoreTests/Deposit.h b/tests/CoreTests/Deposit.h index cf5c81d..0feae81 100644 --- a/tests/CoreTests/Deposit.h +++ b/tests/CoreTests/Deposit.h @@ -14,7 +14,7 @@ namespace DepositTests { struct DepositTestsBase : public test_chain_unit_base { DepositTestsBase() { - m_currency = CryptoNote::CurrencyBuilder(m_logger).upgradeHeight(0).depositMinTerm(10).depositMinTotalRateFactor(100).currency(); + m_currency = CryptoNote::CurrencyBuilder(m_logger).upgradeHeightV2(0).depositMinTerm(10).depositMinTotalRateFactor(100).currency(); from.generate(); to.generate(); REGISTER_CALLBACK_METHOD(DepositTestsBase, mark_invalid_block); @@ -64,7 +64,7 @@ struct DepositIndexTest : public DepositTestsBase { using Core = CryptoNote::core; using Events = std::vector; DepositIndexTest() { - m_currency = CryptoNote::CurrencyBuilder(m_logger).upgradeHeight(0).depositMinTerm(10).depositMinTotalRateFactor(100).mininumFee(1000).currency(); + m_currency = CryptoNote::CurrencyBuilder(m_logger).upgradeHeightV2(0).depositMinTerm(10).depositMinTotalRateFactor(100).mininumFee(1000).currency(); REGISTER_CALLBACK_METHOD(DepositIndexTest, interestZero); REGISTER_CALLBACK_METHOD(DepositIndexTest, interestOneMinimal); REGISTER_CALLBACK_METHOD(DepositIndexTest, interestTwoMininmal); @@ -100,7 +100,7 @@ struct DepositIndexTest : public DepositTestsBase { struct EmissionTest : public DepositTestsBase { EmissionTest() { - m_currency = CryptoNote::CurrencyBuilder(m_logger).upgradeHeight(0).depositMinTerm(10).depositMinTotalRateFactor(100).currency(); + m_currency = CryptoNote::CurrencyBuilder(m_logger).upgradeHeightV2(0).depositMinTerm(10).depositMinTotalRateFactor(100).currency(); REGISTER_CALLBACK_METHOD(EmissionTest, save_emission_before); REGISTER_CALLBACK_METHOD(EmissionTest, save_emission_after); } diff --git a/tests/CoreTests/DoubleSpend.cpp b/tests/CoreTests/DoubleSpend.cpp index bb3a92f..95cb200 100644 --- a/tests/CoreTests/DoubleSpend.cpp +++ b/tests/CoreTests/DoubleSpend.cpp @@ -79,7 +79,7 @@ DoubleSpendBase::DoubleSpendBase() : send_amount(MK_COINS(17)), has_invalid_tx(false) { - m_currency = CurrencyBuilder(m_logger).upgradeHeight(0).currency(); + m_currency = CurrencyBuilder(m_logger).upgradeHeightV2(0).currency(); m_outputTxKey = generateKeyPair(); m_bob_account.generate(); m_alice_account.generate(); diff --git a/tests/CoreTests/TransactionValidation.cpp b/tests/CoreTests/TransactionValidation.cpp index 8bd5d0d..056e6e5 100644 --- a/tests/CoreTests/TransactionValidation.cpp +++ b/tests/CoreTests/TransactionValidation.cpp @@ -701,7 +701,7 @@ bool GenerateTransactionWithZeroFee::generate(std::vector& eve MultiSigTx_OutputSignatures::MultiSigTx_OutputSignatures(size_t givenKeys, uint32_t requiredSignatures, bool shouldSucceed) : m_givenKeys(givenKeys), m_requiredSignatures(requiredSignatures), m_shouldSucceed(shouldSucceed) { - m_currency = CurrencyBuilder(m_logger).upgradeHeight(0).currency(); + m_currency = CurrencyBuilder(m_logger).upgradeHeightV2(0).currency(); for (size_t i = 0; i < m_givenKeys; ++i) { AccountBase acc; @@ -832,7 +832,7 @@ MultiSigTx_Input::MultiSigTx_Input( m_givenSignatures(givenSignatures), m_inputShouldSucceed(inputShouldSucceed) { - m_currency = CurrencyBuilder(m_logger).upgradeHeight(0).currency(); + m_currency = CurrencyBuilder(m_logger).upgradeHeightV2(0).currency(); } bool MultiSigTx_Input::generate(std::vector& events) const { diff --git a/tests/CoreTests/Upgrade.cpp b/tests/CoreTests/Upgrade.cpp index e575bc9..0d542d4 100644 --- a/tests/CoreTests/Upgrade.cpp +++ b/tests/CoreTests/Upgrade.cpp @@ -34,7 +34,8 @@ namespace { gen_upgrade::gen_upgrade() : m_invalidBlockIndex(0), m_checkBlockTemplateVersionCallCounter(0) { CryptoNote::CurrencyBuilder currencyBuilder(m_logger); currencyBuilder.maxBlockSizeInitial(std::numeric_limits::max() / 2); - currencyBuilder.upgradeHeight(UpgradeDetectorBase::UNDEF_HEIGHT); + currencyBuilder.upgradeHeightV2(UpgradeDetectorBase::UNDEF_HEIGHT); + currencyBuilder.upgradeHeightV3(UpgradeDetectorBase::UNDEF_HEIGHT); m_currency = currencyBuilder.currency(); REGISTER_CALLBACK_METHOD(gen_upgrade, markInvalidBlock); @@ -191,8 +192,8 @@ bool gen_upgrade::checkBlockTemplateVersion(CryptoNote::core& c, uint8_t expecte difficulty_type diff; uint32_t height; CHECK_TEST_CONDITION(c.get_block_template(b, account.getAccountKeys().address, diff, height, BinaryArray())); - CHECK_EQ(b.majorVersion, expectedMajorVersion); - CHECK_EQ(b.minorVersion, expectedMinorVersion); + CHECK_EQ(static_cast(b.majorVersion), static_cast(expectedMajorVersion)); + CHECK_EQ(static_cast(b.minorVersion), static_cast(expectedMinorVersion)); return true; } diff --git a/tests/UnitTests/TestUpgradeDetector.cpp b/tests/UnitTests/TestUpgradeDetector.cpp index 43c5ed9..e66a238 100644 --- a/tests/UnitTests/TestUpgradeDetector.cpp +++ b/tests/UnitTests/TestUpgradeDetector.cpp @@ -33,7 +33,8 @@ namespace { currencyBuilder.upgradeVotingThreshold(90); currencyBuilder.upgradeVotingWindow(720); currencyBuilder.upgradeWindow(720); - currencyBuilder.upgradeHeight(upgradeHeight); + currencyBuilder.upgradeHeightV2(upgradeHeight); + currencyBuilder.upgradeHeightV3(UpgradeDetector::UNDEF_HEIGHT); return currencyBuilder.currency(); } @@ -153,14 +154,14 @@ namespace { // Upgrade to v2 is here createBlocks(blocks, 1, BLOCK_MAJOR_VERSION_2, BLOCK_MINOR_VERSION_0); - createBlocks(blocks, currency.upgradeVotingWindow(), BLOCK_MAJOR_VERSION_2, BLOCK_MINOR_VERSION_1); + createBlocks(blocks, currency.upgradeVotingWindow() * currency.upgradeVotingThreshold() / 100, BLOCK_MAJOR_VERSION_2, BLOCK_MINOR_VERSION_1); uint64_t votingCompleteHeigntV3 = blocks.size() - 1; uint64_t upgradeHeightV3 = currency.calculateUpgradeHeight(votingCompleteHeigntV3); createBlocks(blocks, upgradeHeightV3 - blocks.size(), BLOCK_MAJOR_VERSION_2, BLOCK_MINOR_VERSION_0); // Upgrade to v3 is here createBlocks(blocks, 1, BLOCK_V3, BLOCK_MINOR_VERSION_0); - createBlocks(blocks, currency.upgradeVotingWindow(), BLOCK_V3, BLOCK_MINOR_VERSION_1); + createBlocks(blocks, currency.upgradeVotingWindow() * currency.upgradeVotingThreshold() / 100, BLOCK_V3, BLOCK_MINOR_VERSION_1); uint64_t votingCompleteHeigntV4 = blocks.size() - 1; uint64_t upgradeHeightV4 = currency.calculateUpgradeHeight(votingCompleteHeigntV4); createBlocks(blocks, upgradeHeightV4 - blocks.size(), BLOCK_V3, BLOCK_MINOR_VERSION_0); From 350c8f22de90ceadac08462e1752243947ebcb7d Mon Sep 17 00:00:00 2001 From: aivve Date: Sat, 21 Apr 2018 20:48:14 +0300 Subject: [PATCH 04/26] Simplified Zawy LWMA Difficulty --- src/CryptoNoteConfig.h | 6 +- src/CryptoNoteCore/Blockchain.cpp | 24 +++-- src/CryptoNoteCore/Currency.cpp | 138 +++++++++++++++++++--------- src/CryptoNoteCore/Currency.h | 3 +- tests/CoreTests/BlockValidation.cpp | 8 +- tests/Difficulty/Difficulty.cpp | 1 + 6 files changed, 120 insertions(+), 60 deletions(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index ac6354a..e86db5d 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -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); @@ -32,9 +32,9 @@ const uint64_t MINIMUM_FEE = UINT64_C(100000); const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(100000); // pow(10, 5) //const uint64_t GENESIS_BLOCK_REWARD = UINT64_C(0); -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"); diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index feed621..d5b420e 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -657,7 +657,8 @@ difficulty_type Blockchain::getDifficultyForNextBlock() { std::lock_guard lk(m_blockchain_lock); std::vector timestamps; std::vector commulative_difficulties; - size_t offset = m_blocks.size() - std::min(m_blocks.size(), static_cast(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((BlockMajorVersion >= BLOCK_MAJOR_VERSION_3 ? m_currency.difficultyBlocksCount2() + 1 : m_currency.difficultyBlocksCount()))); if (offset == 0) { ++offset; } @@ -667,7 +668,7 @@ 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::getCoinsInCirculation() { @@ -809,10 +810,13 @@ bool Blockchain::switch_to_alternative_blockchain(std::list& alt_chain, BlockEntry& bei) { std::vector timestamps; std::vector 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 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; @@ -823,30 +827,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) { diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index dbc5c51..432b3a0 100644 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -456,49 +456,103 @@ bool Currency::parseAmount(const std::string& str, uint64_t& amount) const { return Common::fromString(strAmount, amount); } -difficulty_type Currency::nextDifficulty(std::vector timestamps, +difficulty_type Currency::nextDifficulty(uint8_t blockMajorVersion, std::vector timestamps, std::vector cumulativeDifficulties) const { - assert(m_difficultyWindow >= 2); - - if (timestamps.size() > m_difficultyWindow) { - timestamps.resize(m_difficultyWindow); - cumulativeDifficulties.resize(m_difficultyWindow); - } - - size_t length = timestamps.size(); - assert(length == cumulativeDifficulties.size()); - assert(length <= m_difficultyWindow); - if (length <= 1) { - return 1; - } - - sort(timestamps.begin(), timestamps.end()); - - size_t cutBegin, cutEnd; - assert(2 * m_difficultyCut <= m_difficultyWindow - 2); - if (length <= m_difficultyWindow - 2 * m_difficultyCut) { - cutBegin = 0; - cutEnd = length; - } else { - cutBegin = (length - (m_difficultyWindow - 2 * m_difficultyCut) + 1) / 2; - cutEnd = cutBegin + (m_difficultyWindow - 2 * m_difficultyCut); - } - assert(/*cut_begin >= 0 &&*/ cutBegin + 2 <= cutEnd && cutEnd <= length); - uint64_t timeSpan = timestamps[cutEnd - 1] - timestamps[cutBegin]; - if (timeSpan == 0) { - timeSpan = 1; - } - - difficulty_type totalWork = cumulativeDifficulties[cutEnd - 1] - cumulativeDifficulties[cutBegin]; - assert(totalWork > 0); - - uint64_t low, high; - low = mul128(totalWork, m_difficultyTarget, &high); - if (high != 0 || low + timeSpan - 1 < low) { - return 0; - } - - return (low + timeSpan - 1) / timeSpan; + if (blockMajorVersion >= BLOCK_MAJOR_VERSION_3) { + + // LWMA difficulty algorithm (simplified) + // Copyright (c) 2017-2018 Zawy + // MIT license http://www.opensource.org/licenses/mit-license.php + // set constants: + // N is most recent solved block. + // T= target solvetime, adjust = 0.9989^(500/N), N=int((45*(600/T)^(0.3*(600/T)^0.2) + // timestamp, cumulativedifficulties, and target are vectors of size N+1 + + const int64_t T = static_cast(m_difficultyTarget); + size_t N = CryptoNote::parameters::DIFFICULTY_WINDOW_V2; + const double_t adjust = pow(0.9989, 500 / N); + const double_t k = T * (N + 1) * adjust; + + if (timestamps.size() < 4) { + return 1; + } + // use a smaller N if timestamps and difficulies vectors are less than N+1 + if (timestamps.size() < N + 1) { + N = timestamps.size() - 1; + } + if (timestamps.size() > N + 1) { + timestamps.resize(N + 1); + } + if (cumulativeDifficulties.size() > N + 1) { + cumulativeDifficulties.resize(N + 1); + } + + int64_t L(0); + uint64_t next_D; + + for (int64_t i = 1; i <= N; i++) { + L += std::max(-7 * T, std::min(7 * T, timestamps[i] - timestamps[i - 1])) * i; + } + if (L < 1) + L = 1; + + uint64_t low, high; + low = mul128(cumulativeDifficulties[N] - cumulativeDifficulties[0], static_cast(k), &high); + // blockchain error "Difficulty overhead" if this function returns zero + if (high != 0) { + return 0; + } + + next_D = low / L / 2; + + return next_D; + + } + else { + + assert(m_difficultyWindow >= 2); + + if (timestamps.size() > m_difficultyWindow) { + timestamps.resize(m_difficultyWindow); + cumulativeDifficulties.resize(m_difficultyWindow); + } + + size_t length = timestamps.size(); + assert(length == cumulativeDifficulties.size()); + assert(length <= m_difficultyWindow); + if (length <= 1) { + return 1; + } + + sort(timestamps.begin(), timestamps.end()); + + size_t cutBegin, cutEnd; + assert(2 * m_difficultyCut <= m_difficultyWindow - 2); + if (length <= m_difficultyWindow - 2 * m_difficultyCut) { + cutBegin = 0; + cutEnd = length; + } + else { + cutBegin = (length - (m_difficultyWindow - 2 * m_difficultyCut) + 1) / 2; + cutEnd = cutBegin + (m_difficultyWindow - 2 * m_difficultyCut); + } + assert(/*cut_begin >= 0 &&*/ cutBegin + 2 <= cutEnd && cutEnd <= length); + uint64_t timeSpan = timestamps[cutEnd - 1] - timestamps[cutBegin]; + if (timeSpan == 0) { + timeSpan = 1; + } + + difficulty_type totalWork = cumulativeDifficulties[cutEnd - 1] - cumulativeDifficulties[cutBegin]; + assert(totalWork > 0); + + uint64_t low, high; + low = mul128(totalWork, m_difficultyTarget, &high); + if (high != 0 || low + timeSpan - 1 < low) { + return 0; + } + + return (low + timeSpan - 1) / timeSpan; + } } bool Currency::checkProofOfWork(Crypto::cn_context& context, const Block& block, difficulty_type currentDiffic, diff --git a/src/CryptoNoteCore/Currency.h b/src/CryptoNoteCore/Currency.h index ca34cb8..c46cb46 100644 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -48,6 +48,7 @@ class Currency { size_t difficultyLag() const { return m_difficultyLag; } size_t difficultyCut() const { return m_difficultyCut; } size_t difficultyBlocksCount() const { return m_difficultyWindow + m_difficultyLag; } + size_t difficultyBlocksCount2() const { return CryptoNote::parameters::DIFFICULTY_WINDOW_V2; } uint64_t depositMinAmount() const { return m_depositMinAmount; } uint32_t depositMinTerm() const { return m_depositMinTerm; } @@ -117,7 +118,7 @@ class Currency { std::string formatAmount(int64_t amount) const; bool parseAmount(const std::string& str, uint64_t& amount) const; - difficulty_type nextDifficulty(std::vector timestamps, std::vector cumulativeDifficulties) const; + difficulty_type nextDifficulty(uint8_t blockMajorVersion, std::vector timestamps, std::vector cumulativeDifficulties) const; bool checkProofOfWork(Crypto::cn_context& context, const Block& block, difficulty_type currentDiffic, Crypto::Hash& proofOfWork) const; size_t getApproximateMaximumInputCount(size_t transactionSize, size_t outputCount, size_t mixinCount) const; diff --git a/tests/CoreTests/BlockValidation.cpp b/tests/CoreTests/BlockValidation.cpp index c02e72d..4bc5094 100644 --- a/tests/CoreTests/BlockValidation.cpp +++ b/tests/CoreTests/BlockValidation.cpp @@ -26,7 +26,7 @@ namespace { CryptoNote::Block blk_prev = blk_last; for (size_t i = 0; i < new_block_count; ++i) { CryptoNote::Block blk_next; - CryptoNote::difficulty_type diffic = currency.nextDifficulty(timestamps, cummulative_difficulties); + CryptoNote::difficulty_type diffic = currency.nextDifficulty(block_major_version, timestamps, cummulative_difficulties); if (!generator.constructBlockManually(blk_next, blk_prev, miner_account, test_generator::bf_major_ver | test_generator::bf_timestamp | test_generator::bf_diffic, block_major_version, 0, blk_prev.timestamp, Crypto::Hash(), diffic)) { @@ -190,7 +190,7 @@ bool gen_block_invalid_nonce::generate(std::vector& events) co } // Create invalid nonce - difficulty_type diffic = m_currency.nextDifficulty(timestamps, commulative_difficulties); + difficulty_type diffic = m_currency.nextDifficulty(m_blockMajorVersion, timestamps, commulative_difficulties); assert(1 < diffic); const Block& blk_last = boost::get(events.back()); uint64_t timestamp = blk_last.timestamp; @@ -616,7 +616,7 @@ bool gen_block_invalid_binary_format::generate(std::vector& ev do { blk_last = boost::get(events.back()); - diffic = m_currency.nextDifficulty(timestamps, cummulative_difficulties); + diffic = m_currency.nextDifficulty(m_blockMajorVersion, timestamps, cummulative_difficulties); if (!lift_up_difficulty(m_currency, events, timestamps, cummulative_difficulties, generator, 1, blk_last, miner_account, m_blockMajorVersion)) { return false; @@ -633,7 +633,7 @@ bool gen_block_invalid_binary_format::generate(std::vector& ev std::vector tx_hashes; tx_hashes.push_back(getObjectHash(tx_0)); size_t txs_size = getObjectBinarySize(tx_0); - diffic = m_currency.nextDifficulty(timestamps, cummulative_difficulties); + diffic = m_currency.nextDifficulty(m_blockMajorVersion, timestamps, cummulative_difficulties); if (!generator.constructBlockManually(blk_test, blk_last, miner_account, test_generator::bf_major_ver | test_generator::bf_diffic | test_generator::bf_timestamp | test_generator::bf_tx_hashes, m_blockMajorVersion, 0, blk_last.timestamp, Crypto::Hash(), diffic, Transaction(), tx_hashes, txs_size)) diff --git a/tests/Difficulty/Difficulty.cpp b/tests/Difficulty/Difficulty.cpp index a54efe1..982a8bc 100644 --- a/tests/Difficulty/Difficulty.cpp +++ b/tests/Difficulty/Difficulty.cpp @@ -45,6 +45,7 @@ int main(int argc, char *argv[]) { begin = end - currency.difficultyWindow(); } uint64_t res = currency.nextDifficulty( + CryptoNote::BLOCK_MAJOR_VERSION_1, vector(timestamps.begin() + begin, timestamps.begin() + end), vector(cumulative_difficulties.begin() + begin, cumulative_difficulties.begin() + end)); if (res != difficulty) { From 637c6917fdf7b8fa41e5a1c87fb4ab256758bdb8 Mon Sep 17 00:00:00 2001 From: aivve Date: Sat, 21 Apr 2018 23:01:45 +0300 Subject: [PATCH 05/26] PoW CryptoNight v1 --- src/CryptoNoteCore/Blockchain.cpp | 2 +- src/CryptoNoteCore/CryptoNoteFormatUtils.cpp | 3 +- src/crypto/hash-ops.h | 2 +- src/crypto/hash.h | 6 +-- src/crypto/slow-hash.c | 6 +-- src/crypto/slow-hash.inl | 55 +++++++++++++++++++- 6 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index d5b420e..8d622c4 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -1806,7 +1806,7 @@ bool Blockchain::pushBlock(const Block& blockData, const std::vector= 3 ? 1 : 0; + cn_slow_hash(context, bd.data(), bd.size(), res, cn_variant); return true; } diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h index df3a89c..432a138 100644 --- a/src/crypto/hash-ops.h +++ b/src/crypto/hash-ops.h @@ -53,7 +53,7 @@ enum { void cn_fast_hash(const void *data, size_t length, char *hash); -void cn_slow_hash_f(void *, const void *, size_t, void *); +void cn_slow_hash_f(void *, const void *, size_t, void *, int); void hash_extra_blake(const void *data, size_t length, char *hash); void hash_extra_groestl(const void *data, size_t length, char *hash); diff --git a/src/crypto/hash.h b/src/crypto/hash.h index d8a6a65..e51c2e8 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -43,11 +43,11 @@ namespace Crypto { private: void *data; - friend inline void cn_slow_hash(cn_context &, const void *, size_t, Hash &); + friend inline void cn_slow_hash(cn_context &, const void *, size_t, Hash &, int); }; - inline void cn_slow_hash(cn_context &context, const void *data, size_t length, Hash &hash) { - (*cn_slow_hash_f)(context.data, data, length, reinterpret_cast(&hash)); + inline void cn_slow_hash(cn_context &context, const void *data, size_t length, Hash &hash, int variant = 0) { + (*cn_slow_hash_f)(context.data, data, length, reinterpret_cast(&hash), variant); } inline void tree_hash(const Hash *hashes, size_t count, Hash &root_hash) { diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 7d09004..d694c15 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -22,10 +22,10 @@ #include "hash-ops.h" #include "oaes_lib.h" -void (*cn_slow_hash_fp)(void *, const void *, size_t, void *); +void(*cn_slow_hash_fp)(void *, const void *, size_t, void *, int); -void cn_slow_hash_f(void * a, const void * b, size_t c, void * d){ -(*cn_slow_hash_fp)(a, b, c, d); +void cn_slow_hash_f(void * a, const void * b, size_t c, void * d, int v){ + (*cn_slow_hash_fp)(a, b, c, d, v); } #if defined(__GNUC__) diff --git a/src/crypto/slow-hash.inl b/src/crypto/slow-hash.inl index f29d17a..21f23e9 100644 --- a/src/crypto/slow-hash.inl +++ b/src/crypto/slow-hash.inl @@ -3,13 +3,63 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#if defined(WIN32) +#include +#else +#include +#endif + +#define xor64(a, b) *((uint64_t*)a) ^= b + +#define VARIANT1_1(p) \ + do if (variant > 0) \ + { \ + const uint8_t tmp = ((const uint8_t*)(p))[11]; \ + static const uint32_t table = 0x75310; \ + const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ + ((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \ + } while(0); + +#define VARIANT1_2(p) \ + do if (variant > 0) \ + { \ + xor64(p, tweak1_2); \ + } while(0); + +#define VARIANT1_CHECK() \ + do if (length < 43) \ + { \ + fprintf(stderr, "Cryptonight variants need at least 43 bytes of data. Exiting."); \ + _exit(1); \ + } while(0); + +#define NONCE_POINTER (((const uint8_t*)data)+35) + +#define VARIANT1_PORTABLE_INIT() \ + uint8_t tweak1_2[8]; \ + do if (variant > 0) \ + { \ + VARIANT1_CHECK(); \ + memcpy(&tweak1_2, &state.hs.b[192], sizeof(tweak1_2)); \ + xor64(tweak1_2, NONCE_POINTER); \ + } while(0) + +#define VARIANT1_INIT64() \ + if (variant > 0) \ + { \ + VARIANT1_CHECK(); \ + } \ + const uint64_t tweak1_2 = variant > 0 ? (ctx->state.hs.w[24] ^ (*((const uint64_t*)NONCE_POINTER))) : 0 + + static void #if defined(AESNI) cn_slow_hash_aesni #else cn_slow_hash_noaesni #endif -(void *restrict context, const void *restrict data, size_t length, void *restrict hash) +(void *restrict context, const void *restrict data, size_t length, void *restrict hash, int variant) { #define ctx ((struct cn_ctx *) context) ALIGNED_DECL(uint8_t ExpandedKey[256], 16); @@ -19,6 +69,9 @@ cn_slow_hash_noaesni hash_process(&ctx->state.hs, (const uint8_t*) data, length); memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + + VARIANT1_INIT64(); + #if defined(AESNI) memcpy(ExpandedKey, ctx->state.hs.b, AES_KEY_SIZE); ExpandAESKey256(ExpandedKey); From 1032eb8cfaecc0caa54f10f586f786a9ac84eca5 Mon Sep 17 00:00:00 2001 From: aivve Date: Sun, 22 Apr 2018 02:47:52 +0300 Subject: [PATCH 06/26] Block upgrade and pow fixes --- src/CryptoNoteCore/Core.cpp | 4 +-- src/CryptoNoteCore/CryptoNoteFormatUtils.cpp | 3 +-- .../CryptoNoteSerialization.cpp | 2 +- src/CryptoNoteCore/Currency.cpp | 2 +- src/crypto/slow-hash.inl | 25 ++++++++----------- 5 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index 5065410..f5ad093 100644 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -316,14 +316,14 @@ bool core::get_block_template(Block& b, const AccountPublicAddress& adr, difficu b = boost::value_initialized(); b.majorVersion = m_blockchain.get_block_major_version_for_height(height); - if (b.majorVersion < BLOCK_MAJOR_VERSION_3) { + if (b.majorVersion < BLOCK_MAJOR_VERSION_3) { if (b.majorVersion == BLOCK_MAJOR_VERSION_1) { b.minorVersion = m_currency.upgradeHeight(BLOCK_MAJOR_VERSION_2) == UpgradeDetectorBase::UNDEF_HEIGHT ? BLOCK_MINOR_VERSION_1 : BLOCK_MINOR_VERSION_0; } else { b.minorVersion = m_currency.upgradeHeight(BLOCK_MAJOR_VERSION_3) == UpgradeDetectorBase::UNDEF_HEIGHT ? BLOCK_MINOR_VERSION_1 : BLOCK_MINOR_VERSION_0; } } else { - b.minorVersion = BLOCK_MINOR_VERSION_0; + b.minorVersion = BLOCK_MINOR_VERSION_0; } b.previousBlockHash = get_tail_id(); diff --git a/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp b/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp index cd33cf3..8bc6fd3 100644 --- a/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp +++ b/src/CryptoNoteCore/CryptoNoteFormatUtils.cpp @@ -484,8 +484,7 @@ bool get_block_longhash(cn_context &context, const Block& b, Hash& res) { return false; } - const int cn_variant = b.majorVersion >= 3 ? 1 : 0; - cn_slow_hash(context, bd.data(), bd.size(), res, cn_variant); + cn_slow_hash(context, bd.data(), bd.size(), res, b.majorVersion >= 3 ? 1 : 0); return true; } diff --git a/src/CryptoNoteCore/CryptoNoteSerialization.cpp b/src/CryptoNoteCore/CryptoNoteSerialization.cpp index a27a6c8..4334e53 100644 --- a/src/CryptoNoteCore/CryptoNoteSerialization.cpp +++ b/src/CryptoNoteCore/CryptoNoteSerialization.cpp @@ -296,7 +296,7 @@ void serialize(MultisignatureOutput& multisignature, ISerializer& serializer) { void serializeBlockHeader(BlockHeader& header, ISerializer& serializer) { serializer(header.majorVersion, "major_version"); - if (header.majorVersion > BLOCK_MAJOR_VERSION_2) { + if (header.majorVersion > BLOCK_MAJOR_VERSION_3) { throw std::runtime_error("Wrong major version"); } diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 432b3a0..fffc4d8 100644 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -61,7 +61,7 @@ bool Currency::init() { if (isTestnet()) { m_upgradeHeightV2 = 0; - m_upgradeHeightV3 = static_cast(-1); + m_upgradeHeightV3 = 11; m_blocksFileName = "testnet_" + m_blocksFileName; m_blocksCacheFileName = "testnet_" + m_blocksCacheFileName; m_blockIndexesFileName = "testnet_" + m_blockIndexesFileName; diff --git a/src/crypto/slow-hash.inl b/src/crypto/slow-hash.inl index 21f23e9..118d4a3 100644 --- a/src/crypto/slow-hash.inl +++ b/src/crypto/slow-hash.inl @@ -19,32 +19,23 @@ static const uint32_t table = 0x75310; \ const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ ((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \ - } while(0); + } while(0) #define VARIANT1_2(p) \ do if (variant > 0) \ { \ xor64(p, tweak1_2); \ - } while(0); + } while(0) #define VARIANT1_CHECK() \ do if (length < 43) \ { \ - fprintf(stderr, "Cryptonight variants need at least 43 bytes of data. Exiting."); \ - _exit(1); \ - } while(0); + printf("Cryptonight variants need at least 43 bytes of data"); \ + exit(1); \ + } while(0) #define NONCE_POINTER (((const uint8_t*)data)+35) -#define VARIANT1_PORTABLE_INIT() \ - uint8_t tweak1_2[8]; \ - do if (variant > 0) \ - { \ - VARIANT1_CHECK(); \ - memcpy(&tweak1_2, &state.hs.b[192], sizeof(tweak1_2)); \ - xor64(tweak1_2, NONCE_POINTER); \ - } while(0) - #define VARIANT1_INIT64() \ if (variant > 0) \ { \ @@ -52,7 +43,6 @@ } \ const uint64_t tweak1_2 = variant > 0 ? (ctx->state.hs.w[24] ^ (*((const uint64_t*)NONCE_POINTER))) : 0 - static void #if defined(AESNI) cn_slow_hash_aesni @@ -152,6 +142,8 @@ cn_slow_hash_noaesni b_x = _mm_xor_si128(b_x, c_x); _mm_store_si128((__m128i *)&ctx->long_state[a[0] & 0x1FFFF0], b_x); + VARIANT1_1(&ctx->long_state[a[0] & 0x1FFFF0]); + nextblock = (uint64_t *)&ctx->long_state[c[0] & 0x1FFFF0]; b[0] = nextblock[0]; b[1] = nextblock[1]; @@ -180,6 +172,9 @@ cn_slow_hash_noaesni a[0] ^= b[0]; a[1] ^= b[1]; + + VARIANT1_2(dst + 1); + b_x = c_x; //__builtin_prefetch(&ctx->long_state[a[0] & 0x1FFFF0], 0, 3); } From cc8335575f307b36b3b4f8e4e4e1d6de0a8006c7 Mon Sep 17 00:00:00 2001 From: aivve Date: Sun, 22 Apr 2018 16:40:55 +0300 Subject: [PATCH 07/26] Additional RPC methods --- src/CryptoNoteCore/CryptoNoteTools.cpp | 13 +++ src/CryptoNoteCore/CryptoNoteTools.h | 1 + src/CryptoNoteCore/TransactionPool.cpp | 4 +- src/CryptoNoteCore/TransactionPool.h | 2 +- src/Rpc/CoreRpcServerCommandsDefinitions.h | 130 ++++++++------------- src/Rpc/RpcServer.cpp | 119 ++++++++++++++++++- src/Rpc/RpcServer.h | 8 ++ 7 files changed, 189 insertions(+), 88 deletions(-) diff --git a/src/CryptoNoteCore/CryptoNoteTools.cpp b/src/CryptoNoteCore/CryptoNoteTools.cpp index 3f0319f..1adf492 100644 --- a/src/CryptoNoteCore/CryptoNoteTools.cpp +++ b/src/CryptoNoteCore/CryptoNoteTools.cpp @@ -31,6 +31,19 @@ Crypto::Hash getBinaryArrayHash(const BinaryArray& binaryArray) { return hash; } +uint64_t getInputAmount(const Transaction& transaction) { + uint64_t amount = 0; + for (auto& input : transaction.inputs) { + if (input.type() == typeid(KeyInput)) { + amount += boost::get(input).amount; + } else if (input.type() == typeid(MultisignatureInput)) { + amount += boost::get(input).amount; + } + } + + return amount; +} + std::vector getInputsAmounts(const Transaction& transaction) { std::vector inputsAmounts; inputsAmounts.reserve(transaction.inputs.size()); diff --git a/src/CryptoNoteCore/CryptoNoteTools.h b/src/CryptoNoteCore/CryptoNoteTools.h index 12687a3..e867099 100644 --- a/src/CryptoNoteCore/CryptoNoteTools.h +++ b/src/CryptoNoteCore/CryptoNoteTools.h @@ -107,6 +107,7 @@ Crypto::Hash getObjectHash(const T& object) { return hash; } +uint64_t getInputAmount(const Transaction& transaction); std::vector getInputsAmounts(const Transaction& transaction); uint64_t getOutputAmount(const Transaction& transaction); void decomposeAmount(uint64_t amount, uint64_t dustThreshold, std::vector& decomposedAmounts); diff --git a/src/CryptoNoteCore/TransactionPool.cpp b/src/CryptoNoteCore/TransactionPool.cpp index 4fa880c..4df293e 100644 --- a/src/CryptoNoteCore/TransactionPool.cpp +++ b/src/CryptoNoteCore/TransactionPool.cpp @@ -97,7 +97,9 @@ namespace CryptoNote { m_timeProvider(timeProvider), m_txCheckInterval(60, timeProvider), m_fee_index(boost::get<1>(m_transactions)), - logger(log, "txpool") { + logger(log, "txpool"), + m_paymentIdIndex(), + m_timestampIndex() { } //--------------------------------------------------------------------------------- bool tx_memory_pool::add_tx(const Transaction &tx, /*const Crypto::Hash& tx_prefix_hash,*/ const Crypto::Hash &id, size_t blobSize, tx_verification_context& tvc, bool keptByBlock) { diff --git a/src/CryptoNoteCore/TransactionPool.h b/src/CryptoNoteCore/TransactionPool.h index 35a097b..966e948 100644 --- a/src/CryptoNoteCore/TransactionPool.h +++ b/src/CryptoNoteCore/TransactionPool.h @@ -75,7 +75,7 @@ namespace CryptoNote { const CryptoNote::Currency& currency, CryptoNote::ITransactionValidator& validator, CryptoNote::ITimeProvider& timeProvider, - Logging::ILogger& log); + Logging::ILogger& log); bool addObserver(ITxPoolObserver* observer); bool removeObserver(ITxPoolObserver* observer); diff --git a/src/Rpc/CoreRpcServerCommandsDefinitions.h b/src/Rpc/CoreRpcServerCommandsDefinitions.h index df3be15..7392923 100644 --- a/src/Rpc/CoreRpcServerCommandsDefinitions.h +++ b/src/Rpc/CoreRpcServerCommandsDefinitions.h @@ -256,6 +256,7 @@ struct COMMAND_RPC_GET_INFO { struct response { std::string status; + std::string version; uint64_t height; uint64_t difficulty; uint64_t tx_count; @@ -271,6 +272,7 @@ struct COMMAND_RPC_GET_INFO { void serialize(ISerializer &s) { KV_MEMBER(status) + KV_MEMBER(version) KV_MEMBER(height) KV_MEMBER(difficulty) KV_MEMBER(tx_count) @@ -299,7 +301,21 @@ struct COMMAND_RPC_STOP_DAEMON { typedef STATUS_STRUCT response; }; -// +//----------------------------------------------- +struct COMMAND_RPC_GET_PEER_LIST { + typedef EMPTY_STRUCT request; + + struct response { + std::vector peers; + std::string status; + + void serialize(ISerializer &s) { + KV_MEMBER(peers) + KV_MEMBER(status) + } + }; +}; + struct COMMAND_RPC_GETBLOCKCOUNT { typedef std::vector request; @@ -441,6 +457,7 @@ struct f_block_short_response { std::string hash; uint64_t tx_count; uint64_t cumul_size; + difficulty_type difficulty; void serialize(ISerializer &s) { KV_MEMBER(timestamp) @@ -448,6 +465,7 @@ struct f_block_short_response { KV_MEMBER(hash) KV_MEMBER(cumul_size) KV_MEMBER(tx_count) + KV_MEMBER(difficulty) } }; @@ -498,71 +516,6 @@ struct f_block_details_response { KV_MEMBER(totalFeeAmount) } }; -struct currency_base_coin { - std::string name; - std::string git; - - void serialize(ISerializer &s) { - KV_MEMBER(name) - KV_MEMBER(git) - } -}; - -struct currency_core { - std::vector SEED_NODES; - uint64_t EMISSION_SPEED_FACTOR; - uint64_t DIFFICULTY_TARGET; - uint64_t CRYPTONOTE_DISPLAY_DECIMAL_POINT; - std::string MONEY_SUPPLY; -//uint64_t GENESIS_BLOCK_REWARD; - uint64_t DEFAULT_DUST_THRESHOLD; - uint64_t MINIMUM_FEE; - uint64_t CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; - uint64_t CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE; -// uint64_t CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1; - uint64_t CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX; - uint64_t P2P_DEFAULT_PORT; - uint64_t RPC_DEFAULT_PORT; - uint64_t MAX_BLOCK_SIZE_INITIAL; - uint64_t EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; - uint64_t UPGRADE_HEIGHT; - uint64_t DIFFICULTY_CUT; - uint64_t DIFFICULTY_LAG; - //std::string BYTECOIN_NETWORK; - std::string CRYPTONOTE_NAME; - std::string GENESIS_COINBASE_TX_HEX; - std::vector CHECKPOINTS; - - void serialize(ISerializer &s) { - KV_MEMBER(SEED_NODES) - KV_MEMBER(EMISSION_SPEED_FACTOR) - KV_MEMBER(DIFFICULTY_TARGET) - KV_MEMBER(CRYPTONOTE_DISPLAY_DECIMAL_POINT) - KV_MEMBER(MONEY_SUPPLY) -// KV_MEMBER(GENESIS_BLOCK_REWARD) - KV_MEMBER(DEFAULT_DUST_THRESHOLD) - KV_MEMBER(MINIMUM_FEE) - KV_MEMBER(CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW) - KV_MEMBER(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) -// KV_MEMBER(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1) - KV_MEMBER(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX) - KV_MEMBER(P2P_DEFAULT_PORT) - KV_MEMBER(RPC_DEFAULT_PORT) - KV_MEMBER(MAX_BLOCK_SIZE_INITIAL) - KV_MEMBER(EXPECTED_NUMBER_OF_BLOCKS_PER_DAY) - KV_MEMBER(UPGRADE_HEIGHT) - KV_MEMBER(DIFFICULTY_CUT) - KV_MEMBER(DIFFICULTY_LAG) -// KV_MEMBER(BYTECOIN_NETWORK) - KV_MEMBER(CRYPTONOTE_NAME) - KV_MEMBER(GENESIS_COINBASE_TX_HEX) - KV_MEMBER(CHECKPOINTS) - } -}; - - - - struct COMMAND_RPC_GET_LAST_BLOCK_HEADER { typedef EMPTY_STRUCT request; @@ -658,24 +611,41 @@ struct F_COMMAND_RPC_GET_TRANSACTION_DETAILS { } }; }; -struct F_COMMAND_RPC_GET_BLOCKCHAIN_SETTINGS { - typedef EMPTY_STRUCT request; - struct response { - currency_base_coin base_coin; - currency_core core; - std::vector extensions; - std::string status; - void serialize(ISerializer &s) { - KV_MEMBER(base_coin) - KV_MEMBER(core) - KV_MEMBER(extensions) - KV_MEMBER(status) - } - }; +//----------------------------------------------- +struct K_COMMAND_RPC_GET_TRANSACTIONS_BY_PAYMENT_ID { + struct request { + std::string payment_id; + + void serialize(ISerializer &s) { + KV_MEMBER(payment_id) + } + }; + + struct response { + std::vector transactions; + std::string status; + + void serialize(ISerializer &s) { + KV_MEMBER(transactions) + KV_MEMBER(status) + } + }; }; +struct F_COMMAND_RPC_GET_POOL { + typedef EMPTY_STRUCT request; + struct response { + std::vector transactions; + std::string status; + + void serialize(ISerializer &s) { + KV_MEMBER(transactions) + KV_MEMBER(status) + } + }; +}; struct COMMAND_RPC_QUERY_BLOCKS { struct request { diff --git a/src/Rpc/RpcServer.cpp b/src/Rpc/RpcServer.cpp index 9e8f56a..2c9b012 100644 --- a/src/Rpc/RpcServer.cpp +++ b/src/Rpc/RpcServer.cpp @@ -1,9 +1,11 @@ // Copyright (c) 2011-2016 The Cryptonote developers // Copyright (c) 2014-2016 SDN developers +// Copyright (c) 2016 - 2018, The Karbo developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "RpcServer.h" +#include "version.h" #include #include @@ -11,6 +13,7 @@ // CryptoNote #include "Common/StringTools.h" #include "CryptoNoteCore/CryptoNoteTools.h" +#include "CryptoNoteCore/CryptoNoteFormatUtils.h" #include "CryptoNoteCore/Core.h" #include "CryptoNoteCore/IBlock.h" #include "CryptoNoteCore/Miner.h" @@ -88,6 +91,7 @@ std::unordered_map(&RpcServer::on_start_mining), false } }, { "/stop_mining", { jsonMethod(&RpcServer::on_stop_mining), false } }, { "/stop_daemon", { jsonMethod(&RpcServer::on_stop_daemon), true } }, + { "/peers", { jsonMethod(&RpcServer::on_get_peer_list), true } }, // json rpc { "/json_rpc", { std::bind(&RpcServer::processJsonRpcRequest, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), true } } @@ -120,6 +124,9 @@ bool RpcServer::processJsonRpcRequest(const HttpRequest& request, HttpResponse& using namespace JsonRpc; response.addHeader("Content-Type", "application/json"); + if (!m_cors_domain.empty()) { + response.addHeader("Access-Control-Allow-Origin", m_cors_domain); + } JsonRpcRequest jsonRequest; JsonRpcResponse jsonResponse; @@ -133,7 +140,6 @@ bool RpcServer::processJsonRpcRequest(const HttpRequest& request, HttpResponse& { "f_blocks_list_json", { makeMemberMethod(&RpcServer::f_on_blocks_list_json), false } }, { "f_block_json", { makeMemberMethod(&RpcServer::f_on_block_json), false } }, { "f_transaction_json", { makeMemberMethod(&RpcServer::f_on_transaction_json), false } }, - // { "f_get_blockchain_settings", { makeMemberMethod(&RpcServer::f_on_get_blockchain_settings), true } }, { "getblockcount", { makeMemberMethod(&RpcServer::on_getblockcount), true } }, { "on_getblockhash", { makeMemberMethod(&RpcServer::on_getblockhash), false } }, { "getblocktemplate", { makeMemberMethod(&RpcServer::on_getblocktemplate), false } }, @@ -141,7 +147,9 @@ bool RpcServer::processJsonRpcRequest(const HttpRequest& request, HttpResponse& { "submitblock", { makeMemberMethod(&RpcServer::on_submitblock), false } }, { "getlastblockheader", { makeMemberMethod(&RpcServer::on_get_last_block_header), false } }, { "getblockheaderbyhash", { makeMemberMethod(&RpcServer::on_get_block_header_by_hash), false } }, - { "getblockheaderbyheight", { makeMemberMethod(&RpcServer::on_get_block_header_by_height), false } } + { "getblockheaderbyheight", { makeMemberMethod(&RpcServer::on_get_block_header_by_height), false } }, + { "f_pool_json", { makeMemberMethod(&RpcServer::f_on_pool_json), false } }, + { "k_transactions_by_payment_id", { makeMemberMethod(&RpcServer::k_on_transactions_by_payment_id), false } } }; auto it = jsonRpcHandlers.find(jsonRequest.getMethod()); @@ -166,6 +174,16 @@ bool RpcServer::processJsonRpcRequest(const HttpRequest& request, HttpResponse& return true; } +bool RpcServer::restrictRPC(const bool is_restricted) { + m_restricted_rpc = is_restricted; + return true; +} + +bool RpcServer::enableCors(const std::string domain) { + m_cors_domain = domain; + return true; +} + bool RpcServer::isCoreReady() { return m_core.currency().isTestnet() || m_p2p.get_payload_object().isSynchronized(); } @@ -328,6 +346,7 @@ bool RpcServer::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RP res.last_known_block_index = std::max(static_cast(1), m_protocolQuery.getObservedHeight()) - 1; res.full_deposit_amount = m_core.fullDepositAmount(); res.full_deposit_interest = m_core.fullDepositInterest(); + res.version = PROJECT_VERSION_LONG; res.status = CORE_RPC_STATUS_OK; return true; } @@ -410,6 +429,10 @@ bool RpcServer::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMM } bool RpcServer::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res) { + if (m_restricted_rpc) { + res.status = "Failed, restricted handle"; + return false; + } AccountPublicAddress adr; if (!m_core.currency().parseAccountAddressString(req.miner_address, adr)) { res.status = "Failed, wrong address"; @@ -426,6 +449,10 @@ bool RpcServer::on_start_mining(const COMMAND_RPC_START_MINING::request& req, CO } bool RpcServer::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res) { + if (m_restricted_rpc) { + res.status = "Failed, restricted handle"; + return false; + } if (!m_core.get_miner().stop()) { res.status = "Failed, mining not stopped"; return true; @@ -435,6 +462,10 @@ bool RpcServer::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMM } bool RpcServer::on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res) { + if (m_restricted_rpc) { + res.status = "Failed, restricted handle"; + return false; + } if (m_core.currency().isTestnet()) { m_p2p.sendStopSignal(); res.status = CORE_RPC_STATUS_OK; @@ -445,6 +476,19 @@ bool RpcServer::on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMM return true; } +bool RpcServer::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res) { + std::list pl_wite; + std::list pl_gray; + m_p2p.getPeerlistManager().get_peerlist_full(pl_gray, pl_wite); + for (const auto& pe : pl_wite) { + std::stringstream ss; + ss << pe.adr; + res.peers.push_back(ss.str()); + } + res.status = CORE_RPC_STATUS_OK; + return true; +} + //------------------------------------------------------------------------------------------------------------------------------ // JSON RPC methods //------------------------------------------------------------------------------------------------------------------------------ @@ -472,6 +516,8 @@ bool RpcServer::f_on_blocks_list_json(const F_COMMAND_RPC_GET_BLOCKS_LIST::reque m_core.getBlockSize(block_hash, tx_cumulative_block_size); size_t blokBlobSize = getObjectBinarySize(blk); size_t minerTxBlobSize = getObjectBinarySize(blk.baseTransaction); + difficulty_type blockDiff; + m_core.getBlockDifficulty(static_cast(i), blockDiff); f_block_short_response block_short; block_short.cumul_size = blokBlobSize + tx_cumulative_block_size - minerTxBlobSize; @@ -480,6 +526,7 @@ bool RpcServer::f_on_blocks_list_json(const F_COMMAND_RPC_GET_BLOCKS_LIST::reque block_short.hash = Common::podToHex(block_hash); block_short.cumul_size = blokBlobSize + tx_cumulative_block_size - minerTxBlobSize; block_short.tx_count = blk.transactionHashes.size() + 1; + block_short.difficulty = blockDiff; res.blocks.push_back(block_short); @@ -494,10 +541,15 @@ bool RpcServer::f_on_blocks_list_json(const F_COMMAND_RPC_GET_BLOCKS_LIST::reque bool RpcServer::f_on_block_json(const F_COMMAND_RPC_GET_BLOCK_DETAILS::request& req, F_COMMAND_RPC_GET_BLOCK_DETAILS::response& res) { Hash hash; - if (!parse_hash256(req.hash, hash)) { - throw JsonRpc::JsonRpcError{ - CORE_RPC_ERROR_CODE_WRONG_PARAM, - "Failed to parse hex representation of block hash. Hex = " + req.hash + '.' }; + try { + uint32_t height = boost::lexical_cast(req.hash); + hash = m_core.getBlockIdByHeight(height); + } catch (boost::bad_lexical_cast &) { + if (!parse_hash256(req.hash, hash)) { + throw JsonRpc::JsonRpcError{ + CORE_RPC_ERROR_CODE_WRONG_PARAM, + "Failed to parse hex representation of block hash. Hex = " + req.hash + '.' }; + } } Block blk; @@ -703,6 +755,24 @@ bool RpcServer::f_on_transaction_json(const F_COMMAND_RPC_GET_TRANSACTION_DETAIL return true; } +bool RpcServer::f_on_pool_json(const F_COMMAND_RPC_GET_POOL::request& req, F_COMMAND_RPC_GET_POOL::response& res) { + auto pool = m_core.getPoolTransactions(); + for (const Transaction tx : pool) { + f_transaction_short_response transaction_short; + + uint64_t amount_in = getInputAmount(tx); + uint64_t amount_out = getOutputAmount(tx); + + transaction_short.hash = Common::podToHex(getObjectHash(tx)); + transaction_short.fee = amount_in < amount_out + parameters::MINIMUM_FEE ? parameters::MINIMUM_FEE : amount_in - amount_out; + transaction_short.amount_out = amount_out; + transaction_short.size = getObjectBinarySize(tx); + res.transactions.push_back(transaction_short); + } + res.status = CORE_RPC_STATUS_OK; + return true; +} + bool RpcServer::f_getMixin(const Transaction& transaction, uint64_t& mixin) { mixin = 0; for (const TransactionInput& txin : transaction.inputs) { @@ -717,6 +787,43 @@ bool RpcServer::f_getMixin(const Transaction& transaction, uint64_t& mixin) { return true; } +bool RpcServer::k_on_transactions_by_payment_id(const K_COMMAND_RPC_GET_TRANSACTIONS_BY_PAYMENT_ID::request& req, K_COMMAND_RPC_GET_TRANSACTIONS_BY_PAYMENT_ID::response& res) { + if (!req.payment_id.size()) { + throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_WRONG_PARAM, "Wrong parameters, expected payment_id" }; + } + logger(Logging::INFO, Logging::WHITE) << "RPC request came: Search by Payment ID: " << req.payment_id; + + Crypto::Hash paymentId; + std::vector transactions; + + if (!parse_hash256(req.payment_id, paymentId)) { + throw JsonRpc::JsonRpcError{ + CORE_RPC_ERROR_CODE_WRONG_PARAM, + "Failed to parse Payment ID: " + req.payment_id + '.' }; + } + + if (!m_core.getTransactionsByPaymentId(paymentId, transactions)) { + throw JsonRpc::JsonRpcError{ + CORE_RPC_ERROR_CODE_INTERNAL_ERROR, + "Internal error: can't get transactions by Payment ID: " + req.payment_id + '.' }; + } + + for (const Transaction& tx : transactions) { + f_transaction_short_response transaction_short; + uint64_t amount_in = 0; + get_inputs_money_amount(tx, amount_in); + uint64_t amount_out = get_outs_money_amount(tx); + + transaction_short.hash = Common::podToHex(getObjectHash(tx)); + transaction_short.fee = amount_in - amount_out; + transaction_short.amount_out = amount_out; + transaction_short.size = getObjectBinarySize(tx); + res.transactions.push_back(transaction_short); + } + + res.status = CORE_RPC_STATUS_OK; + return true; +} bool RpcServer::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res) { res.count = m_core.get_current_blockchain_height(); diff --git a/src/Rpc/RpcServer.h b/src/Rpc/RpcServer.h index 90d9bef..1b2a3e4 100644 --- a/src/Rpc/RpcServer.h +++ b/src/Rpc/RpcServer.h @@ -1,5 +1,6 @@ // Copyright (c) 2011-2016 The Cryptonote developers // Copyright (c) 2014-2016 SDN developers +// Copyright (c) 2016 - 2018, The Karbo developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,6 +24,8 @@ class RpcServer : public HttpServer { RpcServer(System::Dispatcher& dispatcher, Logging::ILogger& log, core& c, NodeServer& p2p, const ICryptoNoteProtocolQuery& protocolQuery); typedef std::function HandlerFunction; + bool enableCors(const std::string domain); + bool restrictRPC(const bool is_resctricted); private: @@ -56,6 +59,9 @@ class RpcServer : public HttpServer { bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res); bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res); bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res); + bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res); + bool f_on_pool_json(const F_COMMAND_RPC_GET_POOL::request& req, F_COMMAND_RPC_GET_POOL::response& res); + bool k_on_transactions_by_payment_id(const K_COMMAND_RPC_GET_TRANSACTIONS_BY_PAYMENT_ID::request& req, K_COMMAND_RPC_GET_TRANSACTIONS_BY_PAYMENT_ID::response& res); // json rpc bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res); @@ -79,6 +85,8 @@ class RpcServer : public HttpServer { core& m_core; NodeServer& m_p2p; const ICryptoNoteProtocolQuery& m_protocolQuery; + bool m_restricted_rpc; + std::string m_cors_domain; }; } From ca64a5fac9179662483b0712432906d049fff10c Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 15:48:20 +0000 Subject: [PATCH 08/26] Update CryptoNoteConfig.h Upgrade Height for Scheduled Fork ( #1 ) --- src/CryptoNoteConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index e86db5d..736bfa5 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -64,7 +64,7 @@ const size_t FUSION_TX_MIN_INPUT_COUNT = 12; const size_t FUSION_TX_MIN_IN_OUT_COUNT_RATIO = 4; const uint32_t UPGRADE_HEIGHT_V2 = 1; -const uint32_t UPGRADE_HEIGHT_V3 = 4294967294; +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 From cdd4128c37fc3aaf7b788ad4926d6f6e65cbb1c0 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 20:29:22 +0000 Subject: [PATCH 09/26] Update CryptoNoteConfig.h --- src/CryptoNoteConfig.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 736bfa5..969704b 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -121,7 +121,10 @@ const char P2P_STAT_TRUSTED_PUB_KEY[] = "85ae8734f90bc1ee const std::initializer_list SEED_NODES = { "seed0.bitcedi.org:55008", "seed1.bitcedi.org:55008", - "seed2.bitcedi.org:55008" + "seed2.bitcedi.org:55008", + "174.138.3.171:55008", + "185.183.99.19:55008", + "138.68.105.149:18080" }; struct CheckpointData { From 8ac83620e21117867c8531ca66261f72d920df29 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 21:04:03 +0000 Subject: [PATCH 10/26] fix --- src/Common/Base58.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Common/Base58.cpp b/src/Common/Base58.cpp index 127b0bf..041e602 100644 --- a/src/Common/Base58.cpp +++ b/src/Common/Base58.cpp @@ -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; From 79e77a3280038332b97c281d6eebf76082391225 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 21:18:58 +0000 Subject: [PATCH 11/26] void --- src/CryptoNoteCore/SwappedMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteCore/SwappedMap.h b/src/CryptoNoteCore/SwappedMap.h index 8e005f8..28aa2d6 100644 --- a/src/CryptoNoteCore/SwappedMap.h +++ b/src/CryptoNoteCore/SwappedMap.h @@ -183,7 +183,7 @@ template bool SwappedMap::open(const std::string& it } template void SwappedMap::close() { - std::cout << "SwappedMap cache hits: " << m_cacheHits << ", misses: " << m_cacheMisses << " (" << std::fixed << std::setprecision(2) << static_cast(m_cacheMisses) / (m_cacheHits + m_cacheMisses) * 100 << "%)" << std::endl; + //std::cout << "SwappedMap cache hits: " << m_cacheHits << ", misses: " << m_cacheMisses << " (" << std::fixed << std::setprecision(2) << static_cast(m_cacheMisses) / (m_cacheHits + m_cacheMisses) * 100 << "%)" << std::endl; } template uint64_t SwappedMap::size() const { From cc1ddcae2ff6c87cadb2978411b8a140c98b6e8b Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 22:26:03 +0000 Subject: [PATCH 12/26] Update CMakeLists.txt --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7a16967..770d327 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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/*) From 515c3842a4fa8a6323388c8c0393eb68604bd8c7 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 22:28:37 +0000 Subject: [PATCH 13/26] Connectivity_Tool removed from C --- src/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 770d327..97ac554 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,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}) @@ -50,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}) @@ -60,7 +59,7 @@ 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}) From 674825737018ad0787bdc67ffa0483f46611a92c Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 22:29:27 +0000 Subject: [PATCH 14/26] connectivity_tool removed from cmakelists.txt --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97ac554..9f0fc90 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,7 +73,6 @@ 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") From bc1e3280c3221be21af23cbbf872f5025e172312 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 22:31:09 +0000 Subject: [PATCH 15/26] ConnectivityTool removed from list --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9f0fc90..908cf2e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,7 +67,6 @@ target_link_libraries(Miner CryptoNoteCore Rpc Serialization System Http Logging add_dependencies(Rpc version) -add_dependencies(ConnectivityTool version) add_dependencies(Daemon version) add_dependencies(SimpleWallet version) add_dependencies(PaymentGateService version) From 521bbb1d161fc0e96e678370d475db5bb7faf662 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 22 Apr 2018 22:45:14 +0000 Subject: [PATCH 16/26] New seednode --- src/CryptoNoteConfig.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 969704b..ba17152 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -124,7 +124,8 @@ const std::initializer_list SEED_NODES = { "seed2.bitcedi.org:55008", "174.138.3.171:55008", "185.183.99.19:55008", - "138.68.105.149:18080" + "138.68.105.149:18080", + "172.104.240.101:55008" }; struct CheckpointData { From 296daa5c7b119b905452c8bd8eabb3a9d5814333 Mon Sep 17 00:00:00 2001 From: aivve Date: Mon, 23 Apr 2018 22:44:57 +0300 Subject: [PATCH 17/26] Fix signed unsigned conversion --- src/CryptoNoteCore/Currency.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index fffc4d8..3962cd1 100644 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -490,8 +490,8 @@ difficulty_type Currency::nextDifficulty(uint8_t blockMajorVersion, std::vector< int64_t L(0); uint64_t next_D; - for (int64_t i = 1; i <= N; i++) { - L += std::max(-7 * T, std::min(7 * T, timestamps[i] - timestamps[i - 1])) * i; + for (size_t i = 1; i <= N; i++) { + L += (int64_t)(std::max(-7 * T, std::min(7 * T, timestamps[i] - timestamps[i - 1])) * i); } if (L < 1) L = 1; From 7c05abba474a5702e05825da18d4a81323cbca6c Mon Sep 17 00:00:00 2001 From: aivve Date: Tue, 1 May 2018 15:47:02 +0300 Subject: [PATCH 18/26] Don't generate a block template with invalid timestamp https://github.com/graft-project/GraftNetwork/pull/118/commits --- src/CryptoNoteCore/Blockchain.cpp | 5 +++++ src/CryptoNoteCore/Blockchain.h | 1 + src/CryptoNoteCore/Core.cpp | 14 ++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index 8d622c4..2e57264 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -671,6 +671,11 @@ difficulty_type Blockchain::getDifficultyForNextBlock() { 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() { std::lock_guard lk(m_blockchain_lock); if (m_blocks.empty()) { diff --git a/src/CryptoNoteCore/Blockchain.h b/src/CryptoNoteCore/Blockchain.h index dbf39ad..b0f390f 100644 --- a/src/CryptoNoteCore/Blockchain.h +++ b/src/CryptoNoteCore/Blockchain.h @@ -78,6 +78,7 @@ namespace CryptoNote { Crypto::Hash getTailId(); Crypto::Hash getTailId(uint32_t& height); difficulty_type getDifficultyForNextBlock(); + uint64_t getBlockTimestamp(uint32_t height); uint64_t getCoinsInCirculation(); uint8_t get_block_major_version_for_height(uint64_t height) const; bool addNewBlock(const Block& bl_, block_verification_context& bvc); diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index f5ad093..d2d2f31 100644 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -10,6 +10,7 @@ #include "../CryptoNoteConfig.h" #include "../Common/CommandLine.h" #include "../Common/Util.h" +#include "../Common/Math.h" #include "../Common/StringTools.h" #include "../crypto/crypto.h" #include "../CryptoNoteProtocol/CryptoNoteProtocolDefinitions.h" @@ -329,6 +330,19 @@ bool core::get_block_template(Block& b, const AccountPublicAddress& adr, difficu b.previousBlockHash = get_tail_id(); b.timestamp = time(NULL); + // Don't generate a block template with invalid timestamp + // Fix by Jagerman - https://github.com/graft-project/GraftNetwork/pull/118/commits + if(height >= m_currency.timestampCheckWindow()) { + std::vector timestamps; + for(size_t offset = height - m_currency.timestampCheckWindow(); offset < height; ++offset) { + timestamps.push_back(m_blockchain.getBlockTimestamp(offset)); + } + uint64_t median_ts = Common::medianValue(timestamps); + if (b.timestamp < median_ts) { + b.timestamp = median_ts; + } + } + median_size = m_blockchain.getCurrentCumulativeBlocksizeLimit() / 2; already_generated_coins = m_blockchain.getCoinsInCirculation(); } From 7732855095cead8a9acc80361fcb14e59c8738ec Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Thu, 3 May 2018 05:43:24 +0000 Subject: [PATCH 19/26] Delete RpcServer - copy.cpp --- src/Rpc/RpcServer - copy.cpp | 651 ----------------------------------- 1 file changed, 651 deletions(-) delete mode 100644 src/Rpc/RpcServer - copy.cpp diff --git a/src/Rpc/RpcServer - copy.cpp b/src/Rpc/RpcServer - copy.cpp deleted file mode 100644 index 494c86f..0000000 --- a/src/Rpc/RpcServer - copy.cpp +++ /dev/null @@ -1,651 +0,0 @@ -// Copyright (c) 2011-2016 The Cryptonote developers -// Copyright (c) 2014-2016 SDN developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "RpcServer.h" - -#include -#include - -// CryptoNote -#include "Common/StringTools.h" -#include "CryptoNoteCore/CryptoNoteTools.h" -#include "CryptoNoteCore/Core.h" -#include "CryptoNoteCore/IBlock.h" -#include "CryptoNoteCore/Miner.h" -#include "CryptoNoteCore/TransactionExtra.h" - -#include "CryptoNoteProtocol/ICryptoNoteProtocolQuery.h" - -#include "P2p/NetNode.h" - -#include "CoreRpcServerErrorCodes.h" -#include "JsonRpc.h" - -#undef ERROR - -using namespace Logging; -using namespace Crypto; -using namespace Common; - -namespace CryptoNote { - -namespace { - -template -RpcServer::HandlerFunction binMethod(bool (RpcServer::*handler)(typename Command::request const&, typename Command::response&)) { - return [handler](RpcServer* obj, const HttpRequest& request, HttpResponse& response) { - - boost::value_initialized req; - boost::value_initialized res; - - if (!loadFromBinaryKeyValue(static_cast(req), request.getBody())) { - return false; - } - - bool result = (obj->*handler)(req, res); - response.setBody(storeToBinaryKeyValue(res.data())); - return result; - }; -} - -template -RpcServer::HandlerFunction jsonMethod(bool (RpcServer::*handler)(typename Command::request const&, typename Command::response&)) { - return [handler](RpcServer* obj, const HttpRequest& request, HttpResponse& response) { - - boost::value_initialized req; - boost::value_initialized res; - - if (!loadFromJson(static_cast(req), request.getBody())) { - return false; - } - - bool result = (obj->*handler)(req, res); - response.setBody(storeToJson(res.data())); - return result; - }; -} - -} - -std::unordered_map> RpcServer::s_handlers = { - - // binary handlers - { "/getblocks.bin", { binMethod(&RpcServer::on_get_blocks), false } }, - { "/queryblocks.bin", { binMethod(&RpcServer::on_query_blocks), false } }, - { "/queryblockslite.bin", { binMethod(&RpcServer::on_query_blocks_lite), false } }, - { "/get_o_indexes.bin", { binMethod(&RpcServer::on_get_indexes), false } }, - { "/getrandom_outs.bin", { binMethod(&RpcServer::on_get_random_outs), false } }, - { "/get_pool_changes.bin", { binMethod(&RpcServer::onGetPoolChanges), false } }, - { "/get_pool_changes_lite.bin", { binMethod(&RpcServer::onGetPoolChangesLite), false } }, - - // json handlers - { "/getinfo", { jsonMethod(&RpcServer::on_get_info), true } }, - { "/getheight", { jsonMethod(&RpcServer::on_get_height), true } }, - { "/gettransactions", { jsonMethod(&RpcServer::on_get_transactions), false } }, - { "/sendrawtransaction", { jsonMethod(&RpcServer::on_send_raw_tx), false } }, - { "/start_mining", { jsonMethod(&RpcServer::on_start_mining), false } }, - { "/stop_mining", { jsonMethod(&RpcServer::on_stop_mining), false } }, - { "/stop_daemon", { jsonMethod(&RpcServer::on_stop_daemon), true } }, - - // json rpc - { "/json_rpc", { std::bind(&RpcServer::processJsonRpcRequest, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), true } } -}; - -RpcServer::RpcServer(System::Dispatcher& dispatcher, Logging::ILogger& log, core& c, NodeServer& p2p, const ICryptoNoteProtocolQuery& protocolQuery) : - HttpServer(dispatcher, log), logger(log, "RpcServer"), m_core(c), m_p2p(p2p), m_protocolQuery(protocolQuery) { -} - -void RpcServer::processRequest(const HttpRequest& request, HttpResponse& response) { - auto url = request.getUrl(); - - auto it = s_handlers.find(url); - if (it == s_handlers.end()) { - response.setStatus(HttpResponse::STATUS_404); - return; - } - - if (!it->second.allowBusyCore && !isCoreReady()) { - response.setStatus(HttpResponse::STATUS_500); - response.setBody("Core is busy"); - return; - } - - it->second.handler(this, request, response); -} - -bool RpcServer::processJsonRpcRequest(const HttpRequest& request, HttpResponse& response) { - - using namespace JsonRpc; - - response.addHeader("Content-Type", "application/json"); - - JsonRpcRequest jsonRequest; - JsonRpcResponse jsonResponse; - - try { - logger(TRACE) << "JSON-RPC request: " << request.getBody(); - jsonRequest.parseRequest(request.getBody()); - jsonResponse.setId(jsonRequest.getId()); // copy id - - static std::unordered_map> jsonRpcHandlers = { - { "getblockcount", { makeMemberMethod(&RpcServer::on_getblockcount), true } }, - { "on_getblockhash", { makeMemberMethod(&RpcServer::on_getblockhash), false } }, - { "getblocktemplate", { makeMemberMethod(&RpcServer::on_getblocktemplate), false } }, - { "getcurrencyid", { makeMemberMethod(&RpcServer::on_get_currency_id), true } }, - { "submitblock", { makeMemberMethod(&RpcServer::on_submitblock), false } }, - { "getlastblockheader", { makeMemberMethod(&RpcServer::on_get_last_block_header), false } }, - { "getblockheaderbyhash", { makeMemberMethod(&RpcServer::on_get_block_header_by_hash), false } }, - { "getblockheaderbyheight", { makeMemberMethod(&RpcServer::on_get_block_header_by_height), false } } - }; - - auto it = jsonRpcHandlers.find(jsonRequest.getMethod()); - if (it == jsonRpcHandlers.end()) { - throw JsonRpcError(JsonRpc::errMethodNotFound); - } - - if (!it->second.allowBusyCore && !isCoreReady()) { - throw JsonRpcError(CORE_RPC_ERROR_CODE_CORE_BUSY, "Core is busy"); - } - - it->second.handler(this, jsonRequest, jsonResponse); - - } catch (const JsonRpcError& err) { - jsonResponse.setError(err); - } catch (const std::exception& e) { - jsonResponse.setError(JsonRpcError(JsonRpc::errInternalError, e.what())); - } - - response.setBody(jsonResponse.getBody()); - logger(TRACE) << "JSON-RPC response: " << jsonResponse.getBody(); - return true; -} - -bool RpcServer::isCoreReady() { - return m_core.currency().isTestnet() || m_p2p.get_payload_object().isSynchronized(); -} - -// -// Binary handlers -// - -bool RpcServer::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res) { - // TODO code duplication see InProcessNode::doGetNewBlocks() - if (req.block_ids.empty()) { - res.status = "Failed"; - return false; - } - - if (req.block_ids.back() != m_core.getBlockIdByHeight(0)) { - res.status = "Failed"; - return false; - } - - uint32_t totalBlockCount; - uint32_t startBlockIndex; - std::vector supplement = m_core.findBlockchainSupplement(req.block_ids, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, totalBlockCount, startBlockIndex); - - res.current_height = totalBlockCount; - res.start_height = startBlockIndex; - - for (const auto& blockId : supplement) { - assert(m_core.have_block(blockId)); - auto completeBlock = m_core.getBlock(blockId); - assert(completeBlock != nullptr); - - res.blocks.resize(res.blocks.size() + 1); - res.blocks.back().block = asString(toBinaryArray(completeBlock->getBlock())); - - res.blocks.back().txs.reserve(completeBlock->getTransactionCount()); - for (size_t i = 0; i < completeBlock->getTransactionCount(); ++i) { - res.blocks.back().txs.push_back(asString(toBinaryArray(completeBlock->getTransaction(i)))); - } - } - - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_query_blocks(const COMMAND_RPC_QUERY_BLOCKS::request& req, COMMAND_RPC_QUERY_BLOCKS::response& res) { - uint32_t startHeight; - uint32_t currentHeight; - uint32_t fullOffset; - - if (!m_core.queryBlocks(req.block_ids, req.timestamp, startHeight, currentHeight, fullOffset, res.items)) { - res.status = "Failed to perform query"; - return false; - } - - res.start_height = startHeight; - res.current_height = currentHeight; - res.full_offset = fullOffset; - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_query_blocks_lite(const COMMAND_RPC_QUERY_BLOCKS_LITE::request& req, COMMAND_RPC_QUERY_BLOCKS_LITE::response& res) { - uint32_t startHeight; - uint32_t currentHeight; - uint32_t fullOffset; - if (!m_core.queryBlocksLite(req.blockIds, req.timestamp, startHeight, currentHeight, fullOffset, res.items)) { - res.status = "Failed to perform query"; - return false; - } - - res.startHeight = startHeight; - res.currentHeight = currentHeight; - res.fullOffset = fullOffset; - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res) { - std::vector outputIndexes; - if (!m_core.get_tx_outputs_gindexs(req.txid, outputIndexes)) { - res.status = "Failed"; - return true; - } - - res.o_indexes.assign(outputIndexes.begin(), outputIndexes.end()); - res.status = CORE_RPC_STATUS_OK; - logger(TRACE) << "COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES: [" << res.o_indexes.size() << "]"; - return true; -} - -bool RpcServer::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) { - res.status = "Failed"; - if (!m_core.get_random_outs_for_amounts(req, res)) { - return true; - } - - res.status = CORE_RPC_STATUS_OK; - - std::stringstream ss; - typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; - typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; - - std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa) { - ss << "[" << ofa.amount << "]:"; - - assert(ofa.outs.size() && "internal error: ofa.outs.size() is empty"); - - std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe) - { - ss << oe.global_amount_index << " "; - }); - ss << ENDL; - }); - std::string s = ss.str(); - logger(TRACE) << "COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s; - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::onGetPoolChanges(const COMMAND_RPC_GET_POOL_CHANGES::request& req, COMMAND_RPC_GET_POOL_CHANGES::response& rsp) { - rsp.status = CORE_RPC_STATUS_OK; - std::vector addedTransactions; - rsp.isTailBlockActual = m_core.getPoolChanges(req.tailBlockId, req.knownTxsIds, addedTransactions, rsp.deletedTxsIds); - for (auto& tx : addedTransactions) { - BinaryArray txBlob; - if (!toBinaryArray(tx, txBlob)) { - rsp.status = "Internal error"; - break;; - } - - rsp.addedTxs.emplace_back(std::move(txBlob)); - } - return true; -} - - -bool RpcServer::onGetPoolChangesLite(const COMMAND_RPC_GET_POOL_CHANGES_LITE::request& req, COMMAND_RPC_GET_POOL_CHANGES_LITE::response& rsp) { - rsp.status = CORE_RPC_STATUS_OK; - rsp.isTailBlockActual = m_core.getPoolChangesLite(req.tailBlockId, req.knownTxsIds, rsp.addedTxs, rsp.deletedTxsIds); - - return true; -} - -// -// JSON handlers -// - -bool RpcServer::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res) { - res.height = m_core.get_current_blockchain_height(); - res.difficulty = m_core.getNextBlockDifficulty(); - res.tx_count = m_core.get_blockchain_total_transactions() - res.height; //without coinbase - res.tx_pool_size = m_core.get_pool_transactions_count(); - res.alt_blocks_count = m_core.get_alternative_blocks_count(); - uint64_t total_conn = m_p2p.get_connections_count(); - res.outgoing_connections_count = m_p2p.get_outgoing_connections_count(); - res.incoming_connections_count = total_conn - res.outgoing_connections_count; - res.white_peerlist_size = m_p2p.getPeerlistManager().get_white_peers_count(); - res.grey_peerlist_size = m_p2p.getPeerlistManager().get_gray_peers_count(); - res.last_known_block_index = std::max(static_cast(1), m_protocolQuery.getObservedHeight()) - 1; - res.full_deposit_amount = m_core.fullDepositAmount(); - res.full_deposit_interest = m_core.fullDepositInterest(); - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res) { - res.height = m_core.get_current_blockchain_height(); - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res) { - std::vector vh; - for (const auto& tx_hex_str : req.txs_hashes) { - BinaryArray b; - if (!fromHex(tx_hex_str, b)) - { - res.status = "Failed to parse hex representation of transaction hash"; - return true; - } - if (b.size() != sizeof(Hash)) - { - res.status = "Failed, size of data mismatch"; - } - vh.push_back(*reinterpret_cast(b.data())); - } - std::list missed_txs; - std::list txs; - m_core.getTransactions(vh, txs, missed_txs); - - for (auto& tx : txs) { - res.txs_as_hex.push_back(toHex(toBinaryArray(tx))); - } - - for (const auto& miss_tx : missed_txs) { - res.missed_tx.push_back(Common::podToHex(miss_tx)); - } - - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res) { - BinaryArray tx_blob; - if (!fromHex(req.tx_as_hex, tx_blob)) - { - logger(INFO) << "[on_send_raw_tx]: Failed to parse tx from hexbuff: " << req.tx_as_hex; - res.status = "Failed"; - return true; - } - - tx_verification_context tvc = boost::value_initialized(); - if (!m_core.handle_incoming_tx(tx_blob, tvc, false)) - { - logger(INFO) << "[on_send_raw_tx]: Failed to process tx"; - res.status = "Failed"; - return true; - } - - if (tvc.m_verifivation_failed) - { - logger(INFO) << "[on_send_raw_tx]: tx verification failed"; - res.status = "Failed"; - return true; - } - - if (!tvc.m_should_be_relayed) - { - logger(INFO) << "[on_send_raw_tx]: tx accepted, but not relayed"; - res.status = "Not relayed"; - return true; - } - - - NOTIFY_NEW_TRANSACTIONS::request r; - r.txs.push_back(asString(tx_blob)); - m_core.get_protocol()->relay_transactions(r); - //TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res) { - AccountPublicAddress adr; - if (!m_core.currency().parseAccountAddressString(req.miner_address, adr)) { - res.status = "Failed, wrong address"; - return true; - } - - if (!m_core.get_miner().start(adr, static_cast(req.threads_count))) { - res.status = "Failed, mining not started"; - return true; - } - - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res) { - if (!m_core.get_miner().stop()) { - res.status = "Failed, mining not stopped"; - return true; - } - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res) { - if (m_core.currency().isTestnet()) { - m_p2p.sendStopSignal(); - res.status = CORE_RPC_STATUS_OK; - } else { - res.status = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; - return false; - } - return true; -} - -//------------------------------------------------------------------------------------------------------------------------------ -// JSON RPC methods -//------------------------------------------------------------------------------------------------------------------------------ -bool RpcServer::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res) { - res.count = m_core.get_current_blockchain_height(); - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res) { - if (req.size() != 1) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_WRONG_PARAM, "Wrong parameters, expected height" }; - } - - uint32_t h = static_cast(req[0]); - Crypto::Hash blockId = m_core.getBlockIdByHeight(h); - if (blockId == NULL_HASH) { - throw JsonRpc::JsonRpcError{ - CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT, - std::string("To big height: ") + std::to_string(h) + ", current blockchain height = " + std::to_string(m_core.get_current_blockchain_height()) - }; - } - - res = Common::podToHex(blockId); - return true; -} - -namespace { - uint64_t slow_memmem(void* start_buff, size_t buflen, void* pat, size_t patlen) - { - void* buf = start_buff; - void* end = (char*)buf + buflen - patlen; - while ((buf = memchr(buf, ((char*)pat)[0], buflen))) - { - if (buf>end) - return 0; - if (memcmp(buf, pat, patlen) == 0) - return (char*)buf - (char*)start_buff; - buf = (char*)buf + 1; - } - return 0; - } -} - -bool RpcServer::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res) { - if (req.reserve_size > TX_EXTRA_NONCE_MAX_COUNT) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE, "To big reserved size, maximum 255" }; - } - - AccountPublicAddress acc = boost::value_initialized(); - - if (!req.wallet_address.size() || !m_core.currency().parseAccountAddressString(req.wallet_address, acc)) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS, "Failed to parse wallet address" }; - } - - Block b = boost::value_initialized(); - CryptoNote::BinaryArray blob_reserve; - blob_reserve.resize(req.reserve_size, 0); - if (!m_core.get_block_template(b, acc, res.difficulty, res.height, blob_reserve)) { - logger(ERROR) << "Failed to create block template"; - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, "Internal error: failed to create block template" }; - } - - BinaryArray block_blob = toBinaryArray(b); - PublicKey tx_pub_key = CryptoNote::getTransactionPublicKeyFromExtra(b.baseTransaction.extra); - if (tx_pub_key == NULL_PUBLIC_KEY) { - logger(ERROR) << "Failed to find tx pub key in coinbase extra"; - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, "Internal error: failed to find tx pub key in coinbase extra" }; - } - - if (0 < req.reserve_size) { - res.reserved_offset = slow_memmem((void*)block_blob.data(), block_blob.size(), &tx_pub_key, sizeof(tx_pub_key)); - if (!res.reserved_offset) { - logger(ERROR) << "Failed to find tx pub key in blockblob"; - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, "Internal error: failed to create block template" }; - } - res.reserved_offset += sizeof(tx_pub_key) + 3; //3 bytes: tag for TX_EXTRA_TAG_PUBKEY(1 byte), tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte) - if (res.reserved_offset + req.reserve_size > block_blob.size()) { - logger(ERROR) << "Failed to calculate offset for reserved bytes"; - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, "Internal error: failed to create block template" }; - } - } else { - res.reserved_offset = 0; - } - - res.blocktemplate_blob = toHex(block_blob); - res.status = CORE_RPC_STATUS_OK; - - return true; -} - -bool RpcServer::on_get_currency_id(const COMMAND_RPC_GET_CURRENCY_ID::request& /*req*/, COMMAND_RPC_GET_CURRENCY_ID::response& res) { - Hash currencyId = m_core.currency().genesisBlockHash(); - res.currency_id_blob = Common::podToHex(currencyId); - return true; -} - -bool RpcServer::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res) { - if (req.size() != 1) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_WRONG_PARAM, "Wrong param" }; - } - - BinaryArray blockblob; - if (!fromHex(req[0], blockblob)) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB, "Wrong block blob" }; - } - - block_verification_context bvc = boost::value_initialized(); - - m_core.handle_incoming_block_blob(blockblob, bvc, true, true); - - if (!bvc.m_added_to_main_chain) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED, "Block not accepted" }; - } - - res.status = CORE_RPC_STATUS_OK; - return true; -} - - -namespace { - uint64_t get_block_reward(const Block& blk) { - uint64_t reward = 0; - for (const TransactionOutput& out : blk.baseTransaction.outputs) { - reward += out.amount; - } - return reward; - } -} - -void RpcServer::fill_block_header_response(const Block& blk, bool orphan_status, uint64_t height, const Hash& hash, block_header_response& responce) { - responce.major_version = blk.majorVersion; - responce.minor_version = blk.minorVersion; - responce.timestamp = blk.timestamp; - responce.prev_hash = Common::podToHex(blk.previousBlockHash); - responce.nonce = blk.nonce; - responce.orphan_status = orphan_status; - responce.height = height; - responce.depth = m_core.get_current_blockchain_height() - height - 1; - responce.hash = Common::podToHex(hash); - m_core.getBlockDifficulty(static_cast(height), responce.difficulty); - responce.reward = get_block_reward(blk); -} - -bool RpcServer::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res) { - uint32_t last_block_height; - Hash last_block_hash; - - m_core.get_blockchain_top(last_block_height, last_block_hash); - - Block last_block; - if (!m_core.getBlockByHash(last_block_hash, last_block)) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, "Internal error: can't get last block hash." }; - } - - fill_block_header_response(last_block, false, last_block_height, last_block_hash, res.block_header); - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res) { - Hash block_hash; - - if (!parse_hash256(req.hash, block_hash)) { - throw JsonRpc::JsonRpcError{ - CORE_RPC_ERROR_CODE_WRONG_PARAM, - "Failed to parse hex representation of block hash. Hex = " + req.hash + '.' }; - } - - Block blk; - if (!m_core.getBlockByHash(block_hash, blk)) { - throw JsonRpc::JsonRpcError{ - CORE_RPC_ERROR_CODE_INTERNAL_ERROR, - "Internal error: can't get block by hash. Hash = " + req.hash + '.' }; - } - - if (blk.baseTransaction.inputs.front().type() != typeid(BaseInput)) { - throw JsonRpc::JsonRpcError{ - CORE_RPC_ERROR_CODE_INTERNAL_ERROR, - "Internal error: coinbase transaction in the block has the wrong type" }; - } - - uint64_t block_height = boost::get(blk.baseTransaction.inputs.front()).blockIndex; - fill_block_header_response(blk, false, block_height, block_hash, res.block_header); - res.status = CORE_RPC_STATUS_OK; - return true; -} - -bool RpcServer::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res) { - if (m_core.get_current_blockchain_height() <= req.height) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT, - std::string("To big height: ") + std::to_string(req.height) + ", current blockchain height = " + std::to_string(m_core.get_current_blockchain_height()) }; - } - - Hash block_hash = m_core.getBlockIdByHeight(static_cast(req.height)); - Block blk; - if (!m_core.getBlockByHash(block_hash, blk)) { - throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, - "Internal error: can't get block by height. Height = " + std::to_string(req.height) + '.' }; - } - - fill_block_header_response(blk, false, req.height, block_hash, res.block_header); - res.status = CORE_RPC_STATUS_OK; - return true; -} - - -} From 96d1c8b248143b0975d6b113b0fd60bf5218560d Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sat, 5 May 2018 17:30:43 +0000 Subject: [PATCH 20/26] BipCot --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 3c83add..9e11fc7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,32 @@ +# LICENSE + +BipCot NoGov Software License (www.bipcot.org), version 1.12 / No warranty of usability of BipCoin software. + +This original computer code and resulting program was made by Beastlick Internet Policy Commission Outreach Team, 2016. All rights to make fun of you reserved. https://bipcoin.org + +(Adapted from CryptoNote code, covered by permissive MIT license. https://cryptonote.org ) + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions and adaptations of source code or program must retain the entirety of this license, including retaining attribution of the license holder of the software. + +Redistributions in binary form must reproduce the entirety of this license. + +Neither the name of the license holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. Furthermore, no attempt will be made to impersonate the person or entity whose software is being used or modified. + +Governments, and agents and subcontractors of same, are not permitted to use this software or derivations of this software. + +If governments, agents and subcontractors of same use this software, or derivations of this software, all agencies and persons directly and knowingly involved may be shamed in public, by name, on the Internet, on radio, and in any media now extant or invented in the future, throughout the known universe and elsewhere, in perpetuity. Governments, agents and subcontractors of same that use this software, or derivations of this software, agree to endure this shaming, without comment or action. + +Any person or entity that violates any part of this agreement will also be shamed as above, and agrees to endure this shaming, without comment or action. + +The BipCot NoGov Software License adopts the first 3 clauses of the 3-Clause BSD license (Berkeley Software Distribution license) and adopts the BSD "as is" text at the end. The 3-Clause BSD license is in the Public Domain. However, there is no partnership or endorsement created or implied between the creators or users of The BipCot NoGov Software License and the creators or users of the BSD license, or vise versa. + +This version allows for "LIBERTARIAN INDULGENCES." i.e. low level government workers like mailmen and peaceful future Internet freedom hero contractors can use the thing that is licensed. But cops, goons, politicians, alphabet soup agency workers, etc, and anyone who carries a gun or orders the use of guns for the gub'mnint is still forbidden. (LICENSE HOLDER SHOULD REMOVE THIS PART, SECTION 8, TO REMOVE THIS OPTION.) + +THIS SOFTWARE IS PROVIDED BY THE LICENSE HOLDER 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 LICENSE 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. + + ## Building Bitcedi ### On *nix: From c53cb9ea205e37e40e56bb6eebb3a3c5461e911b Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sat, 5 May 2018 17:31:19 +0000 Subject: [PATCH 21/26] Bipcot - bipcot.org --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e11fc7..4564b0d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ BipCot NoGov Software License (www.bipcot.org), version 1.12 / No warranty of usability of BipCoin software. -This original computer code and resulting program was made by Beastlick Internet Policy Commission Outreach Team, 2016. All rights to make fun of you reserved. https://bipcoin.org +This original computer code and resulting program was made by Beastlick Internet Policy Commission Outreach Team, 2016. All rights to make fun of you reserved. https://bitcedibanking.org (Adapted from CryptoNote code, covered by permissive MIT license. https://cryptonote.org ) From 88e2cf3e5c2ee0131af7ed4a0a705ddfde03a359 Mon Sep 17 00:00:00 2001 From: aivve Date: Sun, 6 May 2018 18:17:36 +0300 Subject: [PATCH 22/26] Max mixin limit --- src/CryptoNoteConfig.h | 1 + src/CryptoNoteCore/Blockchain.cpp | 6 ++++++ src/CryptoNoteCore/Core.cpp | 21 +++++++++++++++++++++ src/CryptoNoteCore/Core.h | 3 +++ 4 files changed, 31 insertions(+) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index ba17152..330f23c 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -31,6 +31,7 @@ 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 EXPECTED_NUMBER_OF_BLOCKS_PER_DAY = 24 * 60 * 60 / DIFFICULTY_TARGET; const size_t DIFFICULTY_WINDOW = 240; // blocks diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index 2e57264..b6136cd 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -1470,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(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(txin); if (!(!in_to_key.outputIndexes.empty())) { logger(ERROR, BRIGHT_RED) << "empty in_to_key.outputIndexes in transaction with id " << getObjectHash(tx); return false; } diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index d2d2f31..81a913d 100644 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -219,6 +219,21 @@ bool core::get_stat_info(core_stat_info& st_inf) { } +bool core::check_tx_mixin(const Transaction& tx) { + size_t inputIndex = 0; + for (const auto& txin : tx.inputs) { + assert(inputIndex < tx.signatures.size()); + if (txin.type() == typeid(KeyInput)) { + uint64_t txMixin = boost::get(txin).outputIndexes.size(); + if (txMixin > CryptoNote::parameters::MAX_TX_MIXIN_SIZE) { + logger(ERROR) << "Transaction " << getObjectHash(tx) << " has too large mixin count, rejected"; + return false; + } + } + } + return true; +} + bool core::check_tx_semantic(const Transaction& tx, bool keeped_by_block) { if (!tx.inputs.size()) { logger(ERROR) << "tx with empty inputs, rejected for tx id= " << getObjectHash(tx); @@ -980,6 +995,12 @@ bool core::handleIncomingTransaction(const Transaction& tx, const Crypto::Hash& return false; } + if (!check_tx_mixin(tx)) { + logger(INFO) << "Transaction verification failed: mixin count for transaction " << txHash << " is too large, rejected"; + tvc.m_verifivation_failed = true; + return false; + } + if (!check_tx_semantic(tx, keptByBlock)) { logger(INFO) << "WRONG TRANSACTION BLOB, Failed to check tx " << txHash << " semantic, rejected"; tvc.m_verifivation_failed = true; diff --git a/src/CryptoNoteCore/Core.h b/src/CryptoNoteCore/Core.h index b31fe89..10c479a 100644 --- a/src/CryptoNoteCore/Core.h +++ b/src/CryptoNoteCore/Core.h @@ -155,6 +155,9 @@ namespace CryptoNote { //check correct values, amounts and all lightweight checks not related with database bool check_tx_semantic(const Transaction& tx, bool keeped_by_block); //check if tx already in memory pool or in main blockchain + bool check_tx_mixin(const Transaction& tx); + //check if the mixin is not too large + bool is_key_image_spent(const Crypto::KeyImage& key_im); From 808c6a70f976d0dd73cbf0749311c48394c6f5f2 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Sun, 6 May 2018 16:09:10 +0000 Subject: [PATCH 23/26] Remove outdated seednodes, adding new ones. --- src/CryptoNoteConfig.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 330f23c..a31e452 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -120,13 +120,9 @@ const size_t P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT = 5000; // const char P2P_STAT_TRUSTED_PUB_KEY[] = "85ae8734f90bc1ee295ceb0ec05a49852d4dbbc9d1c27a619b5f4bdf26a0196e"; const std::initializer_list SEED_NODES = { - "seed0.bitcedi.org:55008", - "seed1.bitcedi.org:55008", - "seed2.bitcedi.org:55008", - "174.138.3.171:55008", - "185.183.99.19:55008", - "138.68.105.149:18080", - "172.104.240.101:55008" + "173.230.155.185:55008", + "172.104.240.101:55008", + "45.33.53.50:55008" }; struct CheckpointData { From 2c2024e277c374d2a66d57b81837ddf4060041e9 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Thu, 31 May 2018 17:49:18 +0000 Subject: [PATCH 24/26] Citadel Rebrand --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 2090301..5e3d5a6 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define BUILD_COMMIT_ID "@VERSION@" #define PROJECT_VERSION "0.1.2" -#define PROJECT_VERSION_BUILD_NO "cedi0011" +#define PROJECT_VERSION_BUILD_NO "ctl0011" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")" From f264459ff430533f7047a57b5cc7ebd310afb145 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Thu, 31 May 2018 17:50:05 +0000 Subject: [PATCH 25/26] Citadel Rebrand --- src/CryptoNoteConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index a31e452..98c9d5b 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -85,7 +85,7 @@ 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; From 65395ebd93d2313c48e7aa79fb58f0336f476929 Mon Sep 17 00:00:00 2001 From: cntemple <38593686+cntemple@users.noreply.github.com> Date: Thu, 31 May 2018 21:25:36 +0000 Subject: [PATCH 26/26] CITADEL REBRAND --- README.md | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/README.md b/README.md index 4564b0d..281eab3 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,4 @@ -# LICENSE - -BipCot NoGov Software License (www.bipcot.org), version 1.12 / No warranty of usability of BipCoin software. - -This original computer code and resulting program was made by Beastlick Internet Policy Commission Outreach Team, 2016. All rights to make fun of you reserved. https://bitcedibanking.org - -(Adapted from CryptoNote code, covered by permissive MIT license. https://cryptonote.org ) - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -Redistributions and adaptations of source code or program must retain the entirety of this license, including retaining attribution of the license holder of the software. - -Redistributions in binary form must reproduce the entirety of this license. - -Neither the name of the license holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. Furthermore, no attempt will be made to impersonate the person or entity whose software is being used or modified. - -Governments, and agents and subcontractors of same, are not permitted to use this software or derivations of this software. - -If governments, agents and subcontractors of same use this software, or derivations of this software, all agencies and persons directly and knowingly involved may be shamed in public, by name, on the Internet, on radio, and in any media now extant or invented in the future, throughout the known universe and elsewhere, in perpetuity. Governments, agents and subcontractors of same that use this software, or derivations of this software, agree to endure this shaming, without comment or action. - -Any person or entity that violates any part of this agreement will also be shamed as above, and agrees to endure this shaming, without comment or action. - -The BipCot NoGov Software License adopts the first 3 clauses of the 3-Clause BSD license (Berkeley Software Distribution license) and adopts the BSD "as is" text at the end. The 3-Clause BSD license is in the Public Domain. However, there is no partnership or endorsement created or implied between the creators or users of The BipCot NoGov Software License and the creators or users of the BSD license, or vise versa. - -This version allows for "LIBERTARIAN INDULGENCES." i.e. low level government workers like mailmen and peaceful future Internet freedom hero contractors can use the thing that is licensed. But cops, goons, politicians, alphabet soup agency workers, etc, and anyone who carries a gun or orders the use of guns for the gub'mnint is still forbidden. (LICENSE HOLDER SHOULD REMOVE THIS PART, SECTION 8, TO REMOVE THIS OPTION.) - -THIS SOFTWARE IS PROVIDED BY THE LICENSE HOLDER 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 LICENSE 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. - - -## Building Bitcedi +## Building Citadel ### On *nix: