Merge pull request #9311

dd47d03 Enforce Tx unlock_time is Zero by Relay Rule [RELEASE] (jeffro256)
This commit is contained in:
luigi1111 2024-05-20 23:42:54 -05:00
commit 1ec7eae036
No known key found for this signature in database
GPG Key ID: F4ACA0183641E010
38 changed files with 186 additions and 230 deletions

View File

@ -59,6 +59,7 @@ namespace cryptonote
bool m_fee_too_low; bool m_fee_too_low;
bool m_too_few_outputs; bool m_too_few_outputs;
bool m_tx_extra_too_big; bool m_tx_extra_too_big;
bool m_nonzero_unlock_time;
}; };
struct block_verification_context struct block_verification_context

View File

@ -203,7 +203,7 @@ namespace cryptonote
return addr.m_view_public_key; return addr.m_view_public_key;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
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 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, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags) 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 boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags)
{ {
hw::device &hwdev = sender_account_keys.get_device(); hw::device &hwdev = sender_account_keys.get_device();
@ -218,7 +218,7 @@ namespace cryptonote
amount_keys.clear(); amount_keys.clear();
tx.version = rct ? 2 : 1; tx.version = rct ? 2 : 1;
tx.unlock_time = unlock_time; tx.unlock_time = 0;
tx.extra = extra; tx.extra = extra;
crypto::public_key txkey_pub; crypto::public_key txkey_pub;
@ -606,7 +606,7 @@ namespace cryptonote
return true; 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 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 boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, 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(); hw::device &hwdev = sender_account_keys.get_device();
hwdev.open_tx(tx_key); hwdev.open_tx(tx_key);
@ -627,7 +627,7 @@ namespace cryptonote
} }
bool shuffle_outs = true; bool shuffle_outs = true;
bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, 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, change_addr, extra, tx, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags);
hwdev.close_tx(); hwdev.close_tx();
return r; return r;
} catch(...) { } catch(...) {
@ -636,14 +636,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 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 boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx)
{ {
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0}; subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
crypto::secret_key tx_key; crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys; std::vector<crypto::secret_key> additional_tx_keys;
std::vector<tx_destination_entry> destinations_copy = destinations; std::vector<tx_destination_entry> destinations_copy = destinations;
return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, 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, change_addr, extra, tx, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0});
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool generate_genesis_block( bool generate_genesis_block(

View File

@ -118,9 +118,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); 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 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 boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx);
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 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_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 boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, 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 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_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 boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, 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, 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 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, const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys,

View File

@ -236,6 +236,15 @@ namespace cryptonote
return false; return false;
} }
if (!kept_by_block && tx.unlock_time)
{
LOG_PRINT_L1("transaction unlock time is not zero: " << tx.unlock_time);
tvc.m_verifivation_failed = true;
tvc.m_nonzero_unlock_time = true;
tvc.m_no_drop_offense = true;
return false;
}
// if the transaction came from a block popped from the chain, // if the transaction came from a block popped from the chain,
// don't check if we have its key images as spent. // don't check if we have its key images as spent.
// TODO: Investigate why not? // TODO: Investigate why not?

View File

@ -820,7 +820,6 @@ tx_builder_ringct_t::~tx_builder_ringct_t()
bool tx_builder_ringct_t::init( bool tx_builder_ringct_t::init(
const cryptonote::account_keys& account_keys, const cryptonote::account_keys& account_keys,
const std::vector<std::uint8_t>& extra, const std::vector<std::uint8_t>& extra,
const std::uint64_t unlock_time,
const std::uint32_t subaddr_account, const std::uint32_t subaddr_account,
const std::set<std::uint32_t>& subaddr_minor_indices, const std::set<std::uint32_t>& subaddr_minor_indices,
std::vector<cryptonote::tx_source_entry>& sources, std::vector<cryptonote::tx_source_entry>& sources,
@ -854,7 +853,7 @@ bool tx_builder_ringct_t::init(
// misc. fields // misc. fields
unsigned_tx.version = 2; //rct = 2 unsigned_tx.version = 2; //rct = 2
unsigned_tx.unlock_time = unlock_time; unsigned_tx.unlock_time = 0;
// sort inputs // sort inputs
sort_sources(sources); sort_sources(sources);

View File

@ -71,7 +71,6 @@ public:
bool init( bool init(
const cryptonote::account_keys& account_keys, const cryptonote::account_keys& account_keys,
const std::vector<std::uint8_t>& extra, const std::vector<std::uint8_t>& extra,
const std::uint64_t unlock_time,
const std::uint32_t subaddr_account, const std::uint32_t subaddr_account,
const std::set<std::uint32_t>& subaddr_minor_indices, const std::set<std::uint32_t>& subaddr_minor_indices,
std::vector<cryptonote::tx_source_entry>& sources, std::vector<cryptonote::tx_source_entry>& sources,

View File

@ -1340,6 +1340,8 @@ namespace cryptonote
add_reason(reason, "too few outputs"); add_reason(reason, "too few outputs");
if ((res.tx_extra_too_big = tvc.m_tx_extra_too_big)) if ((res.tx_extra_too_big = tvc.m_tx_extra_too_big))
add_reason(reason, "tx-extra too big"); add_reason(reason, "tx-extra too big");
if ((res.nonzero_unlock_time = tvc.m_nonzero_unlock_time))
add_reason(reason, "tx unlock time is not zero");
const std::string punctuation = reason.empty() ? "" : ": "; const std::string punctuation = reason.empty() ? "" : ": ";
if (tvc.m_verifivation_failed) if (tvc.m_verifivation_failed)
{ {

View File

@ -88,7 +88,7 @@ namespace cryptonote
// advance which version they will stop working with // advance which version they will stop working with
// Don't go over 32767 for any of these // Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 3 #define CORE_RPC_VERSION_MAJOR 3
#define CORE_RPC_VERSION_MINOR 13 #define CORE_RPC_VERSION_MINOR 14
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@ -640,6 +640,7 @@ namespace cryptonote
bool too_few_outputs; bool too_few_outputs;
bool sanity_check_failed; bool sanity_check_failed;
bool tx_extra_too_big; bool tx_extra_too_big;
bool nonzero_unlock_time;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_access_response_base) KV_SERIALIZE_PARENT(rpc_access_response_base)
@ -655,6 +656,7 @@ namespace cryptonote
KV_SERIALIZE(too_few_outputs) KV_SERIALIZE(too_few_outputs)
KV_SERIALIZE(sanity_check_failed) KV_SERIALIZE(sanity_check_failed)
KV_SERIALIZE(tx_extra_too_big) KV_SERIALIZE(tx_extra_too_big)
KV_SERIALIZE(nonzero_unlock_time)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
typedef epee::misc_utils::struct_init<response_t> response; typedef epee::misc_utils::struct_init<response_t> response;

View File

@ -422,6 +422,16 @@ namespace rpc
if (!res.error_details.empty()) res.error_details += " and "; if (!res.error_details.empty()) res.error_details += " and ";
res.error_details += "too few outputs"; res.error_details += "too few outputs";
} }
if (tvc.m_tx_extra_too_big)
{
if (!res.error_details.empty()) res.error_details += " and ";
res.error_details += "tx_extra too long";
}
if (tvc.m_nonzero_unlock_time)
{
if (!res.error_details.empty()) res.error_details += " and ";
res.error_details += "non-zero unlock time";
}
if (res.error_details.empty()) if (res.error_details.empty())
{ {
res.error_details = "an unknown issue was found with the transaction"; res.error_details = "an unknown issue was found with the transaction";

View File

@ -155,11 +155,6 @@ typedef cryptonote::simple_wallet sw;
} \ } \
} while(0) } while(0)
enum TransferType {
Transfer,
TransferLocked,
};
static std::string get_human_readable_timespan(std::chrono::seconds seconds); static std::string get_human_readable_timespan(std::chrono::seconds seconds);
static std::string get_human_readable_timespan(uint64_t seconds); static std::string get_human_readable_timespan(uint64_t seconds);
@ -197,8 +192,6 @@ namespace
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]"); const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
const char* USAGE_PAYMENT_ID("payment_id"); const char* USAGE_PAYMENT_ID("payment_id");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [subtractfeefrom=<D0>[,<D1>,all,...]] [<payment_id>]"); const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [subtractfeefrom=<D0>[,<D1>,all,...]] [<payment_id>]");
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]"); const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_ACCOUNT("sweep_account <account> [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]"); const char* USAGE_SWEEP_ACCOUNT("sweep_account <account> [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]"); const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]");
@ -3336,14 +3329,6 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::on_command, this, &simple_wallet::transfer, _1), m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::on_command, this, &simple_wallet::transfer, _1),
tr(USAGE_TRANSFER), tr(USAGE_TRANSFER),
tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included). The \"subtractfeefrom=\" list allows you to choose which destinations to fund the tx fee from instead of the change output. The fee will be split across the chosen destinations proportionally equally. For example, to make 3 transfers where the fee is taken from the first and third destinations, one could do: \"transfer <addr1> 3 <addr2> 0.5 <addr3> 1 subtractfeefrom=0,2\". Let's say the tx fee is 0.1. The balance would drop by exactly 4.5 XMR including fees, and addr1 & addr3 would receive 2.925 & 0.975 XMR, respectively. Use \"subtractfeefrom=all\" to spread the fee across all destinations.")); tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included). The \"subtractfeefrom=\" list allows you to choose which destinations to fund the tx fee from instead of the change output. The fee will be split across the chosen destinations proportionally equally. For example, to make 3 transfers where the fee is taken from the first and third destinations, one could do: \"transfer <addr1> 3 <addr2> 0.5 <addr3> 1 subtractfeefrom=0,2\". Let's say the tx fee is 0.1. The balance would drop by exactly 4.5 XMR including fees, and addr1 & addr3 would receive 2.925 & 0.975 XMR, respectively. Use \"subtractfeefrom=all\" to spread the fee across all destinations."));
m_cmd_binder.set_handler("locked_transfer",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::locked_transfer,_1),
tr(USAGE_LOCKED_TRANSFER),
tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_sweep_all",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::locked_sweep_all,_1),
tr(USAGE_LOCKED_SWEEP_ALL),
tr("Send all unlocked balance to an address and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. <priority> is the priority of the sweep. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability."));
m_cmd_binder.set_handler("sweep_unmixable", m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_unmixable, _1), boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_unmixable, _1),
tr("Send all unmixable outputs to yourself with ring_size 1")); tr("Send all unmixable outputs to yourself with ring_size 1"));
@ -6588,7 +6573,7 @@ bool simple_wallet::on_command(bool (simple_wallet::*cmd)(const std::vector<std:
return (this->*cmd)(args); return (this->*cmd)(args);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::string> &args_, bool called_by_mms) bool simple_wallet::transfer_main(const std::vector<std::string> &args_, bool called_by_mms)
{ {
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]" // "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
if (!try_connect_to_daemon()) if (!try_connect_to_daemon())
@ -6640,7 +6625,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
return false; return false;
} }
const size_t min_args = (transfer_type == TransferLocked) ? 2 : 1; const size_t min_args = 1;
if(local_args.size() < min_args) if(local_args.size() < min_args)
{ {
fail_msg_writer() << tr("wrong number of arguments"); fail_msg_writer() << tr("wrong number of arguments");
@ -6665,26 +6650,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
} }
} }
uint64_t locked_blocks = 0;
if (transfer_type == TransferLocked)
{
try
{
locked_blocks = boost::lexical_cast<uint64_t>(local_args.back());
}
catch (const std::exception &e)
{
fail_msg_writer() << tr("bad locked_blocks parameter:") << " " << local_args.back();
return false;
}
if (locked_blocks > 1000000)
{
fail_msg_writer() << tr("Locked blocks too high, max 1000000 (˜4 yrs)");
return false;
}
local_args.pop_back();
}
// Parse subtractfeefrom destination list // Parse subtractfeefrom destination list
tools::wallet2::unique_index_container subtract_fee_from_outputs; tools::wallet2::unique_index_container subtract_fee_from_outputs;
bool subtract_fee_from_all = false; bool subtract_fee_from_all = false;
@ -6814,28 +6779,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
try try
{ {
// figure out what tx will be necessary // figure out what tx will be necessary
std::vector<tools::wallet2::pending_tx> ptx_vector; auto ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, priority, extra,
uint64_t bc_height, unlock_block = 0; m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
std::string err;
switch (transfer_type)
{
case TransferLocked:
bc_height = get_daemon_blockchain_height(err);
if (!err.empty())
{
fail_msg_writer() << tr("failed to get blockchain height: ") << err;
return false;
}
unlock_block = bc_height + locked_blocks;
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
default:
LOG_ERROR("Unknown transfer method, using default");
/* FALLTHRU */
case Transfer:
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
}
if (ptx_vector.empty()) if (ptx_vector.empty())
{ {
@ -6945,11 +6890,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
if (dust_in_fee != 0) prompt << boost::format(tr(", of which %s is dust from change")) % print_money(dust_in_fee); if (dust_in_fee != 0) prompt << boost::format(tr(", of which %s is dust from change")) % print_money(dust_in_fee);
if (dust_not_in_fee != 0) prompt << tr(".") << ENDL << boost::format(tr("A total of %s from dust change will be sent to dust address")) if (dust_not_in_fee != 0) prompt << tr(".") << ENDL << boost::format(tr("A total of %s from dust change will be sent to dust address"))
% print_money(dust_not_in_fee); % print_money(dust_not_in_fee);
if (transfer_type == TransferLocked)
{
float days = locked_blocks / 720.0f;
prompt << boost::format(tr(".\nThis transaction (including %s change) will unlock on block %llu, in approximately %s days (assuming 2 minutes per block)")) % cryptonote::print_money(change) % ((unsigned long long)unlock_block) % days;
}
if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members())) if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
return false; return false;
bool default_ring_size = true; bool default_ring_size = true;
@ -7069,29 +7009,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
PRINT_USAGE(USAGE_TRANSFER); PRINT_USAGE(USAGE_TRANSFER);
return true; return true;
} }
transfer_main(Transfer, args_, false); transfer_main(args_, false);
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
{
if (args_.size() < 1)
{
PRINT_USAGE(USAGE_LOCKED_TRANSFER);
return true;
}
transfer_main(TransferLocked, args_, false);
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
{
if (args_.size() < 1)
{
PRINT_USAGE(USAGE_LOCKED_SWEEP_ALL);
return true;
}
sweep_main(m_current_subaddress_account, 0, true, args_);
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -7203,7 +7121,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_) bool simple_wallet::sweep_main(uint32_t account, uint64_t below, const std::vector<std::string> &args_)
{ {
auto print_usage = [this, account, below]() auto print_usage = [this, account, below]()
{ {
@ -7283,41 +7201,6 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
return true; return true;
} }
uint64_t unlock_block = 0;
if (locked) {
uint64_t locked_blocks = 0;
if (local_args.size() < 2) {
fail_msg_writer() << tr("missing lockedblocks parameter");
return true;
}
try
{
locked_blocks = boost::lexical_cast<uint64_t>(local_args[1]);
}
catch (const std::exception &e)
{
fail_msg_writer() << tr("bad locked_blocks parameter");
return true;
}
if (locked_blocks > 1000000)
{
fail_msg_writer() << tr("Locked blocks too high, max 1000000 (˜4 yrs)");
return true;
}
std::string err;
uint64_t bc_height = get_daemon_blockchain_height(err);
if (!err.empty())
{
fail_msg_writer() << tr("failed to get blockchain height: ") << err;
return true;
}
unlock_block = bc_height + locked_blocks;
local_args.erase(local_args.begin() + 1);
}
size_t outputs = 1; size_t outputs = 1;
if (local_args.size() > 0 && local_args[0].substr(0, 8) == "outputs=") if (local_args.size() > 0 && local_args[0].substr(0, 8) == "outputs=")
{ {
@ -7392,7 +7275,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
try try
{ {
// figure out what tx will be necessary // figure out what tx will be necessary
auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, account, subaddr_indices); auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, priority, extra, account, subaddr_indices);
if (ptx_vector.empty()) if (ptx_vector.empty())
{ {
@ -7649,7 +7532,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
try try
{ {
// figure out what tx will be necessary // figure out what tx will be necessary
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, outputs, fake_outs_count, 0 /* unlock_time */, priority, extra); auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, outputs, fake_outs_count, priority, extra);
if (ptx_vector.empty()) if (ptx_vector.empty())
{ {
@ -7759,7 +7642,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_all(const std::vector<std::string> &args_) bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
{ {
sweep_main(m_current_subaddress_account, 0, false, args_); sweep_main(m_current_subaddress_account, 0, args_);
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -7779,7 +7662,7 @@ bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
} }
local_args.erase(local_args.begin()); local_args.erase(local_args.begin());
sweep_main(account, 0, false, local_args); sweep_main(account, 0, local_args);
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -7797,7 +7680,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
fail_msg_writer() << tr("invalid amount threshold"); fail_msg_writer() << tr("invalid amount threshold");
return true; return true;
} }
sweep_main(m_current_subaddress_account, below, false, std::vector<std::string>(++args_.begin(), args_.end())); sweep_main(m_current_subaddress_account, below, std::vector<std::string>(++args_.begin(), args_.end()));
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -11399,7 +11282,7 @@ void simple_wallet::mms_sync(const std::vector<std::string> &args)
void simple_wallet::mms_transfer(const std::vector<std::string> &args) void simple_wallet::mms_transfer(const std::vector<std::string> &args)
{ {
// It's too complicated to check any arguments here, just let 'transfer_main' do the whole job // It's too complicated to check any arguments here, just let 'transfer_main' do the whole job
transfer_main(Transfer, args, true); transfer_main(args, true);
} }
void simple_wallet::mms_delete(const std::vector<std::string> &args) void simple_wallet::mms_delete(const std::vector<std::string> &args)

View File

@ -170,11 +170,9 @@ namespace cryptonote
bool show_incoming_transfers(const std::vector<std::string> &args); bool show_incoming_transfers(const std::vector<std::string> &args);
bool show_payments(const std::vector<std::string> &args); bool show_payments(const std::vector<std::string> &args);
bool show_blockchain_height(const std::vector<std::string> &args); bool show_blockchain_height(const std::vector<std::string> &args);
bool transfer_main(int transfer_type, const std::vector<std::string> &args, bool called_by_mms); bool transfer_main(const std::vector<std::string> &args, bool called_by_mms);
bool transfer(const std::vector<std::string> &args); bool transfer(const std::vector<std::string> &args);
bool locked_transfer(const std::vector<std::string> &args); bool sweep_main(uint32_t account, uint64_t below, const std::vector<std::string> &args);
bool locked_sweep_all(const std::vector<std::string> &args);
bool sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args);
bool sweep_all(const std::vector<std::string> &args); bool sweep_all(const std::vector<std::string> &args);
bool sweep_account(const std::vector<std::string> &args); bool sweep_account(const std::vector<std::string> &args);
bool sweep_below(const std::vector<std::string> &args); bool sweep_below(const std::vector<std::string> &args);

View File

@ -1588,11 +1588,11 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
fake_outs_count = m_wallet->adjust_mixin(mixin_count); fake_outs_count = m_wallet->adjust_mixin(mixin_count);
if (amount) { if (amount) {
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count,
adjusted_priority, adjusted_priority,
extra, subaddr_account, subaddr_indices); extra, subaddr_account, subaddr_indices);
} else { } else {
transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count,
adjusted_priority, adjusted_priority,
extra, subaddr_account, subaddr_indices); extra, subaddr_account, subaddr_indices);
} }

View File

@ -7333,14 +7333,15 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
{ {
tools::wallet2::tx_construction_data &sd = exported_txs.txes[n]; tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources"); THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources");
THROW_WALLET_EXCEPTION_IF(sd.unlock_time, error::nonzero_unlock_time);
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size()); LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
signed_txes.ptx.push_back(pending_tx()); signed_txes.ptx.push_back(pending_tx());
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back(); tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
rct::RCTConfig rct_config = sd.rct_config; rct::RCTConfig rct_config = sd.rct_config;
crypto::secret_key tx_key; crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys; std::vector<crypto::secret_key> additional_tx_keys;
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, 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, sd.change_dts.addr, sd.extra, ptx.tx, 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); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, m_nettype);
// we don't test tx size, because we don't know the current limit, due to not having a blockchain, // 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, // and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
// and if we really go over limit, the daemon will reject when it gets submitted. Chances are it's // and if we really go over limit, the daemon will reject when it gets submitted. Chances are it's
@ -7870,7 +7871,6 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
not multisig_tx_builder.init( not multisig_tx_builder.init(
m_account.get_keys(), m_account.get_keys(),
ptx.construction_data.extra, ptx.construction_data.extra,
ptx.construction_data.unlock_time,
ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_account,
ptx.construction_data.subaddr_indices, ptx.construction_data.subaddr_indices,
ptx.construction_data.sources, ptx.construction_data.sources,
@ -9422,7 +9422,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
template<typename T> template<typename T>
void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, void wallet2::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, 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, 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,
bool use_view_tags) bool use_view_tags)
{ {
using namespace cryptonote; using namespace cryptonote;
@ -9533,9 +9533,9 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
crypto::secret_key tx_key; crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys; std::vector<crypto::secret_key> additional_tx_keys;
LOG_PRINT_L2("constructing tx"); LOG_PRINT_L2("constructing tx");
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, {}, use_view_tags); bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, tx_key, additional_tx_keys, false, {}, use_view_tags);
LOG_PRINT_L2("constructed tx, r="<<r); 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(!r, error::tx_not_constructed, sources, splitted_dsts, m_nettype);
THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit); THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
std::string key_images; std::string key_images;
@ -9568,7 +9568,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
ptx.construction_data.splitted_dsts = splitted_dsts; ptx.construction_data.splitted_dsts = splitted_dsts;
ptx.construction_data.selected_transfers = selected_transfers; ptx.construction_data.selected_transfers = selected_transfers;
ptx.construction_data.extra = tx.extra; ptx.construction_data.extra = tx.extra;
ptx.construction_data.unlock_time = unlock_time; ptx.construction_data.unlock_time = 0;
ptx.construction_data.use_rct = false; ptx.construction_data.use_rct = false;
ptx.construction_data.rct_config = { rct::RangeProofBorromean, 0 }; ptx.construction_data.rct_config = { rct::RangeProofBorromean, 0 };
ptx.construction_data.use_view_tags = use_view_tags; ptx.construction_data.use_view_tags = use_view_tags;
@ -9583,7 +9583,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, void wallet2::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, 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, bool use_view_tags) uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, bool use_view_tags)
{ {
using namespace cryptonote; using namespace cryptonote;
// throw if attempting a transaction with no destinations // throw if attempting a transaction with no destinations
@ -9779,7 +9779,6 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
THROW_WALLET_EXCEPTION_IF( THROW_WALLET_EXCEPTION_IF(
not multisig_tx_builder.init(m_account.get_keys(), not multisig_tx_builder.init(m_account.get_keys(),
extra, extra,
unlock_time,
subaddr_account, subaddr_account,
subaddr_minor_indices, subaddr_minor_indices,
sources, sources,
@ -9799,9 +9798,9 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
} }
else { else {
// make a normal tx // make a normal tx
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, 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, change_dts.addr, extra, tx, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
LOG_PRINT_L2("constructed tx, r="<<r); LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, m_nettype);
} }
THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit); THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
@ -9923,7 +9922,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
ptx.construction_data.splitted_dsts = splitted_dsts; ptx.construction_data.splitted_dsts = splitted_dsts;
ptx.construction_data.selected_transfers = ptx.selected_transfers; ptx.construction_data.selected_transfers = ptx.selected_transfers;
ptx.construction_data.extra = tx.extra; ptx.construction_data.extra = tx.extra;
ptx.construction_data.unlock_time = unlock_time; ptx.construction_data.unlock_time = 0;
ptx.construction_data.use_rct = true; ptx.construction_data.use_rct = true;
ptx.construction_data.rct_config = { ptx.construction_data.rct_config = {
rct::RangeProofPaddedBulletproof, rct::RangeProofPaddedBulletproof,
@ -10553,7 +10552,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image,
// This system allows for sending (almost) the entire balance, since it does // This system allows for sending (almost) the entire balance, since it does
// not generate spurious change in all txes, thus decreasing the instantaneous // not generate spurious change in all txes, thus decreasing the instantaneous
// usable balance. // usable balance.
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, 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, const unique_index_container& subtract_fee_from_outputs) std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs)
{ {
//ensure device is let in NONE mode in any case //ensure device is let in NONE mode in any case
hw::device &hwdev = m_account.get_device(); hw::device &hwdev = m_account.get_device();
@ -11080,10 +11079,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
tx.selected_transfers.size() << " inputs"); tx.selected_transfers.size() << " inputs");
auto tx_dsts = tx.get_adjusted_dsts(needed_fee); auto tx_dsts = tx.get_adjusted_dsts(needed_fee);
if (use_rct) if (use_rct)
transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags); test_tx, test_ptx, rct_config, use_view_tags);
else else
transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx); 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); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
@ -11124,10 +11123,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
tx_dsts = tx.get_adjusted_dsts(needed_fee); tx_dsts = tx.get_adjusted_dsts(needed_fee);
if (use_rct) if (use_rct)
transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags); test_tx, test_ptx, rct_config, use_view_tags);
else else
transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
txBlob = t_serializable_object_to_blob(test_ptx.tx); 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); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
@ -11200,7 +11199,6 @@ skip_tx:
fake_outs_count, /* CONST size_t fake_outputs_count, */ fake_outs_count, /* CONST size_t fake_outputs_count, */
tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */ tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */
valid_public_keys_cache, valid_public_keys_cache,
unlock_time, /* CONST uint64_t unlock_time, */
tx.needed_fee, /* CONST uint64_t fee, */ tx.needed_fee, /* CONST uint64_t fee, */
extra, /* const std::vector<uint8_t>& extra, */ extra, /* const std::vector<uint8_t>& extra, */
test_tx, /* OUT cryptonote::transaction& tx, */ test_tx, /* OUT cryptonote::transaction& tx, */
@ -11213,7 +11211,6 @@ skip_tx:
fake_outs_count, fake_outs_count,
tx.outs, tx.outs,
valid_public_keys_cache, valid_public_keys_cache,
unlock_time,
tx.needed_fee, tx.needed_fee,
extra, extra,
detail::digit_split_strategy, detail::digit_split_strategy,
@ -11327,7 +11324,7 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, c
return true; return true;
} }
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, 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> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{ {
std::vector<size_t> unused_transfers_indices; std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices; std::vector<size_t> unused_dust_indices;
@ -11397,10 +11394,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
} }
} }
return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra); return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, priority, extra);
} }
std::vector<wallet2::pending_tx> wallet2::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> wallet2::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, uint32_t priority, const std::vector<uint8_t>& extra)
{ {
std::vector<size_t> unused_transfers_indices; std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices; std::vector<size_t> unused_dust_indices;
@ -11418,10 +11415,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
break; break;
} }
} }
return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra); return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, priority, extra);
} }
std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, 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) std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, 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, uint32_t priority, const std::vector<uint8_t>& extra)
{ {
//ensure device is let in NONE mode in any case //ensure device is let in NONE mode in any case
hw::device &hwdev = m_account.get_device(); hw::device &hwdev = m_account.get_device();
@ -11530,10 +11527,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " << LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
tx.selected_transfers.size() << " outputs"); tx.selected_transfers.size() << " outputs");
if (use_rct) if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags); test_tx, test_ptx, rct_config, use_view_tags);
else else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx); 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); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
@ -11567,10 +11564,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
dt.amount = dt_amount + dt_residue; dt.amount = dt_amount + dt_residue;
} }
if (use_rct) if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags); test_tx, test_ptx, rct_config, use_view_tags);
else else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
txBlob = t_serializable_object_to_blob(test_ptx.tx); 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); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
@ -11606,10 +11603,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
cryptonote::transaction test_tx; cryptonote::transaction test_tx;
pending_tx test_ptx; pending_tx test_ptx;
if (use_rct) { 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, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, tx.needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags); test_tx, test_ptx, rct_config, use_view_tags);
} else { } else {
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, tx.needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
} }
auto txBlob = t_serializable_object_to_blob(test_ptx.tx); auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
@ -11921,7 +11918,7 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions()
unmixable_transfer_outputs.push_back(n); unmixable_transfer_outputs.push_back(n);
} }
return create_transactions_from(m_account_public_address, false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>()); return create_transactions_from(m_account_public_address, false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 1 /*priority */, std::vector<uint8_t>());
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::discard_unmixable_outputs() void wallet2::discard_unmixable_outputs()

View File

@ -1088,10 +1088,10 @@ private:
template<typename T> template<typename T>
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, 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, 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); 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, 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, 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); 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);
void commit_tx(pending_tx& ptx_vector); void commit_tx(pending_tx& ptx_vector);
void commit_tx(std::vector<pending_tx>& ptx_vector); void commit_tx(std::vector<pending_tx>& ptx_vector);
@ -1113,10 +1113,10 @@ private:
bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const; 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 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); 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 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, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, 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_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, 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_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, uint32_t priority, const std::vector<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, 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); std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, 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, uint32_t priority, const std::vector<uint8_t>& extra);
bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const; bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const;
void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux); void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux);
void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux); void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux);

View File

@ -86,6 +86,7 @@ namespace tools
// zero_amount // zero_amount
// zero_destination // zero_destination
// subtract_fee_from_bad_index // subtract_fee_from_bad_index
// nonzero_unlock_time
// wallet_rpc_error * // wallet_rpc_error *
// daemon_busy // daemon_busy
// no_connection_to_daemon // no_connection_to_daemon
@ -592,20 +593,17 @@ namespace tools
std::string && loc std::string && loc
, sources_t const & sources , sources_t const & sources
, destinations_t const & destinations , destinations_t const & destinations
, uint64_t unlock_time
, cryptonote::network_type nettype , cryptonote::network_type nettype
) )
: transfer_error(std::move(loc), "transaction was not constructed") : transfer_error(std::move(loc), "transaction was not constructed")
, m_sources(sources) , m_sources(sources)
, m_destinations(destinations) , m_destinations(destinations)
, m_unlock_time(unlock_time)
, m_nettype(nettype) , m_nettype(nettype)
{ {
} }
const sources_t& sources() const { return m_sources; } const sources_t& sources() const { return m_sources; }
const destinations_t& destinations() const { return m_destinations; } const destinations_t& destinations() const { return m_destinations; }
uint64_t unlock_time() const { return m_unlock_time; }
std::string to_string() const std::string to_string() const
{ {
@ -637,15 +635,12 @@ namespace tools
cryptonote::print_money(dst.amount); cryptonote::print_money(dst.amount);
} }
ss << "\nunlock_time: " << m_unlock_time;
return ss.str(); return ss.str();
} }
private: private:
sources_t m_sources; sources_t m_sources;
destinations_t m_destinations; destinations_t m_destinations;
uint64_t m_unlock_time;
cryptonote::network_type m_nettype; cryptonote::network_type m_nettype;
}; };
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -789,6 +784,14 @@ namespace tools
} }
}; };
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
struct nonzero_unlock_time : public transfer_error
{
explicit nonzero_unlock_time(std::string&& loc)
: transfer_error(std::move(loc), "transaction cannot have non-zero unlock time")
{
}
};
//----------------------------------------------------------------------------------------------------
struct wallet_rpc_error : public wallet_logic_error struct wallet_rpc_error : public wallet_logic_error
{ {
const std::string& request() const { return m_request; } const std::string& request() const { return m_request; }

View File

@ -1080,6 +1080,12 @@ namespace tools
er.message = "Command unavailable in restricted mode."; er.message = "Command unavailable in restricted mode.";
return false; return false;
} }
else if (req.unlock_time)
{
er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME;
er.message = "Transaction cannot have non-zero unlock time";
return false;
}
CHECK_MULTISIG_ENABLED(); CHECK_MULTISIG_ENABLED();
@ -1093,7 +1099,7 @@ namespace tools
{ {
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority); uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs);
if (ptx_vector.empty()) if (ptx_vector.empty())
{ {
@ -1134,6 +1140,12 @@ namespace tools
er.message = "Command unavailable in restricted mode."; er.message = "Command unavailable in restricted mode.";
return false; return false;
} }
else if (req.unlock_time)
{
er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME;
er.message = "Transaction cannot have non-zero unlock time";
return false;
}
CHECK_MULTISIG_ENABLED(); CHECK_MULTISIG_ENABLED();
@ -1148,7 +1160,7 @@ namespace tools
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority); uint32_t priority = m_wallet->adjust_priority(req.priority);
LOG_PRINT_L2("on_transfer_split calling create_transactions_2"); LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, 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, mixin, priority, extra, req.account_index, req.subaddr_indices);
LOG_PRINT_L2("on_transfer_split called create_transactions_2"); LOG_PRINT_L2("on_transfer_split called create_transactions_2");
if (ptx_vector.empty()) if (ptx_vector.empty())
@ -1570,6 +1582,12 @@ namespace tools
er.message = "Command unavailable in restricted mode."; er.message = "Command unavailable in restricted mode.";
return false; return false;
} }
else if (req.unlock_time)
{
er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME;
er.message = "Transaction cannot have non-zero unlock time";
return false;
}
CHECK_MULTISIG_ENABLED(); CHECK_MULTISIG_ENABLED();
@ -1605,7 +1623,7 @@ namespace tools
{ {
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority); uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, subaddr_indices); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, priority, extra, req.account_index, subaddr_indices);
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.amounts_by_dest_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.amounts_by_dest_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er); res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er);
@ -1630,6 +1648,12 @@ namespace tools
er.message = "Command unavailable in restricted mode."; er.message = "Command unavailable in restricted mode.";
return false; return false;
} }
else if (req.unlock_time)
{
er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME;
er.message = "Transaction cannot have non-zero unlock time";
return false;
}
if (req.outputs < 1) if (req.outputs < 1)
{ {
@ -1662,7 +1686,7 @@ namespace tools
{ {
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority); uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, priority, extra);
if (ptx_vector.empty()) if (ptx_vector.empty())
{ {

View File

@ -79,3 +79,5 @@
#define WALLET_RPC_ERROR_CODE_ZERO_AMOUNT -46 #define WALLET_RPC_ERROR_CODE_ZERO_AMOUNT -46
#define WALLET_RPC_ERROR_CODE_INVALID_SIGNATURE_TYPE -47 #define WALLET_RPC_ERROR_CODE_INVALID_SIGNATURE_TYPE -47
#define WALLET_RPC_ERROR_CODE_DISABLED -48 #define WALLET_RPC_ERROR_CODE_DISABLED -48
#define WALLET_RPC_ERROR_CODE_PROXY_ALREADY_DEFINED -49
#define WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME -50

View File

@ -350,7 +350,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events
destinations.push_back(de); destinations.push_back(de);
transaction tmp_tx; transaction tmp_tx;
if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx, 0)) if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx))
return false; return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); MAKE_MINER_TX_MANUALLY(miner_tx, blk_0);
@ -393,7 +393,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry>
destinations.push_back(de); destinations.push_back(de);
transaction tmp_tx; transaction tmp_tx;
if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx, 0)) if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx))
return false; return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_1); MAKE_MINER_TX_MANUALLY(miner_tx, blk_1);

View File

@ -136,7 +136,7 @@ bool gen_bpp_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0};
rct_txes.resize(rct_txes.size() + 1); rct_txes.resize(rct_txes.size() + 1);
bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), tx_key, additional_tx_keys, true, rct_config[n]);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
if (post_tx && !post_tx(rct_txes.back(), n)) if (post_tx && !post_tx(rct_txes.back(), n))

View File

@ -136,7 +136,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& eve
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0};
rct_txes.resize(rct_txes.size() + 1); rct_txes.resize(rct_txes.size() + 1);
bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), tx_key, additional_tx_keys, true, rct_config[n]);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
if (post_tx && !post_tx(rct_txes.back(), n)) if (post_tx && !post_tx(rct_txes.back(), n))

View File

@ -1028,7 +1028,7 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote
vector<tx_destination_entry> destinations; vector<tx_destination_entry> destinations;
fill_tx_sources_and_destinations(events, blk_head, from, get_address(to), amount, fee, nmix, sources, destinations); fill_tx_sources_and_destinations(events, blk_head, from, get_address(to), amount, fee, nmix, sources, destinations);
return construct_tx_rct(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); return construct_tx_rct(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version);
} }
bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const cryptonote::block& blk_head, bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const cryptonote::block& blk_head,
@ -1044,7 +1044,7 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote
fill_tx_destinations(from, destinations, fee, sources, destinations_all, false); fill_tx_destinations(from, destinations, fee, sources, destinations_all, false);
return construct_tx_rct(from.get_keys(), sources, destinations_all, get_address(from), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); return construct_tx_rct(from.get_keys(), sources, destinations_all, get_address(from), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version);
} }
bool construct_tx_to_key(cryptonote::transaction& tx, bool construct_tx_to_key(cryptonote::transaction& tx,
@ -1054,7 +1054,7 @@ bool construct_tx_to_key(cryptonote::transaction& tx,
{ {
vector<tx_destination_entry> destinations; vector<tx_destination_entry> destinations;
fill_tx_destinations(from, get_address(to), amount, fee, sources, destinations, rct); fill_tx_destinations(from, get_address(to), amount, fee, sources, destinations, rct);
return construct_tx_rct(from.get_keys(), sources, destinations, get_address(from), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); return construct_tx_rct(from.get_keys(), sources, destinations, get_address(from), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version);
} }
bool construct_tx_to_key(cryptonote::transaction& tx, bool construct_tx_to_key(cryptonote::transaction& tx,
@ -1065,10 +1065,10 @@ bool construct_tx_to_key(cryptonote::transaction& tx,
{ {
vector<tx_destination_entry> all_destinations; vector<tx_destination_entry> all_destinations;
fill_tx_destinations(from, destinations, fee, sources, all_destinations, rct); fill_tx_destinations(from, destinations, fee, sources, all_destinations, rct);
return construct_tx_rct(from.get_keys(), sources, all_destinations, get_address(from), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); return construct_tx_rct(from.get_keys(), sources, all_destinations, get_address(from), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version);
} }
bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, bool rct, rct::RangeProofType range_proof_type, int bp_version) bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, bool rct, rct::RangeProofType range_proof_type, int bp_version)
{ {
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0, 0}; subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0, 0};
@ -1076,7 +1076,7 @@ bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std::
std::vector<crypto::secret_key> additional_tx_keys; std::vector<crypto::secret_key> additional_tx_keys;
std::vector<tx_destination_entry> destinations_copy = destinations; std::vector<tx_destination_entry> destinations_copy = destinations;
rct::RCTConfig rct_config = {range_proof_type, bp_version}; rct::RCTConfig rct_config = {range_proof_type, bp_version};
return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, 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, change_addr, extra, tx, tx_key, additional_tx_keys, rct, rct_config);
} }
transaction construct_tx_with_fee(std::vector<test_event_entry>& events, const block& blk_head, transaction construct_tx_with_fee(std::vector<test_event_entry>& events, const block& blk_head,

View File

@ -450,7 +450,7 @@ bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys,
std::vector<cryptonote::tx_source_entry>& sources, std::vector<cryptonote::tx_source_entry>& sources,
const std::vector<cryptonote::tx_destination_entry>& destinations, const std::vector<cryptonote::tx_destination_entry>& destinations,
const boost::optional<cryptonote::account_public_address>& change_addr, const boost::optional<cryptonote::account_public_address>& change_addr,
std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, std::vector<uint8_t> extra, cryptonote::transaction& tx,
bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0); bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0);

View File

@ -144,7 +144,7 @@ bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_even
destinations.push_back(de); destinations.push_back(de);
cryptonote::transaction tx_1; cryptonote::transaction tx_1;
if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1, 0)) if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1))
return false; return false;
SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0); SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0);

View File

@ -174,7 +174,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
destinations.push_back(tx_destination_entry(sources.front().amount - MONEY_SUPPLY - MONEY_SUPPLY + 1 - TESTS_DEFAULT_FEE, bob_addr, false)); destinations.push_back(tx_destination_entry(sources.front().amount - MONEY_SUPPLY - MONEY_SUPPLY + 1 - TESTS_DEFAULT_FEE, bob_addr, false));
cryptonote::transaction tx_1; cryptonote::transaction tx_1;
if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1, 0)) if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1))
return false; return false;
events.push_back(tx_1); events.push_back(tx_1);
@ -200,7 +200,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
destinations.push_back(de); destinations.push_back(de);
cryptonote::transaction tx_2; cryptonote::transaction tx_2;
if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_2, 0)) if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_2))
return false; return false;
events.push_back(tx_2); events.push_back(tx_2);

View File

@ -310,7 +310,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry
crypto::secret_key multisig_tx_key_entropy; crypto::secret_key multisig_tx_key_entropy;
auto sources_copy = sources; auto sources_copy = sources;
multisig::signing::tx_builder_ringct_t tx_builder; multisig::signing::tx_builder_ringct_t tx_builder;
CHECK_AND_ASSERT_MES(tx_builder.init(miner_account[creator].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, false, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init"); CHECK_AND_ASSERT_MES(tx_builder.init(miner_account[creator].get_keys(), {}, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, false, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init");
// work out the permutation done on sources // work out the permutation done on sources
std::vector<size_t> ins_order; std::vector<size_t> ins_order;
@ -399,7 +399,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry
} }
tools::apply_permutation(ins_order, k); tools::apply_permutation(ins_order, k);
multisig::signing::tx_builder_ringct_t signer_tx_builder; multisig::signing::tx_builder_ringct_t signer_tx_builder;
CHECK_AND_ASSERT_MES(signer_tx_builder.init(miner_account[signer].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, true, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init"); CHECK_AND_ASSERT_MES(signer_tx_builder.init(miner_account[signer].get_keys(), {}, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, true, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init");
MDEBUG("signing with k size " << k.size()); MDEBUG("signing with k size " << k.size());
for (size_t n = 0; n < multisig::signing::kAlphaComponents; ++n) for (size_t n = 0; n < multisig::signing::kAlphaComponents; ++n)

View File

@ -122,7 +122,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector<test_event_entry
std::vector<crypto::secret_key> additional_tx_keys; std::vector<crypto::secret_key> additional_tx_keys;
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0};
bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes[n], tx_key, additional_tx_keys, true);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
events.push_back(rct_txes[n]); events.push_back(rct_txes[n]);
starting_rct_tx_hashes.push_back(get_transaction_hash(rct_txes[n])); starting_rct_tx_hashes.push_back(get_transaction_hash(rct_txes[n]));
@ -229,7 +229,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector<test_event_entry
std::vector<crypto::secret_key> additional_tx_keys; std::vector<crypto::secret_key> additional_tx_keys;
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[miner_accounts[0].get_keys().m_account_address.m_spend_public_key] = {0,0}; subaddresses[miner_accounts[0].get_keys().m_account_address.m_spend_public_key] = {0,0};
bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), tx, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
if (post_tx) if (post_tx)

View File

@ -136,7 +136,7 @@ bool gen_rct2_tx_validation_base::generate_with(std::vector<test_event_entry>& e
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0};
rct_txes.resize(rct_txes.size() + 1); rct_txes.resize(rct_txes.size() + 1);
bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), tx_key, additional_tx_keys, true, rct_config[n]);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
if (post_tx && !post_tx(rct_txes.back(), n)) if (post_tx && !post_tx(rct_txes.back(), n))

View File

@ -102,7 +102,7 @@ bool test_transaction_generation_and_ring_signature()
destinations.push_back(td); destinations.push_back(td);
transaction tx_rc1; transaction tx_rc1;
bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_rc1, 0); bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_rc1);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
crypto::hash pref_hash = get_transaction_prefix_hash(tx_rc1); crypto::hash pref_hash = get_transaction_prefix_hash(tx_rc1);

View File

@ -212,7 +212,7 @@ bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const
GENERATE_ACCOUNT(miner_account); GENERATE_ACCOUNT(miner_account);
MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
REWIND_BLOCKS_N(events, blk_1, blk_0, miner_account, 10); REWIND_BLOCKS_N(events, blk_1, blk_0, miner_account, 20);
REWIND_BLOCKS(events, blk_1r, blk_1, miner_account); REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
auto make_tx_with_unlock_time = [&](uint64_t unlock_time) -> transaction auto make_tx_with_unlock_time = [&](uint64_t unlock_time) -> transaction
@ -222,9 +222,34 @@ bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const
std::list<transaction> txs_0; std::list<transaction> txs_0;
// Let's make sure that non-zero unlock times fail with a normal relay method
SET_EVENT_VISITOR_SETT(events, 0); // set relay_method::fluff
txs_0.push_back(make_tx_with_unlock_time(0)); txs_0.push_back(make_tx_with_unlock_time(0));
events.push_back(txs_0.back()); events.push_back(txs_0.back());
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) - 1));
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r)));
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) + 1));
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) + 2));
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(make_tx_with_unlock_time(ts_start - 1));
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(make_tx_with_unlock_time(time(0) + 60 * 60));
// We want to try adding these transactions with non-zero unlock times to the pool, but relay
// rules enforce otherwise, so we set the relay method to block
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block); // set relay_method::block
txs_0.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) - 1)); txs_0.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) - 1));
events.push_back(txs_0.back()); events.push_back(txs_0.back());
@ -596,6 +621,7 @@ bool gen_tx_check_input_unlock_time::generate(std::vector<test_event_entry>& eve
events.push_back(txs_0.back()); events.push_back(txs_0.back());
}; };
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block); // set relay_method::block
uint64_t blk_3_height = get_block_height(blk_1r) + 2; uint64_t blk_3_height = get_block_height(blk_1r) + 2;
make_tx_to_acc(0, 0); make_tx_to_acc(0, 0);
make_tx_to_acc(1, blk_3_height - 1); make_tx_to_acc(1, blk_3_height - 1);
@ -604,6 +630,7 @@ bool gen_tx_check_input_unlock_time::generate(std::vector<test_event_entry>& eve
make_tx_to_acc(4, time(0) - 1); make_tx_to_acc(4, time(0) - 1);
make_tx_to_acc(5, time(0) + 60 * 60); make_tx_to_acc(5, time(0) + 60 * 60);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
SET_EVENT_VISITOR_SETT(events, 0); // set relay_method::fluff
std::list<transaction> txs_1; std::list<transaction> txs_1;
auto make_tx_from_acc = [&](size_t acc_idx, bool invalid) auto make_tx_from_acc = [&](size_t acc_idx, bool invalid)

View File

@ -107,7 +107,7 @@ bool gen_v2_tx_validation_base::generate_with(std::vector<test_event_entry>& eve
destinations.push_back(td); destinations.push_back(td);
transaction tx; transaction tx;
bool r = construct_tx(miner_accounts[0].get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx, 0); bool r = construct_tx(miner_accounts[0].get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
if (!valid) if (!valid)
DO_CALLBACK(events, "mark_invalid_tx"); DO_CALLBACK(events, "mark_invalid_tx");

View File

@ -259,7 +259,7 @@ bool construct_tx_to_key(cryptonote::transaction& tx,
{ {
vector<tx_destination_entry> destinations; vector<tx_destination_entry> destinations;
fill_tx_destinations(sender_wallet->get_account(), get_address(to), amount, fee, sources, destinations, rct); fill_tx_destinations(sender_wallet->get_account(), get_address(to), amount, fee, sources, destinations, rct);
return construct_tx_rct(sender_wallet, sources, destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); return construct_tx_rct(sender_wallet, sources, destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version);
} }
bool construct_tx_to_key(cryptonote::transaction& tx, bool construct_tx_to_key(cryptonote::transaction& tx,
@ -270,15 +270,15 @@ bool construct_tx_to_key(cryptonote::transaction& tx,
{ {
vector<tx_destination_entry> all_destinations; vector<tx_destination_entry> all_destinations;
fill_tx_destinations(sender_wallet->get_account(), destinations, fee, sources, all_destinations, rct); fill_tx_destinations(sender_wallet->get_account(), destinations, fee, sources, all_destinations, rct);
return construct_tx_rct(sender_wallet, sources, all_destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); return construct_tx_rct(sender_wallet, sources, all_destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version);
} }
bool construct_tx_rct(tools::wallet2 * sender_wallet, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, bool rct, rct::RangeProofType range_proof_type, int bp_version) bool construct_tx_rct(tools::wallet2 * sender_wallet, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, bool rct, rct::RangeProofType range_proof_type, int bp_version)
{ {
subaddresses_t & subaddresses = wallet_accessor_test::get_subaddresses(sender_wallet); subaddresses_t & subaddresses = wallet_accessor_test::get_subaddresses(sender_wallet);
crypto::secret_key tx_key; crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys; std::vector<crypto::secret_key> additional_tx_keys;
std::vector<tx_destination_entry> destinations_copy = destinations; std::vector<tx_destination_entry> destinations_copy = destinations;
rct::RCTConfig rct_config = {range_proof_type, bp_version}; rct::RCTConfig rct_config = {range_proof_type, bp_version};
return construct_tx_and_get_tx_key(sender_wallet->get_account().get_keys(), subaddresses, sources, destinations_copy, 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, change_addr, extra, tx, tx_key, additional_tx_keys, rct, rct_config);
} }

View File

@ -82,5 +82,5 @@ bool construct_tx_rct(tools::wallet2 * sender_wallet,
std::vector<cryptonote::tx_source_entry>& sources, std::vector<cryptonote::tx_source_entry>& sources,
const std::vector<cryptonote::tx_destination_entry>& destinations, const std::vector<cryptonote::tx_destination_entry>& destinations,
const boost::optional<cryptonote::account_public_address>& change_addr, const boost::optional<cryptonote::account_public_address>& change_addr,
std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, std::vector<uint8_t> extra, cryptonote::transaction& tx,
bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0); bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0);

View File

@ -85,7 +85,7 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
try try
{ {
std::vector<tools::wallet2::pending_tx> ptx; std::vector<tools::wallet2::pending_tx> ptx;
ptx = w1.create_transactions_2(dsts, mix_in_factor, 0, 0, std::vector<uint8_t>(), 0, {}); ptx = w1.create_transactions_2(dsts, mix_in_factor, 0, std::vector<uint8_t>(), 0, {});
for (auto &p: ptx) for (auto &p: ptx)
w1.commit_tx(p); w1.commit_tx(p);
return true; return true;

View File

@ -72,7 +72,7 @@ public:
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0}; subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0};
rct::RCTConfig rct_config{range_proof_type, bp_version}; rct::RCTConfig rct_config{range_proof_type, bp_version};
if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_tx, tx_key, additional_tx_keys, rct, rct_config))
return false; return false;
get_transaction_prefix_hash(m_tx, m_tx_prefix_hash); get_transaction_prefix_hash(m_tx, m_tx_prefix_hash);
@ -136,7 +136,7 @@ public:
m_txes.resize(a_num_txes + (extra_outs > 0 ? 1 : 0)); m_txes.resize(a_num_txes + (extra_outs > 0 ? 1 : 0));
for (size_t n = 0; n < a_num_txes; ++n) 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_txes[n], tx_key, additional_tx_keys, true, {rct::RangeProofPaddedBulletproof, 2}))
return false; return false;
} }
@ -147,7 +147,7 @@ public:
for (size_t n = 1; n < extra_outs; ++n) for (size_t n = 1; n < extra_outs; ++n)
destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_txes.back(), tx_key, additional_tx_keys, true, {rct::RangeProofMultiOutputBulletproof, 2}))
return false; return false;
} }

View File

@ -74,7 +74,7 @@ public:
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0}; subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0};
rct::RCTConfig rct_config{range_proof_type, bp_version}; rct::RCTConfig rct_config{range_proof_type, bp_version};
return cryptonote::construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, m_destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), 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, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_tx, tx_key, additional_tx_keys, rct, rct_config);
} }
private: private:

View File

@ -57,7 +57,7 @@ public:
std::vector<tx_destination_entry> destinations; std::vector<tx_destination_entry> destinations;
destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); 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, boost::none, std::vector<uint8_t>(), m_tx, 0)) if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, boost::none, std::vector<uint8_t>(), m_tx))
return false; return false;
const cryptonote::txin_to_key& txin = boost::get<cryptonote::txin_to_key>(m_tx.vin[0]); const cryptonote::txin_to_key& txin = boost::get<cryptonote::txin_to_key>(m_tx.vin[0]);

View File

@ -57,7 +57,7 @@ public:
std::vector<tx_destination_entry> destinations; std::vector<tx_destination_entry> destinations;
destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); 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, boost::none, std::vector<uint8_t>(), m_tx, 0)) if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, boost::none, std::vector<uint8_t>(), m_tx))
return false; return false;
const cryptonote::txin_to_key& txin = boost::get<cryptonote::txin_to_key>(m_tx.vin[0]); const cryptonote::txin_to_key& txin = boost::get<cryptonote::txin_to_key>(m_tx.vin[0]);

View File

@ -78,7 +78,7 @@ namespace test
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[from.m_account_address.m_spend_public_key] = {0,0}; subaddresses[from.m_account_address.m_spend_public_key] = {0,0};
if (!cryptonote::construct_tx_and_get_tx_key(from, subaddresses, actual_sources, to, 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, boost::none, {}, tx, tx_key, extra_keys, rct, { bulletproof ? rct::RangeProofBulletproof : rct::RangeProofBorromean, bulletproof ? 2 : 0 }))
throw std::runtime_error{"transaction construction error"}; throw std::runtime_error{"transaction construction error"};
return tx; return tx;