diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 0eceec42f..31089d3f4 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -40,6 +40,7 @@ #define CRYPTONOTE_MAX_TX_SIZE 1000000 #define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000 #define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0 +#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2 288 #define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60 #define CURRENT_TRANSACTION_VERSION 2 #define CURRENT_BLOCK_MAJOR_VERSION 7 @@ -184,6 +185,8 @@ #define HF_VERSION_EXACT_COINBASE 16 #define HF_VERSION_CLSAG 16 #define HF_VERSION_DETERMINISTIC_UNLOCK_TIME 16 +#define HF_VERSION_DYNAMIC_UNLOCK 16 +#define HF_VERSION_FIXED_UNLOCK 18 #define HF_VERSION_BULLETPROOF_PLUS 18 #define HF_VERSION_BLOCK_HEADER_MINER_SIG 18 #define HF_VERSION_VIEW_TAGS 20 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 31152228e..0b94588d0 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1380,7 +1380,18 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, return false; } MDEBUG("Miner tx hash: " << get_transaction_hash(b.miner_tx)); - CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW); + if (hf_version >= HF_VERSION_FIXED_UNLOCK) { + CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2, false, "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2); + } else if (hf_version < HF_VERSION_FIXED_UNLOCK && hf_version >= HF_VERSION_DYNAMIC_UNLOCK) { + uint64_t N = m_nettype == MAINNET ? 1337 : 5; + crypto::hash blk_id = get_block_id_by_height(height-N); + std::string hex_str = epee::string_tools::pod_to_hex(blk_id).substr(0, 3); + uint64_t blk_num = std::stol(hex_str,nullptr,16)*2; + uint64_t unlock_window = blk_num + 288; + CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + unlock_window, false, "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + unlock_window); + } else { + CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW); + } //check outs overflow if(!check_outs_overflow(b.miner_tx)) @@ -1751,7 +1762,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, //make blocks coin-base tx looks close to real coinbase tx to get truthful blob weight uint8_t hf_version = b.major_version; size_t max_outs = hf_version >= 4 ? 1 : 11; - bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); + bool r = construct_miner_tx(this, m_nettype, height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance"); size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) @@ -1760,7 +1771,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, #endif for (size_t try_count = 0; try_count != 10; ++try_count) { - r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); + r = construct_miner_tx(this, m_nettype, height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance"); size_t coinbase_weight = get_transaction_weight(b.miner_tx); diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 706ca238e..5363282a7 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -75,7 +75,7 @@ namespace cryptonote LOG_PRINT_L2("destinations include " << num_stdaddresses << " standard addresses and " << num_subaddresses << " subaddresses"); } //--------------------------------------------------------------- - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { + bool construct_miner_tx(const Blockchain *pb, network_type m_nettype, size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); @@ -171,7 +171,20 @@ namespace cryptonote tx.version = 1; //lock - tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + if (hard_fork_version >= HF_VERSION_FIXED_UNLOCK) + { + tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2; + } else if (hard_fork_version < HF_VERSION_FIXED_UNLOCK && hard_fork_version >= HF_VERSION_DYNAMIC_UNLOCK) + { + uint64_t N = m_nettype == MAINNET ? 1337 : 5; + crypto::hash blk_id = pb->get_block_id_by_height(height-N); + std::string hex_str = epee::string_tools::pod_to_hex(blk_id).substr(0, 3); + uint64_t blk_num = std::stol(hex_str,nullptr,16)*2; + uint64_t unlock_window = blk_num + 288; + tx.unlock_time = height + unlock_window; + } else { + tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + } tx.vin.push_back(in); tx.invalidate_hashes(); diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 5f301bb89..435d966f8 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -37,7 +37,8 @@ namespace cryptonote { //--------------------------------------------------------------- - bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1); + class Blockchain; + bool construct_miner_tx(const Blockchain *pb, network_type m_nettype, size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1); struct tx_source_entry { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3202e0d58..27d189e6a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -8326,8 +8326,8 @@ void wallet2::get_outs(std::vector> gamma.reset(new gamma_picker(rct_offsets)); size_t num_selected_transfers = 0; - req.outputs.reserve(selected_transfers.size() * (base_requested_outputs_count + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW)); - daemon_resp.outs.reserve(selected_transfers.size() * (base_requested_outputs_count + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW)); + req.outputs.reserve(selected_transfers.size() * (base_requested_outputs_count + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2)); + daemon_resp.outs.reserve(selected_transfers.size() * (base_requested_outputs_count + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2)); for(size_t idx: selected_transfers) { ++num_selected_transfers; @@ -8335,7 +8335,7 @@ void wallet2::get_outs(std::vector> const uint64_t amount = td.is_rct() ? 0 : td.amount(); std::unordered_set seen_indices; // request more for rct in base recent (locked) coinbases are picked, since they're locked for longer - size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); + size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2 - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); size_t start = req.outputs.size(); bool use_histogram = amount != 0; @@ -8668,7 +8668,7 @@ void wallet2::get_outs(std::vector> for(size_t idx: selected_transfers) { const transfer_details &td = m_transfers[idx]; - size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); + size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW_V2 - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); outs.push_back(std::vector()); outs.back().reserve(fake_outputs_count + 1); const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());