diff options
28 files changed, 205 insertions, 101 deletions
@@ -134,6 +134,8 @@ Dates are provided in the format YYYY-MM-DD. | 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format | 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format | 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs +| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.0.0 | New CLSAG transaction format +| 2210720 | 2020-10-18 | v14 | v0.17.0.0 | v0.17.0.0 | forbid old MLSAG transaction format | XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX | X's indicate that these details have not been determined as of commit date. @@ -220,7 +222,7 @@ invokes cmake commands as needed. ```bash cd monero - git checkout release-v0.16 + git checkout release-v0.17 make ``` @@ -293,7 +295,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( ```bash git clone https://github.com/monero-project/monero.git cd monero - git checkout tags/v0.16.0.0 + git checkout tags/v0.17.0.0 ``` * Build: @@ -410,10 +412,10 @@ application. cd monero ``` -* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.16.0.0'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.0.0'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.16.0.0 + git checkout v0.17.0.0 ``` * If you are on a 64-bit system, run: diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md index c0f230887..1938462aa 100644 --- a/contrib/gitian/README.md +++ b/contrib/gitian/README.md @@ -126,7 +126,7 @@ Setup for LXC: ```bash GH_USER=fluffypony -VERSION=v0.16.0.0 +VERSION=v0.17.0.0 ./gitian-build.py --setup $GH_USER $VERSION ``` @@ -182,7 +182,7 @@ If you chose to do detached signing using `--detach-sign` above (recommended), y ```bash GH_USER=fluffypony -VERSION=v0.16.0.0 +VERSION=v0.17.0.0 gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert diff --git a/contrib/gitian/gitian-android.yml b/contrib/gitian/gitian-android.yml index de98efafe..b8eaa8af9 100644 --- a/contrib/gitian/gitian-android.yml +++ b/contrib/gitian/gitian-android.yml @@ -1,5 +1,5 @@ --- -name: "monero-android-0.16" +name: "monero-android-0.17" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-freebsd.yml b/contrib/gitian/gitian-freebsd.yml index e97c3802b..c104bfd02 100644 --- a/contrib/gitian/gitian-freebsd.yml +++ b/contrib/gitian/gitian-freebsd.yml @@ -1,5 +1,5 @@ --- -name: "monero-freebsd-0.16" +name: "monero-freebsd-0.17" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-linux.yml b/contrib/gitian/gitian-linux.yml index bd42637aa..4a2f3798a 100644 --- a/contrib/gitian/gitian-linux.yml +++ b/contrib/gitian/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "monero-linux-0.16" +name: "monero-linux-0.17" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-osx.yml b/contrib/gitian/gitian-osx.yml index 4d44c4845..9889ca45f 100644 --- a/contrib/gitian/gitian-osx.yml +++ b/contrib/gitian/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "monero-osx-0.16" +name: "monero-osx-0.17" enable_cache: true suites: - "bionic" diff --git a/contrib/gitian/gitian-win.yml b/contrib/gitian/gitian-win.yml index 196b6ebbe..c53086144 100644 --- a/contrib/gitian/gitian-win.yml +++ b/contrib/gitian/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "monero-win-0.16" +name: "monero-win-0.17" enable_cache: true suites: - "bionic" diff --git a/external/unbound b/external/unbound -Subproject b26b3136e25ddcb834d7d75ec155b3ddb1522a2 +Subproject 0f6c0579d66b65f86066e30e7876105ba2775ef diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat Binary files differindex fa58387ab..e75e379f2 100644 --- a/src/blocks/checkpoints.dat +++ b/src/blocks/checkpoints.dat diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index 6e7e1acba..c88a630cc 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -236,6 +236,7 @@ namespace cryptonote ADD_CHECKPOINT2(1958000, "98a5d6e51afdf3146e0eefb10a66e8648d8d4d5c2742be8835e976ba217c9bb2", "0x79dd46d2a0971a"); ADD_CHECKPOINT2(2046000, "5e867f0b8baefed9244a681df97fc885d8ab36c3dfcd24c7a3abf3b8ac8b8314", "0x9cb8b6ff2978c6"); ADD_CHECKPOINT2(2092500, "c4e00820c9c7989b49153d5e90ae095a18a11d990e82fcc3be54e6ed785472b5", "0xb4e585a31369cb"); + ADD_CHECKPOINT2(2182500, "0d22b5f81982eff21d094af9e821dc2007e6342069e3b1a37b15d97646353124", "0xead4a874083492"); return true; } diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index f50ab6a40..a4db99f83 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -37,7 +37,6 @@ #define CRYPTONOTE_DNS_TIMEOUT_MS 20000 #define CRYPTONOTE_MAX_BLOCK_NUMBER 500000000 -#define CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE 196608 //size of block (bytes) that is the maximum that miners will produce #define CRYPTONOTE_MAX_TX_SIZE 1000000 #define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000 #define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0 @@ -155,7 +154,6 @@ #define RPC_IP_FAILS_BEFORE_BLOCK 3 #define CRYPTONOTE_NAME "bitmonero" -#define CRYPTONOTE_POOLDATA_FILENAME "poolstate.bin" #define CRYPTONOTE_BLOCKCHAINDATA_FILENAME "data.mdb" #define CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME "lock.mdb" #define P2P_NET_DATA_FILENAME "p2pstate.bin" @@ -180,6 +178,7 @@ #define HF_VERSION_EFFECTIVE_SHORT_TERM_MEDIAN_IN_PENALTY 12 #define HF_VERSION_EXACT_COINBASE 13 #define HF_VERSION_CLSAG 13 +#define HF_VERSION_DETERMINISTIC_UNLOCK_TIME 13 #define PER_KB_FEE_QUANTIZATION_DECIMALS 8 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 71b32dcf6..93e3ef3bc 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2267,8 +2267,9 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA MERROR("Unexpected output data size: expected " << req.outputs.size() << ", got " << data.size()); return false; } + const uint8_t hf_version = m_hardfork->get_current_version(); for (const auto &t: data) - res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time), t.height, crypto::null_hash}); + res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time, hf_version), t.height, crypto::null_hash}); if (req.get_txid) { @@ -2292,7 +2293,8 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint key = o_data.pubkey; mask = o_data.commitment; tx_out_index toi = m_db->get_output_tx_and_index(amount, index); - unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)); + const uint8_t hf_version = m_hardfork->get_current_version(); + unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first), hf_version); } //------------------------------------------------------------------ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const @@ -3363,7 +3365,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, // make sure that output being spent matches up correctly with the // signature spending it. - if (!check_tx_input(tx.version, in_to_key, tx_prefix_hash, tx.version == 1 ? tx.signatures[sig_index] : std::vector<crypto::signature>(), tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height)) + if (!check_tx_input(tx.version, in_to_key, tx_prefix_hash, tx.version == 1 ? tx.signatures[sig_index] : std::vector<crypto::signature>(), tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height, hf_version)) { MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain() @@ -3756,7 +3758,7 @@ uint64_t Blockchain::get_dynamic_base_fee_estimate(uint64_t grace_blocks) const //------------------------------------------------------------------ // This function checks to see if a tx is unlocked. unlock_time is either // a block index or a unix time. -bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const +bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time, uint8_t hf_version) const { LOG_PRINT_L3("Blockchain::" << __func__); if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) @@ -3771,7 +3773,7 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const else { //interpret as time - uint64_t current_time = static_cast<uint64_t>(time(NULL)); + const uint64_t current_time = hf_version >= HF_VERSION_DETERMINISTIC_UNLOCK_TIME ? get_adjusted_time(m_db->height()) : static_cast<uint64_t>(time(NULL)); if(current_time + (get_current_hard_fork_version() < 2 ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2) >= unlock_time) return true; else @@ -3783,7 +3785,7 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const // This function locates all outputs associated with a given input (mixins) // and validates that they exist and are usable. It also checks the ring // signature for each input. -bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height) const +bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height, uint8_t hf_version) const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -3795,14 +3797,15 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons { std::vector<rct::ctkey >& m_output_keys; const Blockchain& m_bch; - outputs_visitor(std::vector<rct::ctkey>& output_keys, const Blockchain& bch) : - m_output_keys(output_keys), m_bch(bch) + const uint8_t hf_version; + outputs_visitor(std::vector<rct::ctkey>& output_keys, const Blockchain& bch, uint8_t hf_version) : + m_output_keys(output_keys), m_bch(bch), hf_version(hf_version) { } bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey, const rct::key &commitment) { //check tx unlock time - if (!m_bch.is_tx_spendtime_unlocked(unlock_time)) + if (!m_bch.is_tx_spendtime_unlocked(unlock_time, hf_version)) { MERROR_VER("One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time); return false; @@ -3821,7 +3824,7 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons output_keys.clear(); // collect output keys - outputs_visitor vi(output_keys, *this); + outputs_visitor vi(output_keys, *this, hf_version); if (!scan_outputkeys_for_indexes(tx_version, txin, vi, tx_prefix_hash, pmax_related_block_height)) { MERROR_VER("Failed to get output keys for tx with amount = " << print_money(txin.amount) << " and count indexes " << txin.key_offsets.size()); @@ -3840,12 +3843,38 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons return true; } //------------------------------------------------------------------ -//TODO: Is this intended to do something else? Need to look into the todo there. -uint64_t Blockchain::get_adjusted_time() const +// only works on the main chain +uint64_t Blockchain::get_adjusted_time(uint64_t height) const { LOG_PRINT_L3("Blockchain::" << __func__); - //TODO: add collecting median time - return time(NULL); + + // if not enough blocks, no proper median yet, return current time + if(height < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) + { + return static_cast<uint64_t>(time(NULL)); + } + std::vector<uint64_t> timestamps; + + // need most recent 60 blocks, get index of first of those + size_t offset = height - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW; + timestamps.reserve(height - offset); + for(;offset < height; ++offset) + { + timestamps.push_back(m_db->get_block_timestamp(offset)); + } + uint64_t median_ts = epee::misc_utils::median(timestamps); + + // project the median to match approximately when the block being validated will appear + // the median is calculated from a chunk of past blocks, so we use +1 to offset onto the current block + median_ts += (BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW + 1) * DIFFICULTY_TARGET_V2 / 2; + + // project the current block's time based on the previous block's time + // we don't use the current block's time directly to mitigate timestamp manipulation + uint64_t adjusted_current_block_ts = timestamps.back() + DIFFICULTY_TARGET_V2; + + // return minimum of ~current block time and adjusted median time + // we do this since it's better to report a time in the past than a time in the future + return (adjusted_current_block_ts < median_ts ? adjusted_current_block_ts : median_ts); } //------------------------------------------------------------------ //TODO: revisit, has changed a bit on upstream @@ -3873,9 +3902,9 @@ bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) const { LOG_PRINT_L3("Blockchain::" << __func__); - if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT) + if(b.timestamp > (uint64_t)time(NULL) + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT) { - MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 2 hours"); + MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than local time + 2 hours"); return false; } @@ -4049,8 +4078,8 @@ leave: MCINFO("verify", "No pre-validated hash at height " << blockchain_height << ", verifying fully"); } } - else #endif + if (!fast_check) { auto it = m_blocks_longhash_table.find(id); if (it != m_blocks_longhash_table.end()) @@ -5335,7 +5364,7 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) -static const char expected_block_hashes_hash[] = "8b48d259d4b1126801b1f329683a26e1d16237420197cd3ccc76af2c55a36e83"; +static const char expected_block_hashes_hash[] = "8da80ca560793f252d1d4ed449c85d75c74867f3f86b8832c8e3f88b1cbb6ae3"; void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints) { if (get_checkpoints == nullptr || !m_fast_sync) diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 20bd3e5d3..a9b7ca1da 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1042,6 +1042,21 @@ namespace cryptonote */ void flush_invalid_blocks(); + /** + * @brief get the "adjusted time" + * + * Computes the median timestamp of the previous 60 blocks, projects it + * onto the current block to get an 'adjusted median time' which approximates + * what the current block's timestamp should be. Also projects the previous + * block's timestamp to estimate the current block's timestamp. + * + * Returns the minimum of the two projections, or the current local time on + * the machine if less than 60 blocks are available. + * + * @return current time approximated from chain data + */ + uint64_t get_adjusted_time(uint64_t height) const; + #ifndef IN_UNIT_TESTS private: #endif @@ -1182,10 +1197,11 @@ namespace cryptonote * @param output_keys return-by-reference the public keys of the outputs in the input set * @param rct_signatures the ringCT signatures, which are only valid if tx version > 1 * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set + * @param hf_version the consensus rules version to use * * @return false if any output is not yet unlocked, or is missing, otherwise true */ - bool check_tx_input(size_t tx_version,const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height) const; + bool check_tx_input(size_t tx_version,const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height, uint8_t hf_version) const; /** * @brief validate a transaction's inputs and their keys @@ -1373,10 +1389,11 @@ namespace cryptonote * unlock_time is either a block index or a unix time. * * @param unlock_time the unlock parameter (height or time) + * @param hf_version the consensus rules version to use * * @return true if spendable, otherwise false */ - bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; + bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint8_t hf_version) const; /** * @brief stores an invalid block in a separate container @@ -1438,16 +1455,6 @@ namespace cryptonote bool check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b) const { uint64_t median_ts; return check_block_timestamp(timestamps, b, median_ts); } /** - * @brief get the "adjusted time" - * - * Currently this simply returns the current time according to the - * user's machine. - * - * @return the current time - */ - uint64_t get_adjusted_time() const; - - /** * @brief finish an alternate chain's timestamp window from the main chain * * for an alternate chain, get the timestamps from the main chain to complete diff --git a/src/device_trezor/trezor/protocol.cpp b/src/device_trezor/trezor/protocol.cpp index 25c3d816d..288f3ddca 100644 --- a/src/device_trezor/trezor/protocol.cpp +++ b/src/device_trezor/trezor/protocol.cpp @@ -561,11 +561,6 @@ namespace tx { assign_to_repeatable(tsx_data.mutable_minor_indices(), tx.subaddr_indices.begin(), tx.subaddr_indices.end()); } - // TODO: use HF_VERSION_CLSAG after CLSAG is merged - if (tsx_data.hard_fork() >= 13){ - throw exc::ProtocolException("CLSAG is not yet implemented"); - } - // Rsig decision auto rsig_data = tsx_data.mutable_rsig_data(); m_ct.rsig_type = get_rsig_type(tx.rct_config, tx.splitted_dsts.size()); @@ -1017,14 +1012,24 @@ namespace tx { } } - // CLSAG support comes here once it is merged to the Monero - m_ct.rv->p.MGs.reserve(m_ct.signatures.size()); - for(size_t i = 0; i < m_ct.signatures.size(); ++i) { - rct::mgSig mg; - if (!cn_deserialize(m_ct.signatures[i], mg)) { - throw exc::ProtocolException("Cannot deserialize mg[i]"); + if (m_ct.rv->type == rct::RCTTypeCLSAG){ + m_ct.rv->p.CLSAGs.reserve(m_ct.signatures.size()); + for (size_t i = 0; i < m_ct.signatures.size(); ++i) { + rct::clsag clsag; + if (!cn_deserialize(m_ct.signatures[i], clsag)) { + throw exc::ProtocolException("Cannot deserialize clsag[i]"); + } + m_ct.rv->p.CLSAGs.push_back(clsag); + } + } else { + m_ct.rv->p.MGs.reserve(m_ct.signatures.size()); + for (size_t i = 0; i < m_ct.signatures.size(); ++i) { + rct::mgSig mg; + if (!cn_deserialize(m_ct.signatures[i], mg)) { + throw exc::ProtocolException("Cannot deserialize mg[i]"); + } + m_ct.rv->p.MGs.push_back(mg); } - m_ct.rv->p.MGs.push_back(mg); } m_ct.tx.rct_signatures = *(m_ct.rv); diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp index 6b8c0a8d6..9055b92e3 100644 --- a/src/hardforks/hardforks.cpp +++ b/src/hardforks/hardforks.cpp @@ -115,7 +115,7 @@ const hardfork_t stagenet_hard_forks[] = { { 10, 269000, 0, 1550153694 }, { 11, 269720, 0, 1550225678 }, { 12, 454721, 0, 1571419280 }, - { 13, 699045, 0, 1598180817 }, - { 14, 699765, 0, 1598180818 }, + { 13, 675405, 0, 1598180817 }, + { 14, 676125, 0, 1598180818 }, }; const size_t num_stagenet_hard_forks = sizeof(stagenet_hard_forks) / sizeof(stagenet_hard_forks[0]); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 82e3e9040..a50c70418 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -461,6 +461,8 @@ namespace cryptonote res.cumulative_difficulty, res.wide_cumulative_difficulty, res.cumulative_difficulty_top64); res.block_size_limit = res.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit(); res.block_size_median = res.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median(); + res.adjusted_time = m_core.get_blockchain_storage().get_adjusted_time(res.height); + res.start_time = restricted ? 0 : (uint64_t)m_core.get_start_time(); res.free_space = restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space(); res.offline = m_core.offline(); @@ -1306,8 +1308,8 @@ namespace cryptonote case 1: res.pow_algorithm = "CNv1 (Cryptonight variant 1)"; break; case 2: case 3: res.pow_algorithm = "CNv2 (Cryptonight variant 2)"; break; case 4: case 5: res.pow_algorithm = "CNv4 (Cryptonight variant 4)"; break; - case 6: case 7: res.pow_algorithm = "RandomX"; break; - default: res.pow_algorithm = "I'm not sure actually"; break; + case 6: case 7: case 8: case 9: res.pow_algorithm = "RandomX"; break; + default: res.pow_algorithm = "RandomX"; break; // assumed } if (res.is_background_mining_enabled) { diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 09cd67d7d..8748b0540 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -88,7 +88,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 3 -#define CORE_RPC_VERSION_MINOR 1 +#define CORE_RPC_VERSION_MINOR 2 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -675,6 +675,7 @@ namespace cryptonote uint64_t block_weight_limit; uint64_t block_size_median; uint64_t block_weight_median; + uint64_t adjusted_time; uint64_t start_time; uint64_t free_space; bool offline; @@ -713,6 +714,7 @@ namespace cryptonote KV_SERIALIZE_OPT(block_weight_limit, (uint64_t)0) KV_SERIALIZE(block_size_median) KV_SERIALIZE_OPT(block_weight_median, (uint64_t)0) + KV_SERIALIZE(adjusted_time) KV_SERIALIZE(start_time) KV_SERIALIZE(free_space) KV_SERIALIZE(offline) diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 248c54afb..e256322cb 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -538,6 +538,7 @@ namespace rpc res.info.cumulative_difficulty = (res.info.wide_cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>(); res.info.block_size_limit = res.info.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit(); res.info.block_size_median = res.info.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median(); + res.info.adjusted_time = m_core.get_blockchain_storage().get_adjusted_time(res.info.height); res.info.start_time = (uint64_t)m_core.get_start_time(); res.info.version = MONERO_VERSION; diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h index 085148d8a..86424653f 100644 --- a/src/rpc/message_data_structs.h +++ b/src/rpc/message_data_structs.h @@ -196,6 +196,7 @@ namespace rpc uint64_t block_size_limit; uint64_t block_weight_limit; uint64_t block_size_median; + uint64_t adjusted_time; uint64_t block_weight_median; uint64_t start_time; std::string version; diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index 7c48cf6c3..67f042c2e 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -1342,6 +1342,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::r INSERT_INTO_JSON_OBJECT(dest, block_weight_limit, info.block_weight_limit); INSERT_INTO_JSON_OBJECT(dest, block_size_median, info.block_size_median); INSERT_INTO_JSON_OBJECT(dest, block_weight_median, info.block_weight_median); + INSERT_INTO_JSON_OBJECT(dest, adjusted_time, info.adjusted_time); INSERT_INTO_JSON_OBJECT(dest, start_time, info.start_time); dest.EndObject(); @@ -1375,6 +1376,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf GET_FROM_JSON_OBJECT(val, info.block_weight_limit, block_weight_limit); GET_FROM_JSON_OBJECT(val, info.block_size_median, block_size_median); GET_FROM_JSON_OBJECT(val, info.block_weight_median, block_weight_median); + GET_FROM_JSON_OBJECT(val, info.adjusted_time, adjusted_time); GET_FROM_JSON_OBJECT(val, info.start_time, start_time); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index ac8531112..7b26d21fb 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -8553,8 +8553,8 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec } else { - uint64_t current_time = static_cast<uint64_t>(time(NULL)); - uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1); + const uint64_t adjusted_time = m_wallet->get_daemon_adjusted_time(); + uint64_t threshold = adjusted_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1); if (threshold < pd.m_unlock_time) locked_msg = get_human_readable_timespan(std::chrono::seconds(pd.m_unlock_time - threshold)); } @@ -10265,8 +10265,8 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args) } else { - uint64_t current_time = static_cast<uint64_t>(time(NULL)); - uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1); + const uint64_t adjusted_time = m_wallet->get_daemon_adjusted_time(); + uint64_t threshold = adjusted_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1); if (threshold >= pd.m_unlock_time) success_msg_writer() << "unlocked for " << get_human_readable_timespan(std::chrono::seconds(threshold - pd.m_unlock_time)); else diff --git a/src/version.cpp.in b/src/version.cpp.in index 1e720537a..9f6ffd97b 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,6 +1,6 @@ #define DEF_MONERO_VERSION_TAG "@VERSIONTAG@" -#define DEF_MONERO_VERSION "0.16.0.0" -#define DEF_MONERO_RELEASE_NAME "Nitrogen Nebula" +#define DEF_MONERO_VERSION "0.17.0.0" +#define DEF_MONERO_RELEASE_NAME "Oxygen Orion" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG #define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@ diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp index 95b8ce8bb..48a602bf3 100644 --- a/src/wallet/node_rpc_proxy.cpp +++ b/src/wallet/node_rpc_proxy.cpp @@ -72,6 +72,7 @@ void NodeRPCProxy::invalidate() m_rpc_version = 0; m_target_height = 0; m_block_weight_limit = 0; + m_adjusted_time = 0; m_get_info_time = 0; m_rpc_payment_info_time = 0; m_rpc_payment_seed_height = 0; @@ -131,6 +132,7 @@ boost::optional<std::string> NodeRPCProxy::get_info() m_height = resp_t.height; m_target_height = resp_t.target_height; m_block_weight_limit = resp_t.block_weight_limit ? resp_t.block_weight_limit : resp_t.block_size_limit; + m_adjusted_time = resp_t.adjusted_time; m_get_info_time = now; m_height_time = now; } @@ -171,6 +173,15 @@ boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &bloc return boost::optional<std::string>(); } +boost::optional<std::string> NodeRPCProxy::get_adjusted_time(uint64_t &adjusted_time) +{ + auto res = get_info(); + if (res) + return res; + adjusted_time = m_adjusted_time; + return boost::optional<std::string>(); +} + boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) { if (m_offline) diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h index 500ba81d4..51b7f01dd 100644 --- a/src/wallet/node_rpc_proxy.h +++ b/src/wallet/node_rpc_proxy.h @@ -52,6 +52,7 @@ public: void set_height(uint64_t h); boost::optional<std::string> get_target_height(uint64_t &height); boost::optional<std::string> get_block_weight_limit(uint64_t &block_weight_limit); + boost::optional<std::string> get_adjusted_time(uint64_t &adjusted_time); boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height); boost::optional<std::string> get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee); boost::optional<std::string> get_fee_quantization_mask(uint64_t &fee_quantization_mask); @@ -84,6 +85,7 @@ private: uint64_t m_dynamic_base_fee_estimate_cached_height; uint64_t m_dynamic_base_fee_estimate_grace_blocks; uint64_t m_fee_quantization_mask; + uint64_t m_adjusted_time; uint32_t m_rpc_version; uint64_t m_target_height; uint64_t m_block_weight_limit; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3e2ccd1ff..063c493ce 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -301,7 +301,7 @@ struct options { const command_line::arg_descriptor<std::string> tx_notify = { "tx-notify" , "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" , "" }; const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false}; const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor use DNS"), false}; - const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, wihch typically means more than 256 bits of data)")}; + const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)")}; }; void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file) @@ -5969,7 +5969,7 @@ uint64_t wallet2::balance(uint32_t index_major, bool strict) const return amount; } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const +uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) { uint64_t amount = 0; if (blocks_to_unlock) @@ -6021,7 +6021,7 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo return amount_per_subaddr; } //---------------------------------------------------------------------------------------------------- -std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const +std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) { std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> amount_per_subaddr; const uint64_t blockchain_height = get_blockchain_current_height(); @@ -6069,7 +6069,7 @@ uint64_t wallet2::balance_all(bool strict) const return r; } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const +uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) { uint64_t r = 0; if (blocks_to_unlock) @@ -6234,12 +6234,12 @@ void wallet2::rescan_blockchain(bool hard, bool refresh, bool keep_key_images) finish_rescan_bc_keep_key_images(transfers_cnt, transfers_hash); } //---------------------------------------------------------------------------------------------------- -bool wallet2::is_transfer_unlocked(const transfer_details& td) const +bool wallet2::is_transfer_unlocked(const transfer_details& td) { return is_transfer_unlocked(td.m_tx.unlock_time, td.m_block_height); } //---------------------------------------------------------------------------------------------------- -bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const +bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) { if(!is_tx_spendtime_unlocked(unlock_time, block_height)) return false; @@ -6250,7 +6250,7 @@ bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const +bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) { if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) { @@ -6262,12 +6262,14 @@ bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_heig }else { //interpret as time - uint64_t current_time = static_cast<uint64_t>(time(NULL)); + uint64_t adjusted_time; + try { adjusted_time = get_daemon_adjusted_time(); } + catch(...) { adjusted_time = time(NULL); } // use local time if no daemon to report blockchain time // XXX: this needs to be fast, so we'd need to get the starting heights // from the daemon to be correct once voting kicks in uint64_t v2height = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827; uint64_t leeway = block_height < v2height ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2; - if(current_time + leeway >= unlock_time) + if(adjusted_time + leeway >= unlock_time) return true; else return false; @@ -8052,13 +8054,16 @@ std::pair<std::set<uint64_t>, size_t> outs_unique(const std::vector<std::vector< return std::make_pair(std::move(unique), total); } -void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count) +void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct) { std::vector<uint64_t> rct_offsets; for (size_t attempts = 3; attempts > 0; --attempts) { get_outs(outs, selected_transfers, fake_outputs_count, rct_offsets); + if (!rct) + return; + const auto unique = outs_unique(outs); if (tx_sanity_check(unique.first, unique.second, rct_offsets.empty() ? 0 : rct_offsets.back())) { @@ -8696,7 +8701,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts"); if (outs.empty()) - get_outs(outs, selected_transfers, fake_outputs_count); // may throw + get_outs(outs, selected_transfers, fake_outputs_count, false); // may throw //prepare inputs LOG_PRINT_L2("preparing outputs"); @@ -8897,10 +8902,12 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry MDEBUG("We will create " << n_multisig_txes << " txes"); } + bool all_rct = true; uint64_t found_money = 0; for(size_t idx: selected_transfers) { found_money += m_transfers[idx].amount(); + all_rct &= m_transfers[idx].is_rct(); } LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee)); @@ -8911,7 +8918,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts"); if (outs.empty()) - get_outs(outs, selected_transfers, fake_outputs_count); // may throw + get_outs(outs, selected_transfers, fake_outputs_count, all_rct); // may throw //prepare inputs LOG_PRINT_L2("preparing outputs"); @@ -9104,7 +9111,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry LOG_PRINT_L2("transfer_selected_rct done"); } -std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const +std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) { std::vector<size_t> picks; float current_output_relatdness = 1.0f; @@ -10352,7 +10359,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring; const uint64_t fractional_threshold = (fee_multiplier * base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024); - THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet"); + THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the specified account"); std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr; @@ -10682,7 +10689,7 @@ void wallet2::cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_ hw::wallet_shim wallet_shim; setup_shim(&wallet_shim, this); aux_data.tx_recipients = dsts_info; - aux_data.bp_version = use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1; + aux_data.bp_version = (use_fork_rules(HF_VERSION_CLSAG, -10) ? 3 : use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1); aux_data.hard_fork = get_current_hard_fork(); dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data); tx_device_aux = aux_data.tx_device_aux; @@ -10775,7 +10782,7 @@ uint64_t wallet2::get_upper_transaction_weight_limit() return full_reward_zone - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } //---------------------------------------------------------------------------------------------------- -std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const +std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(const transfer_details &td)> &f) { std::vector<size_t> outputs; size_t n = 0; @@ -12080,6 +12087,15 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err) return height; } +uint64_t wallet2::get_daemon_adjusted_time() +{ + uint64_t adjusted_time; + + boost::optional<std::string> result = m_node_rpc_proxy.get_adjusted_time(adjusted_time); + THROW_WALLET_EXCEPTION_IF(result, error::wallet_internal_error, "Invalid adjusted time from daemon"); + return adjusted_time; +} + uint64_t wallet2::get_daemon_blockchain_target_height(string &err) { err = ""; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 62ed111f1..eac99185c 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -939,13 +939,13 @@ private: // locked & unlocked balance of given or current subaddress account uint64_t balance(uint32_t subaddr_index_major, bool strict) const; - uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const; + uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL); // locked & unlocked balance per subaddress of given or current subaddress account std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const; - std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const; + std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict); // all locked & unlocked balances of all subaddress accounts uint64_t balance_all(bool strict) const; - uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const; + uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL); template<typename T> void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, @@ -1003,8 +1003,8 @@ private: uint64_t get_blockchain_current_height() const { return m_light_wallet_blockchain_height ? m_light_wallet_blockchain_height : m_blockchain.size(); } void rescan_spent(); void rescan_blockchain(bool hard, bool refresh = true, bool keep_key_images = false); - bool is_transfer_unlocked(const transfer_details& td) const; - bool is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const; + bool is_transfer_unlocked(const transfer_details& td); + bool is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height); uint64_t get_last_block_reward() const { return m_last_block_reward; } uint64_t get_device_last_key_image_sync() const { return m_device_last_key_image_sync; } @@ -1301,13 +1301,15 @@ private: const boost::optional<epee::net_utils::http::login>& get_daemon_login() const { return m_daemon_login; } uint64_t get_daemon_blockchain_height(std::string& err); uint64_t get_daemon_blockchain_target_height(std::string& err); + uint64_t get_daemon_adjusted_time(); + /*! * \brief Calculates the approximate blockchain height from current date/time. */ uint64_t get_approximate_blockchain_height() const; uint64_t estimate_blockchain_height(); std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct); - std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const; + std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f); std::vector<size_t> select_available_unmixable_outputs(); std::vector<size_t> select_available_mixable_outputs(); @@ -1536,7 +1538,7 @@ private: void set_tx_notify(const std::shared_ptr<tools::Notify> ¬ify) { m_tx_notify = notify; } - bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const; + bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height); void hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const; uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const; void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash); @@ -1600,12 +1602,12 @@ private: std::vector<uint64_t> get_unspent_amounts_vector(bool strict); uint64_t get_dynamic_base_fee_estimate(); float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const; - std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const; + std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices); void set_spent(size_t idx, uint64_t height); void set_unspent(size_t idx); bool is_spent(const transfer_details &td, bool strict = true) const; bool is_spent(size_t idx, bool strict = true) const; - void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count); + void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct); void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, std::vector<uint64_t> &rct_offsets); bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const; diff --git a/tests/trezor/daemon.cpp b/tests/trezor/daemon.cpp index aba835ae2..dd9fd49ee 100644 --- a/tests/trezor/daemon.cpp +++ b/tests/trezor/daemon.cpp @@ -247,7 +247,7 @@ bool mock_daemon::run_main() if (m_start_zmq) { - if (!zmq_server.addTCPSocket("127.0.0.1", m_zmq_bind_port)) + if (!zmq_server.init_rpc("127.0.0.1", m_zmq_bind_port)) { MERROR("Failed to add TCP Socket (127.0.0.1:" << m_zmq_bind_port << ") to ZMQ RPC Server"); diff --git a/tests/trezor/trezor_tests.cpp b/tests/trezor/trezor_tests.cpp index 6a92868cf..972a588f3 100644 --- a/tests/trezor/trezor_tests.cpp +++ b/tests/trezor/trezor_tests.cpp @@ -139,7 +139,7 @@ int main(int argc, char* argv[]) // Bootstrapping common chain & accounts const uint8_t initial_hf = (uint8_t)get_env_long("TEST_MIN_HF", 12); - const uint8_t max_hf = (uint8_t)get_env_long("TEST_MAX_HF", 12); + const uint8_t max_hf = (uint8_t)get_env_long("TEST_MAX_HF", HF_VERSION_CLSAG); auto sync_test = get_env_long("TEST_KI_SYNC", 1); MINFO("Test versions " << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"); MINFO("Testing hardforks [" << (int)initial_hf << ", " << (int)max_hf << "], sync-test: " << sync_test); @@ -546,7 +546,7 @@ static void expand_tsx(cryptonote::transaction &tx) for (size_t n = 0; n < tx.vin.size(); ++n) rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); } - else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG) + else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2) { CHECK_AND_ASSERT_THROW_MES(rv.p.MGs.size() == tx.vin.size(), "Bad MGs size"); for (size_t n = 0; n < tx.vin.size(); ++n) @@ -555,6 +555,21 @@ static void expand_tsx(cryptonote::transaction &tx) rv.p.MGs[n].II[0] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); } } + else if (rv.type == rct::RCTTypeCLSAG) + { + if (!tx.pruned) + { + CHECK_AND_ASSERT_THROW_MES(rv.p.CLSAGs.size() == tx.vin.size(), "Bad CLSAGs size"); + for (size_t n = 0; n < tx.vin.size(); ++n) + { + rv.p.CLSAGs[n].I = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); + } + } + } + else + { + CHECK_AND_ASSERT_THROW_MES(false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type)); + } } static std::vector<tools::wallet2*> vct_wallets(tools::wallet2* w1=nullptr, tools::wallet2* w2=nullptr, tools::wallet2* w3=nullptr, tools::wallet2* w4=nullptr, tools::wallet2* w5=nullptr) @@ -708,7 +723,9 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events) std::vector<size_t> block_weights; generate_genesis_block(blk_gen, get_config(m_network_type).GENESIS_TX, get_config(m_network_type).GENESIS_NONCE); events.push_back(blk_gen); - generator.add_block(blk_gen, 0, block_weights, 0); + uint64_t rew = 0; + cryptonote::get_block_reward(0, get_transaction_weight(blk_gen.miner_tx), 0, rew, 1); + generator.add_block(blk_gen, 0, block_weights, 0, rew); // First event has to be the genesis block m_bob_account.generate(); @@ -926,7 +943,7 @@ void gen_trezor_base::fix_hf(std::vector<test_event_entry>& events) // If current test requires higher hard-fork, move it up auto current_hf = m_hard_forks.back().first; CHECK_AND_ASSERT_THROW_MES(current_hf <= m_top_hard_fork, "Generated chain hardfork is higher than desired maximum"); - CHECK_AND_ASSERT_THROW_MES(m_rct_config.bp_version != 2 || m_top_hard_fork >= 10, "Desired maximum is too low for BPv2"); + CHECK_AND_ASSERT_THROW_MES(m_rct_config.bp_version < 2 || m_top_hard_fork >= 10, "Desired maximum is too low for BPv2"); for(;current_hf < m_top_hard_fork; current_hf+=1) { @@ -1014,9 +1031,10 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std: setup_shim(&wallet_shim); aux_data.tx_recipients = dsts_info; aux_data.bp_version = m_rct_config.bp_version; + aux_data.hard_fork = m_top_hard_fork; dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data); - MDEBUG("Signed tx data from hw: " << exported_txs.ptx.size() << " transactions"); + MDEBUG("Signed tx data from hw: " << exported_txs.ptx.size() << " transactions, hf: " << (int)m_top_hard_fork << ", bpv: " << m_rct_config.bp_version); CHECK_AND_ASSERT_THROW_MES(exported_txs.ptx.size() == ptxs.size(), "Invalid transaction sizes"); for (size_t i = 0; i < exported_txs.ptx.size(); ++i){ @@ -1245,10 +1263,14 @@ void gen_trezor_base::set_hard_fork(uint8_t hf) m_top_hard_fork = hf; if (hf < 9){ throw std::runtime_error("Minimal supported Hardfork is 9"); - } else if (hf == 9){ + } else if (hf <= 11){ rct_config({rct::RangeProofPaddedBulletproof, 1}); - } else { + } else if (hf == 12){ rct_config({rct::RangeProofPaddedBulletproof, 2}); + } else if (hf == HF_VERSION_CLSAG){ + rct_config({rct::RangeProofPaddedBulletproof, 3}); + } else { + throw std::runtime_error("Unsupported HF"); } } @@ -1844,7 +1866,7 @@ bool wallet_api_tests::generate(std::vector<test_event_entry>& events) CHECK_AND_ASSERT_THROW_MES(w->refresh(), "Refresh fail"); uint64_t balance = w->balance(0); MDEBUG("Balance: " << balance); - CHECK_AND_ASSERT_THROW_MES(w->status() == Monero::PendingTransaction::Status_Ok, "Status nok"); + CHECK_AND_ASSERT_THROW_MES(w->status() == Monero::PendingTransaction::Status_Ok, "Status nok, " << w->errorString()); auto addr = get_address(m_eve_account); auto recepient_address = cryptonote::get_account_address_as_str(m_network_type, false, addr); @@ -1855,7 +1877,7 @@ bool wallet_api_tests::generate(std::vector<test_event_entry>& events) Monero::PendingTransaction::Priority_Medium, 0, std::set<uint32_t>{}); - CHECK_AND_ASSERT_THROW_MES(transaction->status() == Monero::PendingTransaction::Status_Ok, "Status nok"); + CHECK_AND_ASSERT_THROW_MES(transaction->status() == Monero::PendingTransaction::Status_Ok, "Status nok: " << transaction->status() << ", msg: " << transaction->errorString()); w->refresh(); CHECK_AND_ASSERT_THROW_MES(w->balance(0) == balance, "Err"); |