updated to support propagation of the transaction type - this was necessary to distinguish between YIELD and TRANSFER type

This commit is contained in:
Some Random Crypto Guy
2023-11-17 17:43:21 +00:00
parent 7f6b8daa49
commit ef27f6380e
34 changed files with 445 additions and 78 deletions
+20
View File
@@ -277,6 +277,8 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& 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<block, blobdata>& 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<transaction, blobdata>& tx : txs)
@@ -344,6 +359,7 @@ void BlockchainDB::pop_block(block& blk, std::vector<transaction>& 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
+70 -1
View File
@@ -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<uint64_t> 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"));
+4 -1
View File
@@ -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;
+2 -2
View File
@@ -198,7 +198,7 @@ namespace cryptonote
//extra
std::vector<uint8_t> 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<uint8_t>(cryptonote::transaction_type::TRANSFER);
type = cryptonote::transaction_type::TRANSFER;
destination_address = crypto::null_pkey;
source_asset_type.clear();
destination_asset_type.clear();
+4
View File
@@ -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
+162
View File
@@ -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<txin_gen>(b.protocol_tx.vin[0]).height != height)
{
MWARNING("The protocol transaction in block has invalid height: " << boost::get<txin_gen>(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<std::pair<transaction, blobdata>>& txs, const std::map<std::string, uint64_t>& 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<crypto::public_key, std::tuple<std::string, uint64_t, uint64_t>> outputs;
for (auto& o : b.protocol_tx.vout) {
if (o.target.type() == typeid(txout_to_key)) {
txout_to_key out = boost::get<txout_to_key>(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<txout_to_tagged_key>(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 <count> blocks, and return by reference <sz>.
void Blockchain::get_last_n_blocks_weights(std::vector<uint64_t>& 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<std::string, uint64_t> 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;
+29
View File
@@ -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<std::pair<transaction, blobdata>>& txs, const std::map<std::string, uint64_t>& circ_supply, uint8_t hf_version);
/**
* @brief reverts the blockchain to its previous state following a failed switch
*
+32 -19
View File
@@ -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<std::string, uint64_t> 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<cryptonote::account_public_address>& change_addr,
const std::vector<uint8_t> &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<uint8_t>(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<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &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<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &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<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time)
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& 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<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time)
{
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
std::vector<tx_destination_entry> 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(
+3 -3
View File
@@ -150,9 +150,9 @@ namespace cryptonote
//---------------------------------------------------------------
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &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<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &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<tx_source_entry> &sources, const std::vector<tx_destination_entry>& 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<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& 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<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &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<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& 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<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &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<cryptonote::account_public_address> &change_addr, const size_t output_index,
const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys,
+5 -4
View File
@@ -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
};
}
+13
View File
@@ -27,6 +27,7 @@
//
// Portions of this code based upon code Copyright (c) 2019, The Monero Project
#include <boost/multiprecision/cpp_int.hpp>
#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<uint64_t>();
}
return 0;
}
bool pricing_record::equal(const pricing_record& other) const noexcept
{
+38 -2
View File
@@ -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 [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
const char* USAGE_BURN("burn <amount> <asset_type>");
const char* USAGE_CONVERT("convert [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <source_amount>) <source_asset> <dest_asset> [<payment_id>]");
const char* USAGE_LOCK_FOR_YIELD("lock_for_yield <amount>");
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<std::string> &args/* = std::vector<st
message_writer() << tr("\"transfer <address> <amount> [<asset_type>]\" - Send FULM or F$ to an address.");
message_writer() << tr("\"burn <amount> <asset_type>\" - destroy coins forever.");
message_writer() << tr("\"convert <address> <amount> <source_asset> <dest_asset>\" - convert between coin types and send to address.");
message_writer() << tr("\"lock_for_tield <amount>\" - 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 <amount> <source_asset> into <dest_asset>, with optional <priority> [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 <amount> 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<std::string> &args_)
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::lock_for_yield(const std::vector<std::string> &args_)
{
// TODO: add locked versions
if (args_.size() != 1)
{
PRINT_USAGE(USAGE_LOCK_FOR_YIELD);
return true;
}
std::vector<std::string> 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<std::string> &args) {
// get circulating supply
std::vector<std::pair<std::string, std::string>> supply_amounts;
+1
View File
@@ -182,6 +182,7 @@ namespace cryptonote
bool sweep_unmixable(const std::vector<std::string> &args);
bool burn(const std::vector<std::string> &args);
bool convert(const std::vector<std::string> &args);
bool lock_for_yield(const std::vector<std::string> &args);
bool price_info(const std::vector<std::string> &args);
bool supply_info(const std::vector<std::string> &args);
bool yield_info(const std::vector<std::string> &args);
+16 -15
View File
@@ -6907,7 +6907,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
// To-do - work out the source_asset and dest_asset.
std::string source_asset = "FULM";
std::string dest_asset = "FULM";
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, hf_version, source_asset, dest_asset, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, rct_config, sd.use_view_tags);
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, hf_version, source_asset, dest_asset, sd.tx_type, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, rct_config, sd.use_view_tags);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
// we don't test tx size, because we don't know the current limit, due to not having a blockchain,
// and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
@@ -9064,7 +9064,8 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
// If it _does_ get called, it's necessary to work out the source_asset and dest_asset as well.
std::string source_asset = "FULM";
std::string dest_asset = "FULM";
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, {}, use_view_tags);
cryptonote::transaction_type tx_type = TRANSFER;
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, {}, use_view_tags);
LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype);
THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
@@ -9120,11 +9121,13 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
uint64_t unlock_time,
uint64_t fee,
const std::vector<uint8_t>& extra,
cryptonote::transaction& tx, pending_tx &ptx,
cryptonote::transaction& tx,
pending_tx &ptx,
const rct::RCTConfig &rct_config,
bool use_view_tags,
const std::string& source_asset,
const std::string& dest_asset,
const transaction_type& tx_type,
const oracle::pricing_record& pr)
{
using namespace cryptonote;
@@ -9350,7 +9353,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
std::vector<std::pair<std::string, std::string>> circ_amounts;
THROW_WALLET_EXCEPTION_IF(!get_circulating_supply(circ_amounts), error::wallet_internal_error, "Failed to get circulating supply");
// make a normal tx
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype);
}
@@ -10108,6 +10111,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(
std::vector<cryptonote::tx_destination_entry> dsts,
const std::string& source_asset,
const std::string& dest_asset,
const transaction_type& tx_type,
const size_t fake_outs_count,
const uint64_t unlock_time,
uint32_t priority,
@@ -10119,7 +10123,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(
hw::device &hwdev = m_account.get_device();
boost::unique_lock<hw::device> hwdev_lock (hwdev);
hw::reset_mode rst(hwdev);
using tt = cryptonote::transaction_type;
auto original_dsts = dsts;
@@ -10200,12 +10203,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(
uint32_t hf_version = get_current_hard_fork();
//const auto specific_transfers = m_transfers.at(source_asset);
// get tx type
tt tx_type;
THROW_WALLET_EXCEPTION_IF(!get_tx_type(source_asset, dest_asset, tx_type), error::wallet_internal_error, "invalid tx type");
oracle::pricing_record pricing_record;
std::vector<std::pair<std::string, std::string>> circ_amounts;
bool b = false;
std::vector<std::pair<std::string, std::string>> 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::pending_tx> 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::pending_tx> 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::pending_tx> 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::pending_tx> 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::pending_tx> 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);
+18 -7
View File
@@ -553,6 +553,7 @@ private:
std::vector<size_t> selected_transfers;
std::vector<uint8_t> 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<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, std::unordered_set<crypto::public_key> &valid_public_keys_cache,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& 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<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, std::unordered_set<crypto::public_key> &valid_public_keys_cache,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& 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<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,
std::unordered_set<crypto::public_key> &valid_public_keys_cache,
uint64_t unlock_time,
uint64_t fee,
const std::vector<uint8_t>& 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<pending_tx>& 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<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> 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<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices); // pass subaddr_indices by value on purpose
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> 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<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices); // pass subaddr_indices by value on purpose
std::vector<wallet2::pending_tx> 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<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
std::vector<wallet2::pending_tx> 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<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, const std::string &asset_type, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
+2 -2
View File
@@ -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<wallet2::pending_tx> 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<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, static_cast<cryptonote::transaction_type>(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<wallet2::pending_tx> 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<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, req.source_asset, req.dest_asset, static_cast<cryptonote::transaction_type>(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())
@@ -537,6 +537,7 @@ namespace wallet_rpc
std::list<transfer_destination> destinations;
std::string source_asset;
std::string dest_asset;
uint8_t tx_type;
uint32_t account_index;
std::set<uint32_t> 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<transfer_destination> destinations;
std::string source_asset;
std::string dest_asset;
uint8_t tx_type;
uint32_t account_index;
std::set<uint32_t> 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)