From ef27f6380e329730fe27b3a02771ec0665897c97 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Fri, 17 Nov 2023 17:43:21 +0000 Subject: [PATCH] updated to support propagation of the transaction type - this was necessary to distinguish between YIELD and TRANSFER type --- src/blockchain_db/blockchain_db.cpp | 20 +++ src/blockchain_db/lmdb/db_lmdb.cpp | 71 +++++++- src/blockchain_db/lmdb/db_lmdb.h | 5 +- src/cryptonote_basic/cryptonote_basic.h | 4 +- src/cryptonote_config.h | 4 + src/cryptonote_core/blockchain.cpp | 162 ++++++++++++++++++ src/cryptonote_core/blockchain.h | 29 ++++ src/cryptonote_core/cryptonote_tx_utils.cpp | 51 ++++-- src/cryptonote_core/cryptonote_tx_utils.h | 6 +- src/cryptonote_protocol/enums.h | 9 +- src/oracle/pricing_record.cpp | 13 ++ src/simplewallet/simplewallet.cpp | 40 ++++- src/simplewallet/simplewallet.h | 1 + src/wallet/wallet2.cpp | 31 ++-- src/wallet/wallet2.h | 25 ++- src/wallet/wallet_rpc_server.cpp | 4 +- src/wallet/wallet_rpc_server_commands_defs.h | 4 + tests/core_tests/block_validation.cpp | 4 +- tests/core_tests/bulletproof_plus.cpp | 2 +- tests/core_tests/bulletproofs.cpp | 2 +- tests/core_tests/chaingen.cpp | 2 +- tests/core_tests/double_spend.inl | 2 +- tests/core_tests/integer_overflow.cpp | 4 +- tests/core_tests/rct.cpp | 4 +- tests/core_tests/rct2.cpp | 2 +- tests/core_tests/transaction_tests.cpp | 2 +- tests/core_tests/v2_tests.cpp | 2 +- tests/core_tests/wallet_tools.cpp | 2 +- .../transactions_flow_test.cpp | 2 +- tests/performance_tests/check_tx_signature.h | 6 +- tests/performance_tests/construct_tx.h | 2 +- .../performance_tests/ge_frombytes_vartime.h | 2 +- tests/performance_tests/ge_tobytes.h | 2 +- tests/unit_tests/json_serialization.cpp | 2 +- 34 files changed, 445 insertions(+), 78 deletions(-) diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index 2553fe3..f261e74 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -277,6 +277,8 @@ uint64_t BlockchainDB::add_block( const std::pair& blck oracle::asset_type_counts num_rct_outs_by_asset_type; blobdata miner_bd = tx_to_blob(blk.miner_tx); add_transaction(blk_hash, std::make_pair(blk.miner_tx, blobdata_ref(miner_bd))); + blobdata protocol_bd = tx_to_blob(blk.protocol_tx); + add_transaction(blk_hash, std::make_pair(blk.protocol_tx, blobdata_ref(protocol_bd))); if (blk.miner_tx.version == 2) { @@ -291,6 +293,19 @@ uint64_t BlockchainDB::add_block( const std::pair& blck } } + if (blk.protocol_tx.version == 2) + { + num_rct_outs += blk.protocol_tx.vout.size(); + + // count the current block's rct outs by asset type + for (auto& vout: blk.protocol_tx.vout) { + std::string asset_type; + if (!get_output_asset_type(vout, asset_type)) + throw std::runtime_error("Failed to get output asset type"); + num_rct_outs_by_asset_type.add(asset_type, 1); + } + } + int tx_i = 0; crypto::hash tx_hash = crypto::null_hash; for (const std::pair& tx : txs) @@ -344,6 +359,7 @@ void BlockchainDB::pop_block(block& blk, std::vector& txs) txs.push_back(std::move(tx)); remove_transaction(h); } + remove_transaction(get_transaction_hash(blk.protocol_tx)); remove_transaction(get_transaction_hash(blk.miner_tx)); } @@ -364,6 +380,10 @@ void BlockchainDB::remove_transaction(const crypto::hash& tx_hash) } } + // Check for yield_tx entries + if (tx.type == cryptonote::transaction_type::YIELD) { + } + const bool miner_tx = tx.vin.size() == 1 && tx.vin[0].type() == typeid(txin_gen); // need tx as tx.vout has the tx outputs, and the output amounts are needed diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 9f0d84f..d5c661f 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -211,6 +211,8 @@ namespace * * alt_blocks block hash {block data, block blob} * + * yield_txs block height {txn hash, dest address, amount} + * * Note: where the data items are of uniform size, DUPFIXED tables have * been used to save space. In most of these cases, a dummy "zerokval" * key is used when accessing the table; the Key listed above will be @@ -249,6 +251,35 @@ const char* const LMDB_PROPERTIES = "properties"; const char* const LMDB_CIRC_SUPPLY = "circ_supply"; const char* const LMDB_CIRC_SUPPLY_TALLY = "circ_supply_tally"; + /** + * We have the following information that will go into a table in the blockchain: + * block_height (this is the key field) + * ----------------------------------------- + * txn_hash (so we can verify) + * dest_address (where to send the yield) + * amount (how much was locked) + * + * + * If we only allow a 30-day (actually 21,600 block) lock, and no variation on that period, then the code + * to identify locks that are earning yield in a given block is probably pretty simple. It gets a LOT more + * complicated if you can lock for a variable period, of course. + * + * So, let's say that we have a block height h for which we want to assess the yield payments. First off, + * we are ONLY interested in making ANY payment if we have YIELD.block_height == h + 21600 (i.e. the yield + * TX has matured). + * + * Now, to calculate the payable yield, we need to know: + * # how much slippage accrued in each of the last 21600 blocks + * (call this slippage_amounts, which is a vector of slippage_height and slippage_amount tuples) + * # the list of all yield TXs that fulfil the criteria + * (YIELD.block_height > (h - 21600)) and (YIELD.block_height <= h) (call this yield_txs) + * + * Given this information, we would sort yield_txs by block_height. Then we iterate over slippage_amounts, + * and for each entry, we look to see which of the yield_txs overlaps the height for the given slippage_height. + * This allows us to work out the % of the slippage_amount that should be paid to the maturing yield TX. + */ +const char* const LMDB_YIELD_TXS = "yield_txs"; + const char zerokey[8] = {0}; const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey }; @@ -350,7 +381,13 @@ typedef struct circ_supply_tally { uint64_t amount_hi; uint64_t amount_lo; } circ_supply_tally; - + +typedef struct yield_tx_data { + crypto::hash tx_hash; + crypto::public_key destination_address; + uint64_t amount; +} yield_tx_data; + std::atomic mdb_txn_safe::num_active_txns{0}; std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT; @@ -973,6 +1010,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons CURSOR(tx_indices) CURSOR(circ_supply) CURSOR(circ_supply_tally) + CURSOR(yield_txs) MDB_val_set(val_tx_id, tx_id); MDB_val_set(val_h, tx_hash); @@ -1085,6 +1123,20 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons "\nDest tally before mint =" << dest_tally.str() << "\nDest tally after mint =" << final_dest_tally.str()); } + // Is there yield_tx data to add? + if (tx.type == cryptonote::transaction_type::YIELD) { + // Create the object we are going to write to the database + yield_tx_data yield_data; + yield_data.tx_hash = tx_hash; + yield_data.destination_address = tx.destination_address; + yield_data.amount = tx.amount_burnt; // SRCG - this feels as though we are bastardising the variable for an invalid purpose + MDB_val_set(val_height, m_height); + MDB_val_set(val_yield_tx_data, yield_data); + result = mdb_cursor_put(m_cur_yield_txs, &val_height, &val_yield_tx_data, MDB_APPEND); + if (result) + throw0(DB_ERROR( lmdb_error("Failed to add tx yield data to db transaction: ", result).c_str() )); + } + return tx_id; } @@ -1107,6 +1159,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const CURSOR(tx_outputs) CURSOR(circ_supply) CURSOR(circ_supply_tally) + CURSOR(yield_txs) MDB_val_set(val_h, tx_hash); @@ -1213,6 +1266,22 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str())); } + // Is there yield_tx data to remove? + if (tx.type == cryptonote::transaction_type::YIELD) { + // Remove any yield_tx data for this transaction + result = mdb_cursor_get(m_cur_yield_txs, &val_tx_id, NULL, MDB_SET); + if (result == MDB_NOTFOUND) + LOG_PRINT_L1("tx has no yield_tx data to remove: " << tx_hash); + else if (result) + throw1(DB_ERROR(lmdb_error("Failed to locate yield_tx data for removal: ", result).c_str())); + if (!result) + { + result = mdb_cursor_del(m_cur_yield_txs, 0); + if (result) + throw1(DB_ERROR(lmdb_error("Failed to add removal of yield_tx data to db transaction: ", result).c_str())); + } + } + // Don't delete the tx_indices entry until the end, after we're done with val_tx_id if (mdb_cursor_del(m_cur_tx_indices, 0)) throw1(DB_ERROR("Failed to add removal of tx index to db transaction")); diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index e7ed1c2..e080258 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -76,6 +76,7 @@ typedef struct mdb_txn_cursors MDB_cursor *m_txc_circ_supply; MDB_cursor *m_txc_circ_supply_tally; + MDB_cursor *m_txc_yield_txs; } mdb_txn_cursors; @@ -98,9 +99,9 @@ typedef struct mdb_txn_cursors #define m_cur_alt_blocks m_cursors->m_txc_alt_blocks #define m_cur_hf_versions m_cursors->m_txc_hf_versions #define m_cur_properties m_cursors->m_txc_properties - #define m_cur_circ_supply m_cursors->m_txc_circ_supply #define m_cur_circ_supply_tally m_cursors->m_txc_circ_supply_tally +#define m_cur_yield_txs m_cursors->m_txc_yield_txs typedef struct mdb_rflags { @@ -126,6 +127,7 @@ typedef struct mdb_rflags bool m_rf_properties; bool m_rf_circ_supply; bool m_rf_circ_supply_tally; + bool m_rf_yield_txs; } mdb_rflags; typedef struct mdb_threadinfo @@ -484,6 +486,7 @@ private: MDB_dbi m_circ_supply; MDB_dbi m_circ_supply_tally; + MDB_dbi m_yield_txs; mutable uint64_t m_cum_size; // used in batch size estimation mutable unsigned int m_cum_count; diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index 30037fd..a41bfab 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -198,7 +198,7 @@ namespace cryptonote //extra std::vector extra; // TX type - uint8_t type; + cryptonote::transaction_type type; // Destination address (encrypted) crypto::public_key destination_address; // Source asset type @@ -234,7 +234,7 @@ namespace cryptonote vin.clear(); vout.clear(); extra.clear(); - type = static_cast(cryptonote::transaction_type::TRANSFER); + type = cryptonote::transaction_type::TRANSFER; destination_address = crypto::null_pkey; source_asset_type.clear(); destination_asset_type.clear(); diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 0c5b335..1d3cd69 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -55,6 +55,10 @@ #define EMISSION_SPEED_FACTOR_PER_MINUTE (19) #define FINAL_SUBSIDY_PER_MINUTE ((uint64_t)30000000) // 3 * pow(10, 7) +#define BURN_LOCK_PERIOD 0 +#define CONVERT_LOCK_PERIOD 0 +#define YIELD_LOCK_PERIOD 30*24*30 + #define CRYPTONOTE_REWARD_BLOCKS_WINDOW 100 #define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 60000 //size of block (bytes) after which reward for block calculated using block size #define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 20000 //size of block (bytes) after which reward for block calculated using block size - before first fork diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 1760f53..8749917 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -38,6 +38,7 @@ #include "cryptonote_basic/cryptonote_basic_impl.h" #include "tx_pool.h" #include "blockchain.h" +#include "blockchain_db/locked_txn.h" #include "blockchain_db/blockchain_db.h" #include "cryptonote_basic/cryptonote_boost_serialization.h" #include "cryptonote_config.h" @@ -1399,6 +1400,45 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, return true; } //------------------------------------------------------------------ +// This function does a sanity check on basic things that all protocol +// transactions have in common, such as: +// one input, of type txin_gen, with height set to the block's height +// valid output types +bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version) +{ + LOG_PRINT_L3("Blockchain::" << __func__); + CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs"); + CHECK_AND_ASSERT_MES(b.protocol_tx.vin[0].type() == typeid(txin_gen), false, "coinbase protocol transaction in the block has the wrong type"); + CHECK_AND_ASSERT_MES(b.protocol_tx.version > 1, false, "Invalid coinbase protocol transaction version"); + + // for v2 txes (ringct), we only accept empty rct signatures for protocol transactions, + if (hf_version >= HF_VERSION_REJECT_SIGS_IN_COINBASE && b.protocol_tx.version >= 2) + { + CHECK_AND_ASSERT_MES(b.protocol_tx.rct_signatures.type == rct::RCTTypeNull, false, "RingCT signatures not allowed in coinbase protocol transactions"); + } + + if(boost::get(b.protocol_tx.vin[0]).height != height) + { + MWARNING("The protocol transaction in block has invalid height: " << boost::get(b.protocol_tx.vin[0]).height << ", expected: " << height); + return false; + } + MDEBUG("Protocol tx hash: " << get_transaction_hash(b.protocol_tx)); + //CHECK_AND_ASSERT_MES(b.protocol_tx.unlock_time == height, false, "coinbase protocol transaction transaction has the wrong unlock time=" << b.protocol_tx.unlock_time << ", expected " << height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW); + + // SRCG - we still need to make output checks + /* + //check outs overflow + if(!check_outs_overflow(b.protocol_tx)) + { + MERROR("protocol transaction has money overflow in block " << get_block_hash(b)); + return false; + } + + CHECK_AND_ASSERT_MES(check_output_types(b.miner_tx, hf_version), false, "miner transaction has invalid output type(s) in block " << get_block_hash(b)); + */ + return true; +} +//------------------------------------------------------------------ // This function validates the miner transaction reward bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_weight, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version) { @@ -1427,7 +1467,98 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl } return true; } +//------------------------------------------------------------------ // SRCG +bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, std::vector>& txs, const std::map& circ_supply, uint8_t hf_version) +{ + LOG_PRINT_L3("Blockchain::" << __func__); + CHECK_AND_ASSERT_MES(b.tx_hashes.size() == txs.size(), false, "Invalid number of TXs / hashes supplied"); + + key_images_container keys; + + uint64_t fee_summary = 0; + uint64_t t_checktx = 0; + uint64_t t_exists = 0; + uint64_t t_pool = 0; + uint64_t t_dblspnd = 0; + uint64_t n_pruned = 0; + + // Build a map of outputs from the protocol_tx + std::map> outputs; + for (auto& o : b.protocol_tx.vout) { + if (o.target.type() == typeid(txout_to_key)) { + txout_to_key out = boost::get(o.target); + outputs[out.key] = {out.asset_type, o.amount, out.unlock_time}; + } else if (o.target.type() == typeid(txout_to_tagged_key)) { + txout_to_tagged_key out = boost::get(o.target); + outputs[out.key] = {out.asset_type, o.amount, out.unlock_time}; + } else { + MERROR("Block at height: " << height << " attempting to add protocol transaction with invalid type " << o.target.type().name()); + return false; + } + } + + size_t tx_index = 0; + // Iterate over the block's transaction hashes, grabbing each + // from the tx_pool and validating them. + for (const auto& tx_tmp : txs) + { + // Get a ptr to the TX to simplify coding + const transaction* tx = &tx_tmp.first; + + // Check to see if the TX exists in the DB - this probably duplicates the effort in our caller, but better to be sure + if (m_db->tx_exists(tx->hash)) + { + MERROR("Block at height: " << height << " attempting to add transaction already in blockchain with id: " << tx->hash); + return false; + } + + // Check to see if the TX is a conversion or not + if (tx->type != cryptonote::transaction_type::CONVERT) { + // Only conversion (and failed conversion, aka refund) TXs need to be verified - skip this TX + continue; + } + + // Verify that the TX has an output in the protocol_tx to verify + if (outputs.count(tx->destination_address) != 1) { + LOG_ERROR("Failed to locate output for conversion TX id " << tx->hash << " - rejecting block"); + return false; + } + + // Get the output information + std::string output_asset_type; + uint64_t output_amount; + uint64_t output_unlock_time; + std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[tx->destination_address]; + + // Verify the asset_type + if (tx->source_asset_type == output_asset_type) { + // Check the amount for REFUND + if (tx->amount_burnt != output_amount) { + LOG_ERROR("Output amount does not match amount_burnt for refunded TX id " << tx->hash << " - rejecting block"); + return false; + } + } else if (tx->destination_asset_type == output_asset_type) { + // Check the amount for CONVERT + + // Verify the amount of the conversion + uint64_t amount_minted_check = 0, amount_slippage_check = 0; + bool ok = cryptonote::calculate_conversion(tx->source_asset_type, tx->destination_asset_type, tx->amount_burnt, tx->amount_slippage_limit, amount_minted_check, amount_slippage_check, circ_supply, b.pricing_record, hf_version); + if (!ok) { + LOG_ERROR("Failed to calculate conversion for TX id " << tx->hash << " - rejecting block"); + return false; + } + if (amount_minted_check != output_amount) { + LOG_ERROR("Output amount does not match amount_burnt for refunded TX id " << tx->hash << " - rejecting block"); + return false; + } + } else { + LOG_ERROR("Output asset type incorrect: source " << tx->source_asset_type << ", dest " << tx->destination_asset_type << ", got " << output_asset_type << " - rejecting block"); + return false; + } + } + return false; +} //------------------------------------------------------------------ // get the block weights of the last blocks, and return by reference . void Blockchain::get_last_n_blocks_weights(std::vector& weights, size_t count) const @@ -2059,6 +2190,13 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id return false; } + if(!prevalidate_protocol_transaction(b, bei.height, hf_version)) + { + MERROR_VER("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative) has incorrect miner transaction."); + bvc.m_verifivation_failed = true; + return false; + } + // FIXME: // this brings up an interesting point: consider allowing to get block // difficulty both by height OR by hash, not just height. @@ -4283,6 +4421,14 @@ leave: goto leave; } + // sanity check basic protocol tx properties; + if(!prevalidate_protocol_transaction(bl, blockchain_height, hf_version)) + { + MERROR_VER("Block with id: " << id << " failed to pass protocol prevalidation"); + bvc.m_verifivation_failed = true; + goto leave; + } + size_t coinbase_weight = get_transaction_weight(bl.miner_tx); size_t cumulative_block_weight = coinbase_weight; @@ -4431,6 +4577,22 @@ leave: } TIME_MEASURE_FINISH(vmt); + + TIME_MEASURE_START(gcs); + std::map circ_supply = get_db().get_circulating_supply(); + TIME_MEASURE_FINISH(gcs); + + TIME_MEASURE_START(vpt); + if(!validate_protocol_transaction(bl, blockchain_height, txs, circ_supply, m_hardfork->get_current_version())) + { + MERROR_VER("Block with id: " << id << " has incorrect protocol transaction"); + bvc.m_verifivation_failed = true; + return_tx_to_pool(txs); + goto leave; + } + + TIME_MEASURE_FINISH(vpt); + size_t block_weight; difficulty_type cumulative_difficulty; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 3a51e2d..25d588c 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1420,6 +1420,20 @@ namespace cryptonote */ bool prevalidate_miner_transaction(const block& b, uint64_t height, uint8_t hf_version); + /** + * @brief sanity checks a protocol transaction before validating an entire block + * + * This function merely checks basic things like the structure of the protocol + * transaction, the unlock time, and that the amount doesn't overflow. + * + * @param b the block containing the protocol transaction + * @param height the height at which the block will be added + * @param hf_version the consensus rules to apply + * + * @return false if anything is found wrong with the protocol transaction, otherwise true + */ + bool prevalidate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version); + /** * @brief validates a miner (coinbase) transaction * @@ -1438,6 +1452,21 @@ namespace cryptonote */ bool validate_miner_transaction(const block& b, size_t cumulative_block_weight, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version); + /** + * @brief validates a protocol (coinbase) transaction + * + * This function makes sure that the protocol rules are being implemented correctly + * and that the conversions and yield payouts match what is expected. + * + * @param b the block containing the miner transaction to be validated + * @param height the blockchain's weight + * @param txs a vector containing all the TXs and their blobs, needed to obtain tx_types, asset_types and burnt amounts + * @param version hard fork version for that transaction + * + * @return false if anything is found wrong with the protocol transaction, otherwise true + */ + bool validate_protocol_transaction(const block& b, uint64_t height, std::vector>& txs, const std::map& circ_supply, uint8_t hf_version); + /** * @brief reverts the blockchain to its previous state following a failed switch * diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index c4f0685..1a1bef9 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -141,10 +141,13 @@ namespace cryptonote bool ok = get_conversion_rate(pr, source_asset, dest_asset, conversion_rate); CHECK_AND_ASSERT_MES(ok, false, "Unable to get conversion rate for " << source_asset << " to " << dest_asset); + // Apply slippage to the burnt amount + amount_slippage = amount_burnt >> 5; // (1/32) + if (hf_version >= HF_VERSION_SLIPPAGE_YIELD) { // Apply slippage to the burnt amount - amount_slippage = 0; + amount_slippage = amount_burnt >> 5; // (1/32) // Check that the slippage is acceptable if (amount_slippage > amount_slippage_limit) { @@ -173,14 +176,20 @@ namespace cryptonote // Clear the TX contents tx.set_null(); + // Force the TX type to 2 + tx.version = 2; + + // Clear the unlock_time + tx.unlock_time = 0; + + // Force the TX type to "special" (0) + tx.type = cryptonote::transaction_type::UNSET; + keypair txkey = keypair::generate(hw::get_device("default")); add_tx_pub_key_to_extra(tx, txkey.pub); if (!sort_tx_extra(tx.extra, tx.extra)) return false; - txin_gen in; - in.height = height; - // Update the circulating_supply information, while keeping a count of amount to be created using txin_gen std::map txin_gen_totals; uint64_t txin_gen_final = 0; @@ -194,6 +203,7 @@ namespace cryptonote } // Calculate the slippage for the output amounts + LOG_PRINT_L2("Creating protocol_tx..."); for (auto const& entry: protocol_data) { if (entry.destination_asset == "") { // BURN TX - no slippage, no money minted - skip @@ -209,6 +219,7 @@ namespace cryptonote if (amount_minted == 0) { // REFUND + LOG_PRINT_L2("Conversion TX refunded - slippage too high"); txin_gen_totals[entry.source_asset] += entry.amount_burnt; // Create the TX output for this refund @@ -218,6 +229,7 @@ namespace cryptonote } else { // CONVERTED + LOG_PRINT_L2("Conversion TX submitted - converted " << entry.amount_burnt << entry.source_asset << " to " << amount_minted << entry.destination_asset << "(slippage " << amount_slippage << ")"); txin_gen_totals[entry.destination_asset] += amount_minted; // Create the TX output for this conversion @@ -229,10 +241,13 @@ namespace cryptonote } // TODO: create the YIELD outputs - - // TODO: sum the txin_gen_totals values so that we know how much we are going to include in the protocol TX - - return false; + + // Create the txin_gen now + txin_gen in; + in.height = height; + tx.vin.push_back(in); + + return true; } //--------------------------------------------------------------- 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) { @@ -396,6 +411,7 @@ namespace cryptonote const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, + const transaction_type& tx_type, const boost::optional& change_addr, const std::vector &extra, transaction& tx, @@ -430,17 +446,14 @@ namespace cryptonote tx.extra = extra; crypto::public_key txkey_pub; - transaction_type tx_type; - if (!get_tx_type(source_asset, dest_asset, tx_type)) { - LOG_ERROR("invalid tx type"); - return false; - } - tx.type = static_cast(tx_type); + tx.type = tx_type; // Is this a CONVERT tx? if (tx_type == cryptonote::transaction_type::CONVERT) { // Set the destination address to be something only our wallet can identify - // This is where Fulmo gets interesting... + // This is where Fulmo gets interesting... we need to include the input key images + // so that we get uniqueness and prevent either Monero burning bug or key leakage. + // tx.d_a = Hs("convert" || input_key_images || 8rAG) + B tx.destination_address = get_destination_view_key_pub(destinations, change_addr); } @@ -875,7 +888,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool use_view_tags) + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const transaction_type& tx_type, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool use_view_tags) { hw::device &hwdev = sender_account_keys.get_device(); hwdev.open_tx(tx_key); @@ -896,7 +909,7 @@ namespace cryptonote } bool shuffle_outs = true; - bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, hf_version, source_asset, dest_asset, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags); + bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, hf_version, source_asset, dest_asset, tx_type, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags); hwdev.close_tx(); return r; } catch(...) { @@ -905,14 +918,14 @@ namespace cryptonote } } //--------------------------------------------------------------- - bool construct_tx(const account_keys& sender_account_keys, std::vector& sources, const std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time) + bool construct_tx(const account_keys& sender_account_keys, std::vector& sources, const std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time) { std::unordered_map subaddresses; subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0}; crypto::secret_key tx_key; std::vector additional_tx_keys; std::vector destinations_copy = destinations; - return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, hf_version, source_asset, dest_asset, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}); + return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, hf_version, source_asset, dest_asset, tx_type, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}); } //--------------------------------------------------------------- bool generate_genesis_block( diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 93fd232..0f3d502 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -150,9 +150,9 @@ namespace cryptonote //--------------------------------------------------------------- crypto::public_key get_destination_view_key_pub(const std::vector &destinations, const boost::optional& change_addr); - bool construct_tx(const account_keys& sender_account_keys, std::vector &sources, const std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false); - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false); + bool construct_tx(const account_keys& sender_account_keys, std::vector &sources, const std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time); + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false); + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional& change_addr, const std::vector &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false); bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, const cryptonote::tx_destination_entry &dst_entr, const boost::optional &change_addr, const size_t output_index, const bool &need_additional_txkeys, const std::vector &additional_tx_keys, diff --git a/src/cryptonote_protocol/enums.h b/src/cryptonote_protocol/enums.h index b26626e..17f9ec9 100644 --- a/src/cryptonote_protocol/enums.h +++ b/src/cryptonote_protocol/enums.h @@ -43,11 +43,12 @@ namespace cryptonote block //!< Received in block, takes precedence over others }; - enum class transaction_type : std::uint8_t + enum transaction_type { UNSET = 0, - TRANSFER, - CONVERT, - BURN + TRANSFER = 1, + CONVERT = 2, + BURN = 3, + YIELD = 4 }; } diff --git a/src/oracle/pricing_record.cpp b/src/oracle/pricing_record.cpp index 5794629..aa2c958 100644 --- a/src/oracle/pricing_record.cpp +++ b/src/oracle/pricing_record.cpp @@ -27,6 +27,7 @@ // // Portions of this code based upon code Copyright (c) 2019, The Monero Project +#include #include "pricing_record.h" #include "serialization/keyvalue_serialization.h" @@ -116,6 +117,18 @@ namespace oracle ::memcpy(signature, orig.signature, sizeof(signature)); return *this; } + + uint64_t pricing_record::operator[](const std::string& asset_type) const + { + if (asset_type == "FULM") return spot; + if (asset_type == "FUSD") { + boost::multiprecision::uint128_t exchange_128 = COIN; + exchange_128 *= COIN; + exchange_128 /= spot; + return exchange_128.convert_to(); + } + return 0; + } bool pricing_record::equal(const pricing_record& other) const noexcept { diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 6fbc815..570c653 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -161,6 +161,7 @@ enum TransferType { TransferLocked, Convert, Burn, + LockForYield }; static std::string get_human_readable_timespan(std::chrono::seconds seconds); @@ -208,6 +209,7 @@ namespace const char* USAGE_SWEEP_SINGLE("sweep_single [] [] [outputs=]
[]"); const char* USAGE_BURN("burn "); const char* USAGE_CONVERT("convert [index=[,,...]] [] [] ( |
) []"); + const char* USAGE_LOCK_FOR_YIELD("lock_for_yield "); const char* USAGE_PRICE_INFO("price_info"); const char* USAGE_SUPPLY_INFO("supply_info"); const char* USAGE_YIELD_INFO("yield_info"); @@ -3152,6 +3154,7 @@ bool simple_wallet::help(const std::vector &args/* = std::vector []\" - Send FULM or F$ to an address."); message_writer() << tr("\"burn \" - destroy coins forever."); message_writer() << tr("\"convert
\" - convert between coin types and send to address."); + message_writer() << tr("\"lock_for_tield \" - lock FULM in order to earn yield."); message_writer() << tr("\"price_info\" - Display current pricing information for supported assets."); message_writer() << tr("\"supply_info\" - Display circulating supply information."); message_writer() << tr("\"yield_info\" - Display current stats on Fulmo yield."); @@ -3336,6 +3339,10 @@ simple_wallet::simple_wallet() boost::bind(&simple_wallet::convert, this, _1), tr(USAGE_CONVERT), tr("Converts into , with optional [0-5]")); + m_cmd_binder.set_handler("lock_for_yield", + boost::bind(&simple_wallet::lock_for_yield, this, _1), + tr(USAGE_LOCK_FOR_YIELD), + tr("Locks of FULM in order to earn yield")); m_cmd_binder.set_handler("price_info", boost::bind(&simple_wallet::price_info, this, _1), tr(USAGE_PRICE_INFO), @@ -6789,6 +6796,18 @@ bool simple_wallet::transfer_main( std::string err; switch (transfer_type) { + case Burn: + unlock_block = 0; + ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::BURN, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices); + break; + case Convert: + unlock_block = CONVERT_LOCK_PERIOD; + ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::CONVERT, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices); + break; + case LockForYield: + unlock_block = YIELD_LOCK_PERIOD; + ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::YIELD, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices); + break; case TransferLocked: bc_height = get_daemon_blockchain_height(err); if (!err.empty()) @@ -6797,13 +6816,13 @@ bool simple_wallet::transfer_main( return false; } unlock_block = bc_height + locked_blocks; - ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices); + ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices); break; default: LOG_ERROR("Unknown transfer method, using default"); /* FALLTHRU */ case Transfer: - ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices); + ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices); break; } @@ -7904,6 +7923,23 @@ bool simple_wallet::convert(const std::vector &args_) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::lock_for_yield(const std::vector &args_) +{ + // TODO: add locked versions + if (args_.size() != 1) + { + PRINT_USAGE(USAGE_LOCK_FOR_YIELD); + return true; + } + + std::vector local_args; + local_args.push_back(m_wallet->get_subaddress_as_str({m_current_subaddress_account,0})); + local_args.insert(local_args.end(), args_.begin(), args_.end()); + + transfer_main(LockForYield, "FULM", "FULM", local_args, false); + return true; +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::price_info(const std::vector &args) { // get circulating supply std::vector> supply_amounts; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index fae079f..1bd1a8b 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -182,6 +182,7 @@ namespace cryptonote bool sweep_unmixable(const std::vector &args); bool burn(const std::vector &args); bool convert(const std::vector &args); + bool lock_for_yield(const std::vector &args); bool price_info(const std::vector &args); bool supply_info(const std::vector &args); bool yield_info(const std::vector &args); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4fc0aa5..ebaa01e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6907,7 +6907,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector> circ_amounts; - bool b = false; + std::vector> circ_amounts; + bool b = false; // Now perform all sanity checks specific to each tx type switch (tx_type) { @@ -10594,7 +10594,7 @@ std::vector wallet2::create_transactions_2( LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " << tx.selected_transfers.size() << " inputs"); transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, - test_tx, test_ptx, rct_config, use_view_tags, source_asset, dest_asset, pricing_record); + test_tx, test_ptx, rct_config, use_view_tags, source_asset, dest_asset, tx_type, pricing_record); auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask); available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0); @@ -10615,7 +10615,7 @@ std::vector wallet2::create_transactions_2( LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee)); while (needed_fee > test_ptx.fee) { transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, - test_tx, test_ptx, rct_config, use_view_tags, source_asset, dest_asset, pricing_record); + test_tx, test_ptx, rct_config, use_view_tags, source_asset, dest_asset, tx_type, pricing_record); txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask); LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) << @@ -10689,6 +10689,7 @@ skip_tx: use_view_tags, /* const bool use_view_tags */ source_asset, dest_asset, + tx_type, pricing_record); auto txBlob = t_serializable_object_to_blob(test_ptx.tx); tx.tx = test_tx; @@ -10987,7 +10988,7 @@ std::vector wallet2::create_transactions_from(const crypton tx.selected_transfers.size() << " outputs"); if (use_rct) transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, - test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, oracle::pricing_record()); + test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, cryptonote::transaction_type::TRANSFER, oracle::pricing_record()); else transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); @@ -11024,7 +11025,7 @@ std::vector wallet2::create_transactions_from(const crypton } if (use_rct) transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, - test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, oracle::pricing_record()); + test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, cryptonote::transaction_type::TRANSFER, oracle::pricing_record()); else transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); @@ -11063,7 +11064,7 @@ std::vector wallet2::create_transactions_from(const crypton pending_tx test_ptx; if (use_rct) { transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra, - test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, oracle::pricing_record()); + test_tx, test_ptx, rct_config, use_view_tags, asset_type, asset_type, cryptonote::transaction_type::TRANSFER, oracle::pricing_record()); } else { transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0048e53..d41af8c 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -553,6 +553,7 @@ private: std::vector selected_transfers; std::vector extra; uint64_t unlock_time; + cryptonote::transaction_type tx_type; bool use_rct; rct::RCTConfig rct_config; bool use_view_tags; @@ -1062,12 +1063,22 @@ private: void transfer_selected(const std::vector& dsts, const std::vector& selected_transfers, size_t fake_outputs_count, std::vector> &outs, std::unordered_set &valid_public_keys_cache, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx, const bool use_view_tags); - void transfer_selected_rct(std::vector dsts, const std::vector& selected_transfers, size_t fake_outputs_count, - std::vector> &outs, std::unordered_set &valid_public_keys_cache, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, const bool use_view_tags, - const std::string& source_asset, - const std::string& dest_asset, - const oracle::pricing_record& pr); + void transfer_selected_rct(std::vector dsts, + const std::vector& selected_transfers, + size_t fake_outputs_count, + std::vector> &outs, + std::unordered_set &valid_public_keys_cache, + uint64_t unlock_time, + uint64_t fee, + const std::vector& extra, + cryptonote::transaction& tx, + pending_tx &ptx, + const rct::RCTConfig &rct_config, + const bool use_view_tags, + const std::string& source_asset, + const std::string& dest_asset, + const cryptonote::transaction_type& tx_type, + const oracle::pricing_record& pr); void commit_tx(pending_tx& ptx_vector); void commit_tx(std::vector& ptx_vector); @@ -1089,7 +1100,7 @@ private: bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const; bool load_tx(const std::string &signed_filename, std::vector &ptx, std::function accept_func = NULL); bool parse_tx_from_str(const std::string &signed_tx_st, std::vector &ptx, std::function accept_func); - std::vector create_transactions_2(std::vector dsts, const std::string& source_asset, const std::string& dest_asset, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices); // pass subaddr_indices by value on purpose + std::vector create_transactions_2(std::vector dsts, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices); // pass subaddr_indices by value on purpose std::vector create_transactions_all(uint64_t below, const std::string &asset_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices); std::vector create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra); std::vector create_transactions_from(const cryptonote::account_public_address &address, const std::string &asset_type, bool is_subaddress, const size_t outputs, std::vector unused_transfers_indices, std::vector unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d4aaaa6..19de3dd 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -1080,7 +1080,7 @@ namespace tools { uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); - std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); + std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, static_cast(req.tx_type), mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); if (ptx_vector.empty()) { @@ -1135,7 +1135,7 @@ namespace tools uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); LOG_PRINT_L2("on_transfer_split calling create_transactions_2"); - std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); + std::vector ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, static_cast(req.tx_type), mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); LOG_PRINT_L2("on_transfer_split called create_transactions_2"); if (ptx_vector.empty()) diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index ea697c5..23e3afa 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -537,6 +537,7 @@ namespace wallet_rpc std::list destinations; std::string source_asset; std::string dest_asset; + uint8_t tx_type; uint32_t account_index; std::set subaddr_indices; uint32_t priority; @@ -552,6 +553,7 @@ namespace wallet_rpc KV_SERIALIZE(destinations) KV_SERIALIZE(source_asset) KV_SERIALIZE(dest_asset) + KV_SERIALIZE(tx_type) KV_SERIALIZE(account_index) KV_SERIALIZE(subaddr_indices) KV_SERIALIZE(priority) @@ -602,6 +604,7 @@ namespace wallet_rpc std::list destinations; std::string source_asset; std::string dest_asset; + uint8_t tx_type; uint32_t account_index; std::set subaddr_indices; uint32_t priority; @@ -617,6 +620,7 @@ namespace wallet_rpc KV_SERIALIZE(destinations) KV_SERIALIZE(source_asset) KV_SERIALIZE(dest_asset) + KV_SERIALIZE(tx_type) KV_SERIALIZE(account_index) KV_SERIALIZE(subaddr_indices) KV_SERIALIZE(priority) diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index ffe51cf..7c05b49 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -350,7 +350,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector& events destinations.push_back(de); transaction tmp_tx; - if (!construct_tx(miner_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), tmp_tx, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), tmp_tx, 0)) return false; MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); @@ -393,7 +393,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector destinations.push_back(de); transaction tmp_tx; - if (!construct_tx(miner_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), tmp_tx, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), tmp_tx, 0)) return false; MAKE_MINER_TX_MANUALLY(miner_tx, blk_1); diff --git a/tests/core_tests/bulletproof_plus.cpp b/tests/core_tests/bulletproof_plus.cpp index 9cf04c4..d600b4f 100644 --- a/tests/core_tests/bulletproof_plus.cpp +++ b/tests/core_tests/bulletproof_plus.cpp @@ -138,7 +138,7 @@ bool gen_bpp_tx_validation_base::generate_with(std::vector& ev rct_txes.resize(rct_txes.size() + 1); std::string source_asset = "FULM"; std::string dest_asset = "FULM"; - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::account_public_address{}, std::vector(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx && !post_tx(rct_txes.back(), n)) diff --git a/tests/core_tests/bulletproofs.cpp b/tests/core_tests/bulletproofs.cpp index ba11f67..1c93c4a 100644 --- a/tests/core_tests/bulletproofs.cpp +++ b/tests/core_tests/bulletproofs.cpp @@ -138,7 +138,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector& eve std::string dest_asset = "FULM"; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; rct_txes.resize(rct_txes.size() + 1); - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::account_public_address{}, std::vector(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx && !post_tx(rct_txes.back(), n)) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 07e2751..be63d0e 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1080,7 +1080,7 @@ bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std:: rct::RCTConfig rct_config = {range_proof_type, bp_version}; std::string source_asset = "FULM"; std::string dest_asset = "FULM"; - return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, 1/*hf_version*/, source_asset, dest_asset, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); + return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); } transaction construct_tx_with_fee(std::vector& events, const block& blk_head, diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl index dfc8f5d..7683e2b 100644 --- a/tests/core_tests/double_spend.inl +++ b/tests/core_tests/double_spend.inl @@ -144,7 +144,7 @@ bool gen_double_spend_in_tx::generate(std::vector(), tx_1, 0)) + if (!construct_tx(bob_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), tx_1, 0)) return false; SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0); diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp index 9535aca..41a359c 100644 --- a/tests/core_tests/integer_overflow.cpp +++ b/tests/core_tests/integer_overflow.cpp @@ -174,7 +174,7 @@ bool gen_uint_overflow_2::generate(std::vector& events) const destinations.push_back(tx_destination_entry(sources.front().amount - MONEY_SUPPLY - MONEY_SUPPLY + 1 - TESTS_DEFAULT_FEE, bob_addr, false)); cryptonote::transaction tx_1; - if (!construct_tx(miner_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), tx_1, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), tx_1, 0)) return false; events.push_back(tx_1); @@ -200,7 +200,7 @@ bool gen_uint_overflow_2::generate(std::vector& events) const destinations.push_back(de); cryptonote::transaction tx_2; - if (!construct_tx(bob_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), tx_2, 0)) + if (!construct_tx(bob_account.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), tx_2, 0)) return false; events.push_back(tx_2); diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 797d7eb..eee9d1c 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -124,7 +124,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector(), rct_txes[n], 0, tx_key, additional_tx_keys, true); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), rct_txes[n], 0, tx_key, additional_tx_keys, true); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); events.push_back(rct_txes[n]); starting_rct_tx_hashes.push_back(get_transaction_hash(rct_txes[n])); @@ -233,7 +233,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector(), tx, 0, tx_key, additional_tx_keys, true, rct_config, use_view_tags); + bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), tx, 0, tx_key, additional_tx_keys, true, rct_config, use_view_tags); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx) diff --git a/tests/core_tests/rct2.cpp b/tests/core_tests/rct2.cpp index aa338ee..28ab0cd 100644 --- a/tests/core_tests/rct2.cpp +++ b/tests/core_tests/rct2.cpp @@ -138,7 +138,7 @@ bool gen_rct2_tx_validation_base::generate_with(std::vector& e rct_txes.resize(rct_txes.size() + 1); std::string source_asset = "FULM"; std::string dest_asset = "FULM"; - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::account_public_address{}, std::vector(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx && !post_tx(rct_txes.back(), n)) diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index 4f850ae..ed5e926 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -157,7 +157,7 @@ bool test_transaction_generation_and_ring_signature() destinations.push_back(td); transaction tx_rc1; - bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), tx_rc1, 0); + bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), tx_rc1, 0); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); crypto::hash pref_hash = get_transaction_prefix_hash(tx_rc1); diff --git a/tests/core_tests/v2_tests.cpp b/tests/core_tests/v2_tests.cpp index 4916a4b..9884384 100644 --- a/tests/core_tests/v2_tests.cpp +++ b/tests/core_tests/v2_tests.cpp @@ -107,7 +107,7 @@ bool gen_v2_tx_validation_base::generate_with(std::vector& eve destinations.push_back(td); transaction tx; - bool r = construct_tx(miner_accounts[0].get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), tx, 0); + bool r = construct_tx(miner_accounts[0].get_keys(), sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), tx, 0); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (!valid) DO_CALLBACK(events, "mark_invalid_tx"); diff --git a/tests/core_tests/wallet_tools.cpp b/tests/core_tests/wallet_tools.cpp index c5b3a54..becd012 100644 --- a/tests/core_tests/wallet_tools.cpp +++ b/tests/core_tests/wallet_tools.cpp @@ -282,5 +282,5 @@ bool construct_tx_rct(tools::wallet2 * sender_wallet, std::vectorget_account().get_keys(), subaddresses, sources, destinations_copy, 1/*hf_version*/, source_asset, dest_asset, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); + return construct_tx_and_get_tx_key(sender_wallet->get_account().get_keys(), subaddresses, sources, destinations_copy, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); } diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index bacc84b..784e758 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -85,7 +85,7 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor, try { std::vector ptx; - ptx = w1.create_transactions_2(dsts, "", "", mix_in_factor, 0, 0, std::vector(), 0, {}); + ptx = w1.create_transactions_2(dsts, "", "", cryptonote::transaction_type::TRANSFER, mix_in_factor, 0, 0, std::vector(), 0, {}); for (auto &p: ptx) w1.commit_tx(p); return true; diff --git a/tests/performance_tests/check_tx_signature.h b/tests/performance_tests/check_tx_signature.h index 579408c..ab125c9 100644 --- a/tests/performance_tests/check_tx_signature.h +++ b/tests/performance_tests/check_tx_signature.h @@ -74,7 +74,7 @@ public: rct::RCTConfig rct_config{range_proof_type, bp_version}; std::string source_asset = "FULM"; std::string dest_asset = "FULM"; - if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::account_public_address{}, std::vector(), m_tx, 0, tx_key, additional_tx_keys, rct, rct_config)) + if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), m_tx, 0, tx_key, additional_tx_keys, rct, rct_config)) return false; get_transaction_prefix_hash(m_tx, m_tx_prefix_hash); @@ -141,7 +141,7 @@ public: m_txes.resize(a_num_txes + (extra_outs > 0 ? 1 : 0)); for (size_t n = 0; n < a_num_txes; ++n) { - if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::account_public_address{}, std::vector(), m_txes[n], 0, tx_key, additional_tx_keys, true, {rct::RangeProofPaddedBulletproof, 2})) + if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), m_txes[n], 0, tx_key, additional_tx_keys, true, {rct::RangeProofPaddedBulletproof, 2})) return false; } @@ -152,7 +152,7 @@ public: for (size_t n = 1; n < extra_outs; ++n) destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); - if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::account_public_address{}, std::vector(), m_txes.back(), 0, tx_key, additional_tx_keys, true, {rct::RangeProofMultiOutputBulletproof, 2})) + if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), m_txes.back(), 0, tx_key, additional_tx_keys, true, {rct::RangeProofMultiOutputBulletproof, 2})) return false; } diff --git a/tests/performance_tests/construct_tx.h b/tests/performance_tests/construct_tx.h index a4aa11b..84e8853 100644 --- a/tests/performance_tests/construct_tx.h +++ b/tests/performance_tests/construct_tx.h @@ -76,7 +76,7 @@ public: rct::RCTConfig rct_config{range_proof_type, bp_version}; std::string source_asset = "FULM"; std::string dest_asset = "FULM"; - return cryptonote::construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, m_destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::account_public_address{}, std::vector(), m_tx, 0, tx_key, additional_tx_keys, rct, rct_config); + return cryptonote::construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, m_destinations, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, cryptonote::account_public_address{}, std::vector(), m_tx, 0, tx_key, additional_tx_keys, rct, rct_config); } private: diff --git a/tests/performance_tests/ge_frombytes_vartime.h b/tests/performance_tests/ge_frombytes_vartime.h index bd699ff..1d487ee 100644 --- a/tests/performance_tests/ge_frombytes_vartime.h +++ b/tests/performance_tests/ge_frombytes_vartime.h @@ -57,7 +57,7 @@ public: std::vector destinations; destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); - if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), m_tx, 0)) + if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), m_tx, 0)) return false; const cryptonote::txin_to_key& txin = boost::get(m_tx.vin[0]); diff --git a/tests/performance_tests/ge_tobytes.h b/tests/performance_tests/ge_tobytes.h index 7b272da..ce39e37 100644 --- a/tests/performance_tests/ge_tobytes.h +++ b/tests/performance_tests/ge_tobytes.h @@ -57,7 +57,7 @@ public: std::vector destinations; destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); - if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, 1/*hf_version*/, "FULM", "FULM", boost::none, std::vector(), m_tx, 0)) + if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, 1/*hf_version*/, "FULM", "FULM", cryptonote::transaction_type::TRANSFER, boost::none, std::vector(), m_tx, 0)) return false; const cryptonote::txin_to_key& txin = boost::get(m_tx.vin[0]); diff --git a/tests/unit_tests/json_serialization.cpp b/tests/unit_tests/json_serialization.cpp index f45c32d..6df3b25 100644 --- a/tests/unit_tests/json_serialization.cpp +++ b/tests/unit_tests/json_serialization.cpp @@ -79,7 +79,7 @@ namespace test std::string source_asset = "FULM"; std::string dest_asset = "FULM"; - if (!cryptonote::construct_tx_and_get_tx_key(from, subaddresses, actual_sources, to, 1/*hf_version*/, source_asset, dest_asset, boost::none, {}, tx, 0, tx_key, extra_keys, rct, { bulletproof ? rct::RangeProofBulletproof : rct::RangeProofBorromean, bulletproof ? 2 : 0 })) + if (!cryptonote::construct_tx_and_get_tx_key(from, subaddresses, actual_sources, to, 1/*hf_version*/, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, boost::none, {}, tx, 0, tx_key, extra_keys, rct, { bulletproof ? rct::RangeProofBulletproof : rct::RangeProofBorromean, bulletproof ? 2 : 0 })) throw std::runtime_error{"transaction construction error"}; return tx;