1
0
Fork 0
forked from lthn/blockchain

Merge branch 'multiassets' into cryptoassets

This commit is contained in:
sowle 2023-04-27 19:19:19 +02:00
commit 86e9667773
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
38 changed files with 2068 additions and 515 deletions

@ -1 +1 @@
Subproject commit 486a46e927449a5827cf3cb69731bc0e3811b46a
Subproject commit b589edb1906dccb387cfeded6ed12286c5f0405f

View file

@ -40,4 +40,5 @@
#define API_RETURN_CODE_TX_IS_TOO_BIG "TX_IS_TOO_BIG"
#define API_RETURN_CODE_TX_REJECTED "TX_REJECTED"
#define API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED "HTLC_ORIGIN_HASH_MISSMATCHED"
#define API_RETURN_CODE_WRAP "WRAP"
#define API_RETURN_CODE_WRAP "WRAP"
#define API_RETURN_CODE_MISSING_ZC_INPUTS "MISSING_ZC_INPUTS"

View file

@ -5150,6 +5150,88 @@ std::shared_ptr<const transaction_chain_entry> blockchain_storage::find_key_imag
return std::shared_ptr<const transaction_chain_entry>();
}
//---------------------------------------------------------------
bool blockchain_storage::fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short) const
{
//tei.blob = tx_ptr->tx
tei.id = epee::string_tools::pod_to_hex(h);
if (!tei.blob_size)
tei.blob_size = get_object_blobsize(tx);
tei.fee = get_tx_fee(tx);
tei.pub_key = epee::string_tools::pod_to_hex(get_tx_pub_key_from_extra(tx));
tei.timestamp = timestamp;
tei.amount = get_outs_money_amount(tx);
if (is_short)
return true;
fill_tx_rpc_inputs(tei, tx);
fill_tx_rpc_outputs(tei, tx, ptce);
fill_tx_rpc_payload_items(tei.extra, tx.extra);
fill_tx_rpc_payload_items(tei.attachments, tx.attachment);
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx) const
{
//handle inputs
for (auto in : tx.vin)
{
tei.ins.push_back(tx_in_rpc_entry());
tx_in_rpc_entry& entry_to_fill = tei.ins.back();
if (in.type() == typeid(txin_gen))
{
entry_to_fill.amount = 0;
}
else if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc) || in.type() == typeid(txin_zc_input))
{
//TODO: add htlc info
entry_to_fill.amount = get_amount_from_variant(in);
entry_to_fill.kimage_or_ms_id = epee::string_tools::pod_to_hex(get_key_image_from_txin_v(in));
const std::vector<txout_ref_v>& key_offsets = get_key_offsets_from_txin_v(in);
std::vector<txout_ref_v> absolute_offsets = relative_output_offsets_to_absolute(key_offsets);
for (auto& ao : absolute_offsets)
{
entry_to_fill.global_indexes.push_back(0);
if (ao.type() == typeid(uint64_t))
{
entry_to_fill.global_indexes.back() = boost::get<uint64_t>(ao);
}
else if (ao.type() == typeid(ref_by_id))
{
//disable for the reset at the moment
auto tx_ptr = get_tx_chain_entry(boost::get<ref_by_id>(ao).tx_id);
if (!tx_ptr || tx_ptr->m_global_output_indexes.size() <= boost::get<ref_by_id>(ao).n)
{
tei.ins.back().global_indexes.back() = std::numeric_limits<uint64_t>::max();
return false;
}
tei.ins.back().global_indexes.back() = tx_ptr->m_global_output_indexes[boost::get<ref_by_id>(ao).n];
}
}
if (in.type() == typeid(txin_htlc))
{
entry_to_fill.htlc_origin = epee::string_tools::buff_to_hex_nodelimer(boost::get<txin_htlc>(in).hltc_origin);
}
//tk.etc_details -> visualize it may be later
}
else if (in.type() == typeid(txin_multisig))
{
txin_multisig& tms = boost::get<txin_multisig>(in);
entry_to_fill.amount = tms.amount;
entry_to_fill.kimage_or_ms_id = epee::string_tools::pod_to_hex(tms.multisig_out_id);
if (tx.signatures.size() >= tei.ins.size() &&
tx.signatures[tei.ins.size() - 1].type() == typeid(NLSAG_sig))
{
entry_to_fill.multisig_count = boost::get<NLSAG_sig>(tx.signatures[tei.ins.size() - 1]).s.size();
}
}
}
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::prune_aged_alt_blocks()
{
@ -6327,15 +6409,7 @@ bool blockchain_storage::prevalidate_block(const block& bl)
return true;
}
// HF3
if ( m_core_runtime_config.is_hardfork_active_for_height(3, block_height) &&
!m_core_runtime_config.is_hardfork_active_for_height(4, block_height))
{
CHECK_AND_ASSERT_MES(bl.major_version == HF3_BLOCK_MAJOR_VERSION, false, "HF3, incorrect block major version: " << (int)bl.major_version);
}
//after hard_fork3
// >= HF3
if (bl.major_version > CURRENT_BLOCK_MAJOR_VERSION)
{
LOG_ERROR("prevalidation failed for block " << get_block_hash(bl) << ": major block version " << static_cast<size_t>(bl.major_version) << " is incorrect, " << CURRENT_BLOCK_MAJOR_VERSION << " is expected" << ENDL

View file

@ -334,6 +334,8 @@ namespace currency
// returns true as soon as the hardfork is active for the NEXT upcoming block (not for the top block in the blockchain storage)
bool is_hardfork_active(size_t hardfork_id) const;
bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx) const;
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false) const;
wide_difficulty_type block_difficulty(size_t i)const;
bool forecast_difficulty(std::vector<std::pair<uint64_t, wide_difficulty_type>> &out_height_2_diff_vector, bool pos) const;

View file

@ -56,8 +56,8 @@ namespace currency
const static crypto::key_derivation null_derivation = AUTO_VAL_INIT(null_derivation);
const static crypto::hash gdefault_genesis = epee::string_tools::hex_to_pod<crypto::hash>("CC608F59F8080E2FBFE3C8C80EB6E6A953D47CF2D6AEBD345BADA3A1CAB99852");
const static crypto::hash ffff_hash = epee::string_tools::hex_to_pod<crypto::hash>("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
const static crypto::public_key ffff_pkey = epee::string_tools::hex_to_pod<crypto::public_key>("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // TODO @#@# consider getting rid of this
//const static crypto::hash ffff_hash = epee::string_tools::hex_to_pod<crypto::hash>("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
//const static crypto::public_key ffff_pkey = epee::string_tools::hex_to_pod<crypto::public_key>("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // TODO @#@# consider getting rid of this
// TODO: rewtire the following to a normal aggregate initialization once we move to C++17 -- sowle
const static crypto::public_key native_coin_asset_id = reinterpret_cast<const crypto::public_key&>(static_cast<const crypto::ec_scalar&>(crypto::ec_scalar{'\xd6', '\x32', '\x9b', '\x5b', '\x1f', '\x7c', '\x08', '\x05', '\xb5', '\xc3', '\x45', '\xf4', '\x95', '\x75', '\x54', '\x00', '\x2a', '\x2f', '\x55', '\x78', '\x45', '\xf6', '\x4d', '\x76', '\x45', '\xda', '\xe0', '\xe0', '\x51', '\xa6', '\x49', '\x8a'})); // == crypto::c_point_H, checked in crypto_constants

View file

@ -406,7 +406,7 @@ namespace currency
tx_destination_entry de = AUTO_VAL_INIT(de);
de.addr.push_back(miner_address);
de.amount = a;
de.explicit_native_asset_id = true; // don't use asset id blinding as it's obvious which asset it is
de.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
{
//this means that block is creating after hardfork_1 and unlock_time is needed to set for every destination separately
@ -421,7 +421,7 @@ namespace currency
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
stake_lock_time = pe.stake_unlock_time;
destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address, stake_lock_time));
destinations.back().explicit_native_asset_id = true; // don't use asset id blinding as it's obvious which asset it is
destinations.back().flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is
}
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed.");
@ -1143,8 +1143,8 @@ namespace currency
blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X;
out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X)
CHECK_AND_ASSERT_MES(!de.explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
asset_blinding_mask = de.explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
CHECK_AND_ASSERT_MES(!de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
asset_blinding_mask = de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
amount_commitment = de.amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G;
out.amount_commitment = (crypto::c_scalar_1div8 * amount_commitment).to_public_key(); // E = 1/8 * e * T + 1/8 * y * G
@ -1163,8 +1163,8 @@ namespace currency
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
out.encrypted_amount = de.amount ^ amount_mask.m_u64[0];
CHECK_AND_ASSERT_MES(!de.explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
asset_blinding_mask = de.explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
CHECK_AND_ASSERT_MES(!de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
asset_blinding_mask = de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X;
out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X)
@ -1549,13 +1549,6 @@ namespace currency
crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys)
{
crypto::key_derivation derivation = null_derivation;
tx_crypto_checksum crypto_info = AUTO_VAL_INIT(crypto_info);
if (!get_type_in_variant_container(tx.extra, crypto_info) && !get_type_in_variant_container(tx.attachment, crypto_info))
{
//no crypt info in tx
return null_derivation;
}
if (is_income)
{
crypto::public_key tx_pub_key = currency::get_tx_pub_key_from_extra(tx);
@ -1563,18 +1556,25 @@ namespace currency
bool r = crypto::generate_key_derivation(tx_pub_key, acc_keys.view_secret_key, derivation);
CHECK_AND_ASSERT_MES(r, null_derivation, "failed to generate_key_derivation");
LOG_PRINT_GREEN("DECRYPTING ON KEY: " << epee::string_tools::pod_to_hex(derivation) << ", key derived from destination addr: " << currency::get_account_address_as_str(acc_keys.account_address), LOG_LEVEL_0);
return derivation;
}
else
{
tx_crypto_checksum crypto_info = AUTO_VAL_INIT(crypto_info);
if (!get_type_in_variant_container(tx.extra, crypto_info) && !get_type_in_variant_container(tx.attachment, crypto_info))
{
//no crypt info in tx
return null_derivation;
}
derivation = crypto_info.encrypted_key_derivation;
crypto::chacha_crypt(derivation, acc_keys.spend_secret_key);
LOG_PRINT_GREEN("DECRYPTING ON KEY: " << epee::string_tools::pod_to_hex(derivation) << ", key decrypted from sender address: " << currency::get_account_address_as_str(acc_keys.account_address), LOG_LEVEL_0);
//validate derivation we here. Yoda style
crypto::hash hash_for_check_sum = crypto::cn_fast_hash(&derivation, sizeof(derivation));
CHECK_AND_ASSERT_MES(*(uint32_t*)&hash_for_check_sum == crypto_info.derivation_hash, null_derivation, "Derivation hash missmatched in tx id " << currency::get_transaction_hash(tx));
return derivation;
}
//validate derivation we here. Yoda style
crypto::hash hash_for_check_sum = crypto::cn_fast_hash(&derivation, sizeof(derivation));
CHECK_AND_ASSERT_MES(*(uint32_t*)&hash_for_check_sum == crypto_info.derivation_hash, null_derivation, "Derivation hash missmatched in tx id " << currency::get_transaction_hash(tx));
return derivation;
}
//---------------------------------------------------------------
template<class total_t_container>
@ -1612,9 +1612,8 @@ namespace currency
}
//---------------------------------------------------------------
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key)
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation)
{
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
bool r = crypto::generate_key_derivation(destination_addr.view_public_key, tx_random_key.sec, derivation);
CHECK_AND_ASSERT_MES(r, void(), "failed to generate_key_derivation");
bool was_attachment_crypted_entries = false;
@ -1645,6 +1644,12 @@ namespace currency
}
}
//---------------------------------------------------------------
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key)
{
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
return encrypt_attachments(tx, sender_keys, destination_addr, tx_random_key, derivation);
}
//---------------------------------------------------------------
void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x)
{
x.is_service = currency::is_service_tx(x.tx);
@ -2022,7 +2027,8 @@ namespace currency
append_mode = true;
keypair txkey = AUTO_VAL_INIT(txkey);
size_t zc_inputs_count = 0;
bool has_non_zc_inputs = false;
if (!append_mode)
{
@ -2052,7 +2058,7 @@ namespace currency
//include offers if need
tx.attachment = attachments;
encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, txkey);
encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, txkey, result.derivation);
}
else
{
@ -2061,7 +2067,8 @@ namespace currency
CHECK_AND_ASSERT_MES(txkey.pub != null_pkey && txkey.sec != null_skey, false, "In append mode both public and secret keys must be provided");
//separately encrypt attachments without putting extra
crypto::key_derivation derivation = get_encryption_key_derivation(true, tx, sender_account_keys);
result.derivation = get_encryption_key_derivation(true, tx, sender_account_keys);
crypto::key_derivation& derivation = result.derivation;
CHECK_AND_ASSERT_MES(derivation != null_derivation, false, "failed to generate_key_derivation");
bool was_attachment_crypted_entries = false;
std::vector<extra_v> extra_local = extra;
@ -2076,9 +2083,20 @@ namespace currency
tx.attachment.insert(tx.attachment.end(), attachments_local.begin(), attachments_local.end());
tx.extra.insert(tx.extra.end(), extra_local.begin(), extra_local.end());
for (const auto in : tx.vin)
{
if (in.type() == typeid(txin_zc_input))
{
zc_inputs_count++;
}
else {
has_non_zc_inputs = true;
}
}
}
size_t thirdparty_zc_inputs_count = zc_inputs_count;
//
// INs
//
@ -2088,7 +2106,6 @@ namespace currency
size_t current_index = 0;
inputs_mapping.resize(sources.size());
size_t input_starter_index = tx.vin.size();
size_t zc_inputs_count = 0;
bool all_inputs_are_obviously_native_coins = true;
for (const tx_source_entry& src_entr : sources)
{
@ -2107,6 +2124,7 @@ namespace currency
input_multisig.multisig_out_id = src_entr.multisig_id;
input_multisig.sigs_count = src_entr.ms_sigs_count;
tx.vin.push_back(input_multisig);
has_non_zc_inputs = true;
}
else if (src_entr.htlc_origin.size())
{
@ -2141,6 +2159,7 @@ namespace currency
input_to_key.key_offsets.push_back(src_entr.outputs.front().out_reference);
tx.vin.push_back(input_to_key);
has_non_zc_inputs = true;
}
else
{
@ -2183,6 +2202,7 @@ namespace currency
input_to_key.k_image = img;
input_to_key.key_offsets = std::move(key_offsets);
tx.vin.push_back(input_to_key);
has_non_zc_inputs = true;
}
}
@ -2203,15 +2223,15 @@ namespace currency
}
}
}
bool has_non_zc_inputs = zc_inputs_count != sources.size(); // TODO @#@# reconsider this for consilidated txs
//
// OUTs
//
std::vector<tx_destination_entry> shuffled_dsts(destinations);
size_t outputs_to_be_constructed = shuffled_dsts.size();
//size_t outputs_to_be_constructed = shuffled_dsts.size();
tx_generation_context& gen_context = result.ftp.gen_context;
gen_context.resize(zc_inputs_count, outputs_to_be_constructed);
gen_context.resize(zc_inputs_count, tx.vout.size() + shuffled_dsts.size());
// ASSET oprations handling
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
@ -2235,7 +2255,7 @@ namespace currency
uint64_t amount_of_emitted_asset = 0;
for (auto& item : shuffled_dsts)
{
if (item.asset_id == currency::ffff_pkey)
if (item.asset_id == currency::null_pkey)
{
item.asset_id = gen_context.ao_asset_id; // set calculated asset_id to the asset's outputs, if this asset is being emitted within this tx
amount_of_emitted_asset += item.amount;
@ -2259,24 +2279,24 @@ namespace currency
// construct outputs
uint64_t native_coins_output_sum = 0;
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1
uint64_t range_proof_start_index = output_index;
uint64_t range_proof_start_index = 0;
std::set<uint16_t> deriv_cache;
for(size_t j = 0; j < outputs_to_be_constructed; ++j, ++output_index)
for(size_t destination_index = 0; destination_index < shuffled_dsts.size(); ++destination_index, ++output_index)
{
tx_destination_entry& dst_entr = shuffled_dsts[j];
if (all_inputs_are_obviously_native_coins && gen_context.ao_asset_id == currency::null_pkey)
dst_entr.explicit_native_asset_id = true; // all inputs are obviously native coins -- all outputs must have explicit asset ids (unless there's an asset emission)
tx_destination_entry& dst_entr = shuffled_dsts[destination_index];
if (!append_mode && all_inputs_are_obviously_native_coins && gen_context.ao_asset_id == currency::null_pkey)
dst_entr.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // all inputs are obviously native coins -- all outputs must have explicit asset ids (unless there's an asset emission)
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount); // <<-- TODO @#@# consider removing this check
r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys,
gen_context.asset_id_blinding_masks[j], gen_context.amount_blinding_masks[j],
gen_context.blinded_asset_ids[j], gen_context.amount_commitments[j], result, tx_outs_attr);
gen_context.asset_id_blinding_masks[output_index], gen_context.amount_blinding_masks[output_index],
gen_context.blinded_asset_ids[output_index], gen_context.amount_commitments[output_index], result, tx_outs_attr);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct tx out");
gen_context.amounts[j] = dst_entr.amount;
gen_context.asset_ids[j] = crypto::point_t(dst_entr.asset_id);
gen_context.asset_id_blinding_mask_x_amount_sum += gen_context.asset_id_blinding_masks[j] * dst_entr.amount;
gen_context.amount_blinding_masks_sum += gen_context.amount_blinding_masks[j];
gen_context.amount_commitments_sum += gen_context.amount_commitments[j];
gen_context.amounts[output_index] = dst_entr.amount;
gen_context.asset_ids[output_index] = crypto::point_t(dst_entr.asset_id);
gen_context.asset_id_blinding_mask_x_amount_sum += gen_context.asset_id_blinding_masks[output_index] * dst_entr.amount;
gen_context.amount_blinding_masks_sum += gen_context.amount_blinding_masks[output_index];
gen_context.amount_commitments_sum += gen_context.amount_commitments[output_index];
if (dst_entr.is_native_coin())
native_coins_output_sum += dst_entr.amount;
}
@ -2311,8 +2331,16 @@ namespace currency
std::sort(tx.vin.begin() + input_starter_index, tx.vin.end(), less_txin_v);
// add explicit fee info
r = add_tx_fee_amount_to_extra(tx, native_coins_input_sum - native_coins_output_sum);
CHECK_AND_ASSERT_MES(r, false, "add_tx_fee_amount_to_extra failed");
uint64_t fee_to_declare = native_coins_input_sum - native_coins_output_sum;
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
{
fee_to_declare = ftp.mode_separate_fee;
}
if (fee_to_declare)
{
r = add_tx_fee_amount_to_extra(tx, fee_to_declare);
CHECK_AND_ASSERT_MES(r, false, "add_tx_fee_amount_to_extra failed");
}
}
// attachments container should be sealed by now
@ -2348,13 +2376,13 @@ namespace currency
// ring signatures (per-input proofs)
r = false;
size_t curren_zc_index = thirdparty_zc_inputs_count;
for (size_t i_ = 0; i_ != sources.size(); i_++)
{
size_t i_mapped = inputs_mapping[i_];
const tx_source_entry& source_entry = sources[i_mapped];
crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, i_ + input_starter_index, tx_prefix_hash);
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed");
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed");
std::stringstream ss_ring_s;
if (source_entry.is_zc())
@ -2363,6 +2391,8 @@ namespace currency
// blinding_masks_sum is supposed to be sum(mask of all tx output) - sum(masks of all pseudo out commitments)
r = generate_ZC_sig(tx_hash_for_signature, i_ + input_starter_index, source_entry, in_contexts[i_mapped], sender_account_keys, flags, gen_context, tx, i_ + 1 == sources.size());
CHECK_AND_ASSERT_MES(r, false, "generate_ZC_sigs failed");
gen_context.zc_input_amounts[curren_zc_index] = source_entry.amount;
curren_zc_index++;
}
else
{
@ -2377,7 +2407,8 @@ namespace currency
//
// proofs (transaction-wise, not pre-input)
//
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
if (tx.version > TRANSACTION_VERSION_PRE_HF4 &&
(append_mode || (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) == 0))
{
// asset surjection proof
currency::zc_asset_surjection_proof asp{};
@ -3502,7 +3533,7 @@ namespace currency
}
if (p_amount_burnt)
*p_amount_burnt = sum_of_bare_outs_burnt;
return sum_of_bare_outs_burnt == amount;
return sum_of_bare_outs_burnt >= amount;
}
// post HF-4 txs
@ -3564,235 +3595,7 @@ namespace currency
return cnt;
}
struct rpc_tx_payload_handler : public boost::static_visitor<bool>
{
tx_extra_rpc_entry& tv;
rpc_tx_payload_handler(tx_extra_rpc_entry& t) : tv(t)
{}
bool operator()(const tx_service_attachment& ee)
{
tv.type = "service";
tv.short_view = ee.service_id + ":" + ee.instruction;
if (ee.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY)
tv.short_view += "(encrypted)";
else
{
std::string deflated_buff;
const std::string* pfinalbuff = &ee.body;
if (ee.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY)
{
bool r = epee::zlib_helper::unpack(ee.body, deflated_buff);
CHECK_AND_ASSERT_MES(r, false, "Failed to unpack");
pfinalbuff = &deflated_buff;
}
if (ee.service_id == BC_PAYMENT_ID_SERVICE_ID || ee.service_id == BC_OFFERS_SERVICE_ID)
tv.details_view = *pfinalbuff;
else
tv.details_view = "BINARY DATA";
}
return true;
}
bool operator()(const tx_crypto_checksum& ee)
{
tv.type = "crypto_checksum";
tv.short_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash);
tv.details_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash) + "\n"
+ "encrypted_key_derivation: " + epee::string_tools::pod_to_hex(ee.encrypted_key_derivation);
return true;
}
bool operator()(const etc_tx_time& ee)
{
tv.type = "pos_time";
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_unlock_time& ee)
{
tv.type = "unlock_time";
if (ee.v < CURRENCY_MAX_BLOCK_NUMBER)
tv.short_view = std::string("height: ") + std::to_string(ee.v);
else
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_unlock_time2& ee)
{
tv.type = "unlock_time";
std::stringstream ss;
ss << "[";
for (auto v : ee.unlock_time_array)
{
ss << " " << v;
}
ss << "]";
tv.short_view = ss.str();
return true;
}
bool operator()(const etc_tx_details_expiration_time& ee)
{
tv.type = "expiration_time";
if (ee.v < CURRENCY_MAX_BLOCK_NUMBER)
tv.short_view = std::string("height: ") + std::to_string(ee.v);
else
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_flags& ee)
{
tv.type = "details_flags";
tv.short_view = epee::string_tools::pod_to_hex(ee.v);
return true;
}
bool operator()(const crypto::public_key& ee)
{
tv.type = "pub_key";
tv.short_view = epee::string_tools::pod_to_hex(ee);
return true;
}
bool operator()(const extra_attachment_info& ee)
{
tv.type = "attachment_info";
tv.short_view = std::to_string(ee.sz) + " bytes";
tv.details_view = currency::obj_to_json_str(ee);
return true;
}
bool operator()(const extra_alias_entry& ee)
{
tv.type = "alias_info";
tv.short_view = ee.m_alias + "-->" + get_account_address_as_str(ee.m_address);
tv.details_view = currency::obj_to_json_str(ee);
return true;
}
bool operator()(const extra_alias_entry_old& ee)
{
return operator()(static_cast<const extra_alias_entry&>(ee));
}
bool operator()(const extra_user_data& ee)
{
tv.type = "user_data";
tv.short_view = std::to_string(ee.buff.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.buff);
return true;
}
bool operator()(const extra_padding& ee)
{
tv.type = "extra_padding";
tv.short_view = std::to_string(ee.buff.size()) + " bytes";
if (!ee.buff.empty())
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(&ee.buff[0]), ee.buff.size()));
return true;
}
bool operator()(const tx_comment& ee)
{
tv.type = "comment";
tv.short_view = std::to_string(ee.comment.size()) + " bytes(encrypted)";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.comment);
return true;
}
bool operator()(const tx_payer& ee)
{
//const tx_payer& ee = boost::get<tx_payer>(extra);
tv.type = "payer";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_payer_old&)
{
tv.type = "payer_old";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_receiver& ee)
{
//const tx_payer& ee = boost::get<tx_payer>(extra);
tv.type = "receiver";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_receiver_old& ee)
{
tv.type = "receiver_old";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_derivation_hint& ee)
{
tv.type = "derivation_hint";
tv.short_view = std::to_string(ee.msg.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.msg);
return true;
}
bool operator()(const std::string& ee)
{
tv.type = "string";
tv.short_view = std::to_string(ee.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee);
return true;
}
bool operator()(const etc_tx_flags16_t& dh)
{
tv.type = "FLAGS16";
tv.short_view = epee::string_tools::pod_to_hex(dh);
tv.details_view = epee::string_tools::pod_to_hex(dh);
return true;
}
bool operator()(const zarcanum_tx_data_v1& ztxd)
{
tv.type = "zarcanum_tx_data_v1";
tv.short_view = "fee = " + print_money_brief(ztxd.fee);
tv.details_view = tv.short_view;
return true;
}
bool operator()(const zc_outs_range_proof& rp)
{
tv.type = "zc_outs_range_proof";
// TODO @#@#
//tv.short_view = "outputs_count = " + std::to_string(rp.outputs_count);
return true;
}
bool operator()(const zc_balance_proof& bp)
{
tv.type = "zc_balance_proof";
return true;
}
template<typename t_type>
bool operator()(const t_type& t_t)
{
tv.type = typeid(t_t).name();
return true;
}
};
//------------------------------------------------------------------
template<class t_container>
bool fill_tx_rpc_payload_items(std::vector<tx_extra_rpc_entry>& target_vector, const t_container& tc)
{
//handle extra
for (auto& extra : tc)
{
target_vector.push_back(tx_extra_rpc_entry());
tx_extra_rpc_entry& tv = target_vector.back();
rpc_tx_payload_handler vstr(tv);
boost::apply_visitor(vstr, extra);
}
return true;
}
//------------------------------------------------------------------
bool fill_tx_rpc_outputs(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce)
{
@ -3913,28 +3716,7 @@ namespace currency
pei_rpc.penalty = (pei_rpc.base_reward + pei_rpc.total_fee) - pei_rpc.summary_reward;
return true;
}
//---------------------------------------------------------------
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short)
{
//tei.blob = tx_ptr->tx
tei.id = epee::string_tools::pod_to_hex(h);
if(!tei.blob_size)
tei.blob_size = get_object_blobsize(tx);
tei.fee = get_tx_fee(tx);
tei.pub_key = epee::string_tools::pod_to_hex(get_tx_pub_key_from_extra(tx));
tei.timestamp = timestamp;
tei.amount = get_outs_money_amount(tx);
if (is_short)
return true;
fill_tx_rpc_inputs(tei, tx);
fill_tx_rpc_outputs(tei, tx, ptce);
fill_tx_rpc_payload_items(tei.extra, tx.extra);
fill_tx_rpc_payload_items(tei.attachments, tx.attachment);
return true;
}
//------------------------------------------------------------------
void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map<uint64_t, uint32_t>& gindices)
{

View file

@ -29,6 +29,9 @@
#include "currency_format_utils_transactions.h"
#include "core_runtime_config.h"
#include "wallet/wallet_public_structs_defs.h"
#include "bc_attachments_helpers.h"
#include "bc_payments_id_service.h"
#include "bc_offers_service_basic.h"
// ------ get_tx_type_definition -------------
@ -139,6 +142,7 @@ namespace currency
struct finalize_tx_param
{
uint64_t unlock_time;
std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments;
@ -153,6 +157,7 @@ namespace currency
uint64_t expiration_time;
crypto::public_key spend_pub_key; // only for validations
uint64_t tx_version;
uint64_t mode_separate_fee = 0;
tx_generation_context gen_context{}; // solely for consolidated txs
@ -171,6 +176,7 @@ namespace currency
FIELD(expiration_time)
FIELD(spend_pub_key)
FIELD(tx_version)
FIELD(mode_separate_fee)
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
FIELD(gen_context);
END_SERIALIZE()
@ -183,6 +189,7 @@ namespace currency
finalize_tx_param ftp;
std::string htlc_origin;
std::vector<serializable_pair<uint64_t, crypto::key_image>> outs_key_images; // pairs (out_index, key_image) for each change output
crypto::key_derivation derivation;
BEGIN_SERIALIZE_OBJECT()
FIELD(tx)
@ -190,6 +197,7 @@ namespace currency
FIELD(ftp)
FIELD(htlc_origin)
FIELD(outs_key_images)
FIELD(derivation)
END_SERIALIZE()
};
@ -339,6 +347,7 @@ namespace currency
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time);
crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys);
bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector<payload_items_v>& decrypted_items);
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation);
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key);
bool is_derivation_used_to_encrypt(const transaction& tx, const crypto::key_derivation& derivation);
bool is_address_like_wrapped(const std::string& addr);
@ -414,8 +423,7 @@ namespace currency
update_alias_rpc_details alias_info_to_rpc_update_alias_info(const currency::extra_alias_entry& ai, const std::string& old_address);
size_t get_service_attachments_count_in_tx(const transaction& tx);
bool fill_tx_rpc_outputs(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce);
bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx);
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false);
bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h);
void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map<uint64_t, uint32_t>& gindices);
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password);
@ -891,5 +899,236 @@ namespace currency
const difficulties& b_diff
);
struct rpc_tx_payload_handler : public boost::static_visitor<bool>
{
tx_extra_rpc_entry& tv;
rpc_tx_payload_handler(tx_extra_rpc_entry& t) : tv(t)
{}
bool operator()(const tx_service_attachment& ee)
{
tv.type = "service";
tv.short_view = ee.service_id + ":" + ee.instruction;
if (ee.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY)
tv.short_view += "(encrypted)";
else
{
std::string deflated_buff;
const std::string* pfinalbuff = &ee.body;
if (ee.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY)
{
bool r = epee::zlib_helper::unpack(ee.body, deflated_buff);
CHECK_AND_ASSERT_MES(r, false, "Failed to unpack");
pfinalbuff = &deflated_buff;
}
if (ee.service_id == BC_PAYMENT_ID_SERVICE_ID || ee.service_id == BC_OFFERS_SERVICE_ID)
tv.details_view = *pfinalbuff;
else
tv.details_view = "BINARY DATA";
}
return true;
}
bool operator()(const tx_crypto_checksum& ee)
{
tv.type = "crypto_checksum";
tv.short_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash);
tv.details_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash) + "\n"
+ "encrypted_key_derivation: " + epee::string_tools::pod_to_hex(ee.encrypted_key_derivation);
return true;
}
bool operator()(const etc_tx_time& ee)
{
tv.type = "pos_time";
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_unlock_time& ee)
{
tv.type = "unlock_time";
if (ee.v < CURRENCY_MAX_BLOCK_NUMBER)
tv.short_view = std::string("height: ") + std::to_string(ee.v);
else
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_unlock_time2& ee)
{
tv.type = "unlock_time";
std::stringstream ss;
ss << "[";
for (auto v : ee.unlock_time_array)
{
ss << " " << v;
}
ss << "]";
tv.short_view = ss.str();
return true;
}
bool operator()(const etc_tx_details_expiration_time& ee)
{
tv.type = "expiration_time";
if (ee.v < CURRENCY_MAX_BLOCK_NUMBER)
tv.short_view = std::string("height: ") + std::to_string(ee.v);
else
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_flags& ee)
{
tv.type = "details_flags";
tv.short_view = epee::string_tools::pod_to_hex(ee.v);
return true;
}
bool operator()(const crypto::public_key& ee)
{
tv.type = "pub_key";
tv.short_view = epee::string_tools::pod_to_hex(ee);
return true;
}
bool operator()(const extra_attachment_info& ee)
{
tv.type = "attachment_info";
tv.short_view = std::to_string(ee.sz) + " bytes";
tv.details_view = currency::obj_to_json_str(ee);
return true;
}
bool operator()(const extra_alias_entry& ee)
{
tv.type = "alias_info";
tv.short_view = ee.m_alias + "-->" + get_account_address_as_str(ee.m_address);
tv.details_view = currency::obj_to_json_str(ee);
return true;
}
bool operator()(const extra_alias_entry_old& ee)
{
return operator()(static_cast<const extra_alias_entry&>(ee));
}
bool operator()(const extra_user_data& ee)
{
tv.type = "user_data";
tv.short_view = std::to_string(ee.buff.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.buff);
return true;
}
bool operator()(const extra_padding& ee)
{
tv.type = "extra_padding";
tv.short_view = std::to_string(ee.buff.size()) + " bytes";
if (!ee.buff.empty())
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(&ee.buff[0]), ee.buff.size()));
return true;
}
bool operator()(const tx_comment& ee)
{
tv.type = "comment";
tv.short_view = std::to_string(ee.comment.size()) + " bytes(encrypted)";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.comment);
return true;
}
bool operator()(const tx_payer& ee)
{
//const tx_payer& ee = boost::get<tx_payer>(extra);
tv.type = "payer";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_payer_old&)
{
tv.type = "payer_old";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_receiver& ee)
{
//const tx_payer& ee = boost::get<tx_payer>(extra);
tv.type = "receiver";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_receiver_old& ee)
{
tv.type = "receiver_old";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_derivation_hint& ee)
{
tv.type = "derivation_hint";
tv.short_view = std::to_string(ee.msg.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.msg);
return true;
}
bool operator()(const std::string& ee)
{
tv.type = "string";
tv.short_view = std::to_string(ee.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee);
return true;
}
bool operator()(const etc_tx_flags16_t& dh)
{
tv.type = "FLAGS16";
tv.short_view = epee::string_tools::pod_to_hex(dh);
tv.details_view = epee::string_tools::pod_to_hex(dh);
return true;
}
bool operator()(const zarcanum_tx_data_v1& ztxd)
{
tv.type = "zarcanum_tx_data_v1";
tv.short_view = "fee = " + print_money_brief(ztxd.fee);
tv.details_view = tv.short_view;
return true;
}
bool operator()(const zc_outs_range_proof& rp)
{
tv.type = "zc_outs_range_proof";
// TODO @#@#
//tv.short_view = "outputs_count = " + std::to_string(rp.outputs_count);
return true;
}
bool operator()(const zc_balance_proof& bp)
{
tv.type = "zc_balance_proof";
return true;
}
template<typename t_type>
bool operator()(const t_type& t_t)
{
tv.type = typeid(t_t).name();
return true;
}
};
//------------------------------------------------------------------
template<class t_container>
bool fill_tx_rpc_payload_items(std::vector<tx_extra_rpc_entry>& target_vector, const t_container& tc)
{
//handle extra
for (auto& extra : tc)
{
target_vector.push_back(tx_extra_rpc_entry());
tx_extra_rpc_entry& tv = target_vector.back();
rpc_tx_payload_handler vstr(tv);
boost::apply_visitor(vstr, extra);
}
return true;
}
} // namespace currency

View file

@ -397,5 +397,14 @@ namespace currency
CATCH_ENTRY2(std::vector<tx_source_entry::output_entry>{});
}
//---------------------------------------------------------------
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key)
{
//TODO: Implement this function before mainnet
#ifdef TESTNET
return true;
#else
return false;
#endif
}
}

View file

@ -94,6 +94,13 @@ namespace currency
};
enum tx_destination_entry_flags
{
tdef_none = 0,
tdef_explicit_native_asset_id = 0x0001,
tdef_explicit_amount_to_provide = 0x0002
};
struct tx_destination_entry
{
uint64_t amount = 0; // money
@ -103,7 +110,7 @@ namespace currency
uint64_t unlock_time = 0;
destination_option_htlc_out htlc_options; // htlc options
crypto::public_key asset_id = currency::native_coin_asset_id; // not blinded, not premultiplied
bool explicit_native_asset_id = false;
uint64_t flags = 0; // set of flags (see tx_destination_entry_flags)
tx_destination_entry() = default;
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad) {}
@ -123,7 +130,7 @@ namespace currency
FIELD(unlock_time)
FIELD(htlc_options)
FIELD(asset_id)
FIELD(explicit_native_asset_id)
FIELD(flags)
END_SERIALIZE()
};
//---------------------------------------------------------------
@ -201,7 +208,7 @@ namespace currency
bool tx_to_blob(const transaction& b, blobdata& b_blob);
bool read_keyimages_from_tx(const transaction& tx, std::list<crypto::key_image>& kil);
bool validate_inputs_sorting(const transaction& tx);
bool is_asset_emitting_transaction(const transaction& tx, asset_descriptor_operation* p_ado = nullptr);
bool is_asset_emitting_transaction(const transaction& tx, asset_descriptor_operation* p_ado = nullptr);
std::vector<tx_source_entry::output_entry> prepare_outputs_entries_for_key_offsets(const std::vector<tx_source_entry::output_entry>& outputs, size_t old_real_index, size_t& new_real_index) noexcept;
@ -218,6 +225,7 @@ namespace currency
asset_id_blinding_masks.resize(outs_count);
amounts.resize(outs_count);
amount_blinding_masks.resize(outs_count);
zc_input_amounts.resize(zc_ins_count);
}
// TODO @#@# reconsider this check -- sowle
@ -245,6 +253,7 @@ namespace currency
std::vector<crypto::point_t> pseudo_outs_blinded_asset_ids; // generate_asset_surjection_proof
crypto::scalar_vec_t pseudo_outs_plus_real_out_blinding_masks; // r_pi + r'_j // generate_asset_surjection_proof
std::vector<crypto::point_t> real_zc_ins_asset_ids; // H_i // generate_asset_surjection_proof
std::vector<uint64_t> zc_input_amounts; // ZC only input amounts
// common data: inputs
crypto::point_t pseudo_out_amount_commitments_sum = crypto::c_point_0; // generate_tx_balance_proof generate_ZC_sig
@ -264,44 +273,48 @@ namespace currency
// consider redesign, some data may possibly be excluded from kv serialization -- sowle
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_ids);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blinded_asset_ids);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_commitments);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_id_blinding_masks);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amounts);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_blinding_masks);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_blinded_asset_ids);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_plus_real_out_blinding_masks);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(real_zc_ins_asset_ids);
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_commitments_sum);
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_blinding_masks_sum);
KV_SERIALIZE_POD_AS_HEX_STRING(real_in_asset_id_blinding_mask_x_amount_sum);
KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitments_sum);
KV_SERIALIZE_POD_AS_HEX_STRING(amount_blinding_masks_sum);
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id_blinding_mask_x_amount_sum);
KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id);
KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id_pt);
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_commitment);
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_blinding_mask);
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_commitments)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_id_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amounts)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_plus_real_out_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(real_zc_ins_asset_ids)
KV_SERIALIZE(zc_input_amounts)
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_commitments_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_blinding_masks_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(real_in_asset_id_blinding_mask_x_amount_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitments_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(amount_blinding_masks_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id_blinding_mask_x_amount_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id_pt)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_commitment)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_blinding_mask)
END_KV_SERIALIZE_MAP()
// solely for consolidated txs, asset opration fields are not serialized
BEGIN_SERIALIZE_OBJECT()
FIELD(asset_ids);
FIELD(blinded_asset_ids);
FIELD(amount_commitments);
FIELD((std::vector<crypto::scalar_t>&)(asset_id_blinding_masks));
FIELD((std::vector<crypto::scalar_t>&)(amounts));
FIELD((std::vector<crypto::scalar_t>&)(amount_blinding_masks));
FIELD(pseudo_outs_blinded_asset_ids);
FIELD((std::vector<crypto::scalar_t>&)(pseudo_outs_plus_real_out_blinding_masks));
FIELD(real_zc_ins_asset_ids);
FIELD(pseudo_out_amount_commitments_sum);
FIELD(pseudo_out_amount_blinding_masks_sum);
FIELD(real_in_asset_id_blinding_mask_x_amount_sum);
FIELD(amount_commitments_sum);
FIELD(amount_blinding_masks_sum);
FIELD(asset_id_blinding_mask_x_amount_sum);
VERSION()
CURRENT_VERSION(0)
FIELD(asset_ids)
FIELD(blinded_asset_ids)
FIELD(amount_commitments)
FIELD((std::vector<crypto::scalar_t>&)(asset_id_blinding_masks))
FIELD((std::vector<crypto::scalar_t>&)(amounts))
FIELD((std::vector<crypto::scalar_t>&)(amount_blinding_masks))
FIELD(pseudo_outs_blinded_asset_ids)
FIELD((std::vector<crypto::scalar_t>&)(pseudo_outs_plus_real_out_blinding_masks))
FIELD(real_zc_ins_asset_ids)
FIELD(zc_input_amounts)
FIELD(pseudo_out_amount_commitments_sum)
FIELD(pseudo_out_amount_blinding_masks_sum)
FIELD(real_in_asset_id_blinding_mask_x_amount_sum)
FIELD(amount_commitments_sum)
FIELD(amount_blinding_masks_sum)
FIELD(asset_id_blinding_mask_x_amount_sum)
// no asset operation fields here
//ao_asset_id
@ -311,4 +324,6 @@ namespace currency
END_SERIALIZE()
}; // struct tx_generation_context
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key);
} // namespace currency

View file

@ -516,7 +516,7 @@ namespace currency
txs.push_back(tx_rpc_extended_info());
tx_rpc_extended_info& trei = txs.back();
trei.blob_size = tx_entry.blob_size;
fill_tx_rpc_details(trei, tx_entry.tx, nullptr, h, tx_entry.receive_time, true);
m_blockchain.fill_tx_rpc_details(trei, tx_entry.tx, nullptr, h, tx_entry.receive_time, true);
return true;
});
@ -568,7 +568,7 @@ namespace currency
txs.push_back(tx_rpc_extended_info());
tx_rpc_extended_info& trei = txs.back();
trei.blob_size = ptei->blob_size;
fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
m_blockchain.fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
}
return true;
}
@ -605,7 +605,7 @@ namespace currency
if (!ptei)
return false;
fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
m_blockchain.fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
return true;
}
//---------------------------------------------------------------------------------

View file

@ -18,6 +18,7 @@
#define PREPARE_ARG_FROM_JSON(arg_type, var_name) \
arg_type var_name = AUTO_VAL_INIT(var_name); \
view::api_response default_ar = AUTO_VAL_INIT(default_ar); \
LOG_PRINT_BLUE("[REQUEST]: " << param.toStdString(), LOG_LEVEL_3); \
if (!epee::serialization::load_t_from_json(var_name, param.toStdString())) \
{ \
default_ar.error_code = API_RETURN_CODE_BAD_ARG; \
@ -28,6 +29,7 @@ template<typename T>
QString make_response(const T& r)
{
std::string str = epee::serialization::store_t_to_json(r);
LOG_PRINT_BLUE("[RESPONSE]: " << str, LOG_LEVEL_3);
return str.c_str();
}
@ -549,6 +551,14 @@ void MainWindow::store_pos(bool consider_showed)
void MainWindow::restore_pos(bool consider_showed)
{
TRY_ENTRY();
if (consider_showed)
{
if (m_config.is_showed)
this->showNormal();
else
this->showMinimized();
}
if (m_config.is_maximazed)
{
this->setWindowState(windowState() | Qt::WindowMaximized);
@ -580,14 +590,6 @@ void MainWindow::restore_pos(bool consider_showed)
}
}
if (consider_showed)
{
if (m_config.is_showed)
this->showNormal();
else
this->showMinimized();
}
CATCH_ENTRY2(void());
}
void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
@ -2160,7 +2162,39 @@ QString MainWindow::get_wallet_info(const QString& param)
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::create_ionic_swap_proposal(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::create_ionic_swap_proposal_request, cispr);
PREPARE_RESPONSE(std::string, ar);
ar.error_code = m_backend.create_ionic_swap_proposal(cispr.wallet_id, cispr, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_ionic_swap_proposal_info(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::api_request_t<std::string>, tx_raw_hex);
PREPARE_RESPONSE(tools::wallet_public::ionic_swap_proposal_info, ar);
ar.error_code = m_backend.get_ionic_swap_proposal_info(tx_raw_hex.wallet_id, tx_raw_hex.req_data, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::accept_ionic_swap_proposal(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::api_request_t<std::string>, tx_raw_hex);
PREPARE_RESPONSE(std::string, ar);
ar.error_code = m_backend.accept_ionic_swap_proposal(tx_raw_hex.wallet_id, tx_raw_hex.req_data, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::backup_wallet_keys(const QString& param)
{
TRY_ENTRY();

View file

@ -172,6 +172,9 @@ public:
QString remove_custom_asset_id(const QString& param);
QString get_wallet_info(const QString& param);
QString create_ionic_swap_proposal(const QString& param);
QString get_ionic_swap_proposal_info(const QString& param);
QString accept_ionic_swap_proposal(const QString& param);
bool get_is_disabled_notifications();
bool set_is_disabled_notifications(const bool& param);

View file

@ -63,8 +63,8 @@ inline bool do_serialize(Archive &ar, T &v)
#define BEGIN_SERIALIZE() \
template <bool W, template <bool> class Archive> bool do_serialize(Archive<W> &_ser_ar) {uint8_t s_current_version ATTRIBUTE_UNUSED = 0; uint8_t s_version ATTRIBUTE_UNUSED = 0;
#define BEGIN_SERIALIZE_OBJECT() \
template <bool W, template <bool> class Archive> bool do_serialize(Archive<W> &_ser_ar) { _ser_ar.begin_object(); bool _ser_res = do_serialize_object(_ser_ar); _ser_ar.end_object(); return _ser_res; } \
template <bool W, template <bool> class Archive> bool do_serialize_object(Archive<W> &_ser_ar){
template <bool W, template <bool> class Archive> bool do_serialize(Archive<W> &_ser_ar) {_ser_ar.begin_object(); bool _ser_res = do_serialize_object(_ser_ar); _ser_ar.end_object(); return _ser_res; } \
template <bool W, template <bool> class Archive> bool do_serialize_object(Archive<W> &_ser_ar){ uint8_t s_current_version ATTRIBUTE_UNUSED = 0; uint8_t s_version ATTRIBUTE_UNUSED = 0;
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) ::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving())
#define END_SERIALIZE() return true;}

View file

@ -4,6 +4,10 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <cstdlib>
#if defined(WIN32)
#include <crtdbg.h>
#endif
#include <thread>
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
@ -22,11 +26,10 @@
#include "string_coding.h"
#include "wallet/wrap_service.h"
#include "common/general_purpose_commands_defs.h"
#include <cstdlib>
#if defined(WIN32)
#include <crtdbg.h>
#endif
#include "wallet/wallet_helpers.h"
using namespace std;
using namespace epee;
@ -229,6 +232,10 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("add_custom_asset_id", boost::bind(&simple_wallet::add_custom_asset_id, this, ph::_1), "Approve asset id to be recognized in the wallet and returned in balances");
m_cmd_binder.set_handler("remove_custom_asset_id", boost::bind(&simple_wallet::remove_custom_asset_id, this, ph::_1), "Cancel previously made approval for asset id");
m_cmd_binder.set_handler("generate_ionic_swap_proposal", boost::bind(&simple_wallet::generate_ionic_swap_proposal, this, _1), "generate_ionic_swap_proposal <proposal_config.json> <destination_addr>- Generates ionic_swap proposal with given conditions");
m_cmd_binder.set_handler("get_ionic_swap_proposal_info", boost::bind(&simple_wallet::get_ionic_swap_proposal_info, this, _1), "get_ionic_swap_proposal_info <hex_encoded_raw_proposal> - Extracts and display information from ionic_swap proposal raw data");
m_cmd_binder.set_handler("accept_ionic_swap_proposal", boost::bind(&simple_wallet::accept_ionic_swap_proposal, this, _1), "accept_ionic_swap_proposal <hex_encoded_raw_proposal> - Accept ionic_swap proposal and generates exchange transaction");
}
//----------------------------------------------------------------------------------------------------
simple_wallet::~simple_wallet()
@ -691,6 +698,17 @@ void simple_wallet::on_tor_status_change(const std::string& state)
message_writer(epee::log_space::console_color_yellow, true, std::string("[TOR]: ")) << human_message;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets)
{
wallets.resize(1);
tools::get_wallet_info(*m_wallet, wallets[0].wi);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::on_mw_select_wallet(uint64_t wallet_id)
{
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::refresh(const std::vector<std::string>& args)
{
if (m_offline_mode)
@ -1801,7 +1819,7 @@ bool simple_wallet::deploy_new_asset(const std::vector<std::string> &args)
tx_destination_entry td = AUTO_VAL_INIT(td);
td.addr.push_back(m_wallet->get_account().get_public_address());
td.amount = adb.current_supply;
td.asset_id = currency::ffff_pkey;
td.asset_id = currency::null_pkey;
std::vector<currency::tx_destination_entry> destinations;
destinations.push_back(td);
currency::transaction result_tx = AUTO_VAL_INIT(result_tx);
@ -1849,6 +1867,104 @@ bool simple_wallet::add_custom_asset_id(const std::vector<std::string> &args)
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::generate_ionic_swap_proposal(const std::vector<std::string> &args)
{
if (args.size() != 2)
{
fail_msg_writer() << "invalid arguments count: " << args.size() << ", expected 1";
}
view::ionic_swap_proposal_info proposal = AUTO_VAL_INIT(proposal);
bool r = epee::serialization::load_t_from_json_file(proposal, args[0]);
if (!r)
{
fail_msg_writer() << "Failed to load json file with asset specification: " << args[0];
}
currency::account_public_address destination_addr = AUTO_VAL_INIT(destination_addr);
currency::payment_id_t integrated_payment_id;
if (!m_wallet->get_transfer_address(args[1], destination_addr, integrated_payment_id))
{
fail_msg_writer() << "wrong address: " << args[1];
return true;
}
if (integrated_payment_id.size())
{
fail_msg_writer() << "Integrated addresses not supported yet";
return true;
}
transaction tx_template = AUTO_VAL_INIT(tx_template);
r = m_wallet->create_ionic_swap_proposal(proposal, destination_addr, tx_template);
if (!r)
{
fail_msg_writer() << "Failed to create ionic_swap proposal";
return true;
}
else
{
success_msg_writer() << "Generated proposal: " << ENDL << epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx_template));
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::get_ionic_swap_proposal_info(const std::vector<std::string> &args)
{
if (args.size() != 1)
{
fail_msg_writer() << "invalid arguments count: " << args.size() << ", expected 1";
}
std::string raw_tx_template;
bool r = epee::string_tools::parse_hexstr_to_binbuff(args[0], raw_tx_template);
if (!r)
{
fail_msg_writer() << "Failed to parse proposal hex to raw data";
return true;
}
view::ionic_swap_proposal_info proposal = AUTO_VAL_INIT(proposal);
if (!m_wallet->get_ionic_swap_proposal_info(raw_tx_template, proposal))
{
fail_msg_writer() << "Failed to decode proposal info";
return true;
}
std::string json_proposal = epee::serialization::store_t_to_json(proposal);
success_msg_writer() << "Proposal details: " << ENDL << json_proposal;
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::accept_ionic_swap_proposal(const std::vector<std::string> &args)
{
if (args.size() != 1)
{
fail_msg_writer() << "invalid arguments count: " << args.size() << ", expected 1";
}
std::string raw_tx_template;
bool r = epee::string_tools::parse_hexstr_to_binbuff(args[0], raw_tx_template);
if (!r)
{
fail_msg_writer() << "Failed to parse proposal hex to raw data";
return true;
}
currency::transaction result_tx = AUTO_VAL_INIT(result_tx);
if (!m_wallet->accept_ionic_swap_proposal(raw_tx_template, result_tx))
{
fail_msg_writer() << "Failed accept ionic_swap proposal";
return true;
}
success_msg_writer() << "Proposal accepted and executed, tx_id : " << currency::get_transaction_hash(result_tx);
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::remove_custom_asset_id(const std::vector<std::string> &args)
{
@ -2239,7 +2355,8 @@ int main(int argc, char* argv[])
if (daemon_address.empty())
daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
tools::wallet2 wal;
std::shared_ptr<tools::wallet2> wallet_ptr(new tools::wallet2());
tools::wallet2& wal = *wallet_ptr;
//try to open it
while (true)
{
@ -2295,7 +2412,7 @@ int main(int argc, char* argv[])
}
}
tools::wallet_rpc_server wrpc(wal);
tools::wallet_rpc_server wrpc(wallet_ptr);
bool r = wrpc.init(vm);
CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "Failed to initialize wallet rpc server");

View file

@ -92,6 +92,11 @@ namespace currency
bool add_custom_asset_id(const std::vector<std::string> &args);
bool remove_custom_asset_id(const std::vector<std::string> &args);
//----------------------------------------------------------------------------------------------------
bool generate_ionic_swap_proposal(const std::vector<std::string> &args);
bool get_ionic_swap_proposal_info(const std::vector<std::string> &args);
bool accept_ionic_swap_proposal(const std::vector<std::string> &args);
bool validate_wrap_status(uint64_t amount);
bool get_alias_from_daemon(const std::string& alias_name, currency::extra_alias_entry_base& ai);
@ -106,6 +111,8 @@ namespace currency
virtual void on_message(i_wallet2_callback::message_severity severity, const std::string& m) override;
virtual void on_tor_status_change(const std::string& state) override;
virtual void on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets) override;
virtual bool on_mw_select_wallet(uint64_t wallet_id) override;
//----------------------------------------------------------
friend class refresh_progress_reporter_t;
@ -178,7 +185,7 @@ namespace currency
epee::console_handlers_binder m_cmd_binder;
std::unique_ptr<tools::wallet2> m_wallet;
std::shared_ptr<tools::wallet2> m_wallet;
net_utils::http::http_simple_client m_http_client;
refresh_progress_reporter_t m_refresh_progress_reporter;
};

View file

@ -209,40 +209,9 @@ public:
END_KV_SERIALIZE_MAP()
};
struct wallet_info
{
std::list<tools::wallet_public::asset_balance_entry> balances;
uint64_t mined_total;
std::string address;
std::string view_sec_key;
std::string path;
bool is_auditable;
bool is_watch_only;
typedef tools::wallet_public::wallet_info wallet_info;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balances)
KV_SERIALIZE(mined_total)
KV_SERIALIZE(address)
KV_SERIALIZE(view_sec_key)
KV_SERIALIZE(path)
KV_SERIALIZE(is_auditable);
KV_SERIALIZE(is_watch_only);
END_KV_SERIALIZE_MAP()
};
struct wallet_entry_info
{
wallet_info wi;
uint64_t wallet_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wi)
KV_SERIALIZE(wallet_id)
END_KV_SERIALIZE_MAP()
};
typedef tools::wallet_public::wallet_entry_info wallet_entry_info;
@ -440,7 +409,7 @@ public:
struct wallet_and_asset_id
{
uint64_t wallet_id = 0;
crypto::hash asset_id = currency::null_hash;
crypto::public_key asset_id = currency::null_pkey;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wallet_id)
@ -686,14 +655,11 @@ public:
};
struct wallet_and_contract_id_param
{
uint64_t wallet_id;
crypto::hash contract_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wallet_id)
KV_SERIALIZE_POD_AS_HEX_STRING(contract_id)
@ -742,6 +708,11 @@ public:
END_KV_SERIALIZE_MAP()
};
typedef tools::wallet_public::asset_funds asset_funds;
typedef tools::wallet_public::ionic_swap_proposal_info ionic_swap_proposal_info;
typedef tools::wallet_public::create_ionic_swap_proposal_request create_ionic_swap_proposal_request;
struct address_validation_response
{
std::string error_code;

View file

@ -42,6 +42,8 @@ using namespace epee;
using namespace currency;
#define SET_CONTEXT_OBJ_FOR_SCOPE(name, obj) m_current_context.name = &obj; \
auto COMBINE(auto_scope_var_, __LINE__) = epee::misc_utils::create_scope_leave_handler([&]() { m_current_context.name = nullptr; });
#define MINIMUM_REQUIRED_WALLET_FREE_SPACE_BYTES (100*1024*1024) // 100 MB
@ -934,7 +936,9 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
construct_tx_param construct_param = AUTO_VAL_INIT(construct_param);
construct_param.fee = b_acceptance_fee;
currency::transaction tx = contr_it->second.proposal.tx_template;
mode_separate_context msc = AUTO_VAL_INIT(msc);
msc.tx_for_mode_separate = contr_it->second.proposal.tx_template;
currency::transaction& tx = msc.tx_for_mode_separate;
crypto::secret_key one_time_key = contr_it->second.proposal.tx_onetime_secret_key;
construct_param.crypt_address = m_account.get_public_address();
construct_param.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE;
@ -992,7 +996,7 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
//build transaction
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
ftp.tx_version = this->get_current_tx_version();
prepare_transaction(construct_param, ftp, tx);
prepare_transaction(construct_param, ftp, msc);
mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been accepted with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">");
try
@ -4739,7 +4743,7 @@ void wallet2::build_escrow_template(const bc_services::contract_private_details&
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
ftp.tx_version = this->get_current_tx_version();
prepare_transaction(ctp, ftp, tx);
prepare_transaction(ctp, ftp);
selected_transfers = ftp.selected_transfers;
@ -4991,6 +4995,337 @@ bool wallet2::check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& o
return false;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::create_ionic_swap_proposal(const wallet_public::ionic_swap_proposal_info& proposal_details, const currency::account_public_address& destination_addr, wallet_public::ionic_swap_proposal& proposal)
{
std::vector<uint64_t> selected_transfers_for_template;
build_ionic_swap_template(proposal_details, destination_addr, proposal, selected_transfers_for_template);
const uint32_t mask_to_mark_escrow_template_locked_transfers = WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION;
mark_transfers_with_flag(selected_transfers_for_template, mask_to_mark_escrow_template_locked_transfers, "preparing ionic_swap");
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal_info& proposal_detais, const currency::account_public_address& destination_addr,
wallet_public::ionic_swap_proposal& proposal,
std::vector<uint64_t>& selected_transfers)
{
construct_tx_param ctp = get_default_construct_tx_param();
ctp.fake_outputs_count = proposal_detais.mixins;
ctp.fee = proposal_detais.fee_paid_by_a;
ctp.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE;
ctp.mark_tx_as_complete = false;
ctp.crypt_address = destination_addr;
etc_tx_details_expiration_time t = AUTO_VAL_INIT(t);
t.v = proposal_detais.expiration_time;
ctp.extra.push_back(t);
ctp.dsts.resize(proposal_detais.to_bob.size() + proposal_detais.to_alice.size());
size_t i = 0;
// Here is an proposed for exchange funds
for (; i != proposal_detais.to_bob.size(); i++)
{
ctp.dsts[i].amount = proposal_detais.to_bob[i].amount;
ctp.dsts[i].amount_to_provide = proposal_detais.to_bob[i].amount;
ctp.dsts[i].flags |= tx_destination_entry_flags::tdef_explicit_amount_to_provide;
ctp.dsts[i].addr.push_back(destination_addr);
ctp.dsts[i].asset_id = proposal_detais.to_bob[i].asset_id;
}
// Here is an expected in return funds
for (size_t j = 0; j != proposal_detais.to_alice.size(); j++, i++)
{
ctp.dsts[i].amount = proposal_detais.to_alice[j].amount;
ctp.dsts[i].amount_to_provide = 0;
ctp.dsts[i].flags |= tx_destination_entry_flags::tdef_explicit_amount_to_provide;
ctp.dsts[i].addr.push_back(m_account.get_public_address());
ctp.dsts[i].asset_id = proposal_detais.to_alice[j].asset_id;
}
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
ftp.mode_separate_fee = ctp.fee;
ftp.tx_version = this->get_current_tx_version();
prepare_transaction(ctp, ftp);
selected_transfers = ftp.selected_transfers;
currency::finalized_tx finalize_result = AUTO_VAL_INIT(finalize_result);
finalize_transaction(ftp, finalize_result, false);
add_transfers_to_expiration_list(selected_transfers, proposal_detais.expiration_time, 0, currency::null_hash);
//wrap it all
proposal.tx_template = finalize_result.tx;
wallet_public::ionic_swap_proposal_context ispc = AUTO_VAL_INIT(ispc);
ispc.gen_context = finalize_result.ftp.gen_context;
ispc.one_time_skey = finalize_result.one_time_key;
std::string proposal_context_blob = t_serializable_object_to_blob(ispc);
proposal.encrypted_context = crypto::chacha_crypt(static_cast<const std::string&>(proposal_context_blob), finalize_result.derivation);
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_ionic_swap_proposal_info(const std::string&raw_proposal, wallet_public::ionic_swap_proposal_info& proposal_info)
{
wallet_public::ionic_swap_proposal proposal = AUTO_VAL_INIT(proposal);
bool r = t_unserializable_object_from_blob(proposal, raw_proposal);
THROW_IF_TRUE_WALLET_EX(!r, error::wallet_internal_error, "Failed to parse proposal");
return get_ionic_swap_proposal_info(proposal, proposal_info);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_proposal& proposal, wallet_public::ionic_swap_proposal_info& proposal_info)
{
wallet_public::ionic_swap_proposal_context ionic_context = AUTO_VAL_INIT(ionic_context);
return get_ionic_swap_proposal_info(proposal, proposal_info, ionic_context);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_proposal& proposal, wallet_public::ionic_swap_proposal_info& proposal_info, wallet_public::ionic_swap_proposal_context& ionic_context)
{
const transaction& tx = proposal.tx_template;
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
std::vector<wallet_out_info> outs;
uint64_t tx_money_got_in_outs = 0;
bool r = lookup_acc_outs(m_account.get_keys(), tx, outs, tx_money_got_in_outs, derivation);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to lookup_acc_outs for tx: " << get_transaction_hash(tx));
if (!outs.size())
{
return false;
}
//decrypt context
std::string decrypted_raw_context = crypto::chacha_crypt(proposal.encrypted_context, derivation);
r = t_unserializable_object_from_blob(ionic_context, decrypted_raw_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to unserialize decrypted ionic_context");
r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context, ionic_context.one_time_skey);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to validate decrypted ionic_context");
std::unordered_map<crypto::public_key, uint64_t> amounts_provided_by_a;
std::unordered_map<crypto::public_key, uint64_t> ammounts_to_a; //amounts to Alice (the one who created proposal), should be NOT funded
std::unordered_map<crypto::public_key, uint64_t> ammounts_to_b; //amounts to Bob (the one who received proposal), should BE funded
std::vector<bool> bob_outs;
bob_outs.resize(proposal.tx_template.vout.size());
for (const auto& o : outs)
{
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids.size() > o.index, "Tx gen context has mismatch with tx(asset_ids) ");
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids[o.index].to_public_key() == o.asset_id, "Tx gen context has mismatch with tx(asset_id != asset_id) ");
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.amounts[o.index].m_u64[0] == o.amount, "Tx gen context has mismatch with tx(amount != amount)");
ammounts_to_b[o.asset_id] += o.amount;
bob_outs[o.index] = true;
}
size_t i = 0;
//validate outputs against decrypted tx generation context
for (i = 0; i != tx.vout.size(); i++)
{
if (bob_outs[i])
{
continue;
}
crypto::public_key asset_id = ionic_context.gen_context.asset_ids[i].to_public_key();
uint64_t amount = ionic_context.gen_context.amounts[i].m_u64[0];
ammounts_to_a[asset_id] += amount;
}
//read amounts already provided by third party
size_t zc_current_index = 0; //some inputs might be old ones, so it's asset id assumed as native and there is no entry for it in real_zc_ins_asset_ids
//THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.input_amounts.size() == tx.vin.size(), "Tx gen context has mismatch with tx(amount != amount)");
for (i = 0; i != tx.vin.size(); i++)
{
size_t mx = 0;
uint64_t amount = 0;
crypto::public_key in_asset_id = currency::native_coin_asset_id;
if (tx.vin[i].type() == typeid(txin_zc_input))
{
in_asset_id = ionic_context.gen_context.real_zc_ins_asset_ids[zc_current_index].to_public_key();
amount = ionic_context.gen_context.zc_input_amounts[zc_current_index];
zc_current_index++;
mx = boost::get<currency::txin_zc_input>(tx.vin[i]).key_offsets.size() - 1;
}
else if (tx.vin[i].type() == typeid(txin_to_key))
{
amount = boost::get<txin_to_key>(tx.vin[i]).amount;
mx = boost::get<currency::txin_to_key>(tx.vin[i]).key_offsets.size() - 1;
}
else
{
WLT_LOG_RED("Unexpected type of input in ionic_swap tx: " << tx.vin[i].type().name(), LOG_LEVEL_0);
return false;
}
amounts_provided_by_a[in_asset_id] += amount;
if (proposal_info.mixins == 0 || proposal_info.mixins > mx)
{
proposal_info.mixins = mx;
}
}
//this might be 0, if Alice don't want to pay fee herself
proposal_info.fee_paid_by_a = currency::get_tx_fee(tx);
if (proposal_info.fee_paid_by_a)
{
THROW_IF_FALSE_WALLET_INT_ERR_EX(amounts_provided_by_a[currency::native_coin_asset_id] >= proposal_info.fee_paid_by_a, "Fee mentioned as specified but not provided by A");
amounts_provided_by_a[currency::native_coin_asset_id] -= proposal_info.fee_paid_by_a;
}
//proposal_info.fee = currency::get_tx_fee(tx);
//need to make sure that funds for Bob properly funded
for (const auto& a : ammounts_to_b)
{
uint64_t amount_sent_back_to_alice = ammounts_to_a[a.first];
if (amounts_provided_by_a[a.first] < (a.second + amount_sent_back_to_alice) )
{
WLT_LOG_RED("Amount[" << a.first << "] provided by Alice(" << amounts_provided_by_a[a.first] << ") is less then transfered to Bob(" << a.second <<")", LOG_LEVEL_0);
return false;
}
amounts_provided_by_a[a.first] -= (amount_sent_back_to_alice + a.second);
proposal_info.to_bob.push_back(view::asset_funds{ a.first, a.second });
//clean accounted assets
ammounts_to_a.erase(ammounts_to_a.find(a.first));
if (amounts_provided_by_a[a.first] > 0)
{
WLT_LOG_RED("Amount[" << a.first << "] provided by Alice has unused leftovers: " << amounts_provided_by_a[a.first], LOG_LEVEL_0);
return false;
}
}
//need to see what Alice actually expect in return
for (const auto& a : ammounts_to_a)
{
//now amount provided by A should be less or equal to what we have in a.second
if (amounts_provided_by_a[a.first] > a.second)
{
//could be fee
WLT_LOG_RED("Amount[" << a.first << "] provided by Alice has unused leftovers: " << amounts_provided_by_a[a.first], LOG_LEVEL_0);
return false;
}
proposal_info.to_alice.push_back(view::asset_funds{ a.first, a.second - amounts_provided_by_a[a.first] });
}
etc_tx_details_expiration_time t = AUTO_VAL_INIT(t);
if (!get_type_in_variant_container(tx.extra, t))
{
return false;
}
proposal_info.expiration_time = t.v;
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::accept_ionic_swap_proposal(const std::string& raw_proposal, currency::transaction& result_tx)
{
wallet_public::ionic_swap_proposal proposal = AUTO_VAL_INIT(proposal);
bool r = t_unserializable_object_from_blob(proposal, raw_proposal);
THROW_IF_TRUE_WALLET_EX(!r, error::wallet_internal_error, "Failed to parse proposal info");
return accept_ionic_swap_proposal(proposal, result_tx);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposal& proposal, currency::transaction& result_tx)
{
mode_separate_context msc = AUTO_VAL_INIT(msc);
msc.tx_for_mode_separate = proposal.tx_template;
result_tx = msc.tx_for_mode_separate;
wallet_public::ionic_swap_proposal_context ionic_context = AUTO_VAL_INIT(ionic_context);
bool r = get_ionic_swap_proposal_info(proposal, msc.proposal_info, ionic_context);
THROW_IF_TRUE_WALLET_EX(!r, error::wallet_internal_error, "Failed to get info from proposal");
std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances;
uint64_t mined = 0;
this->balance(balances, mined);
//validate balances needed
uint64_t native_amount_required = 0;
for (const auto& item : msc.proposal_info.to_alice)
{
if (balances[item.asset_id].unlocked < item.amount)
{
return false;
}
if (item.asset_id == currency::native_coin_asset_id)
{
native_amount_required = item.amount;
}
}
// balances is ok, check if fee is added to tx
uint64_t additional_fee = 0;
if (msc.proposal_info.fee_paid_by_a < m_core_runtime_config.tx_default_fee)
{
additional_fee = m_core_runtime_config.tx_default_fee - msc.proposal_info.fee_paid_by_a;
if (balances[currency::native_coin_asset_id].unlocked < additional_fee + native_amount_required)
{
return false;
}
}
//everything is seemed to be ok
construct_tx_param construct_param = get_default_construct_tx_param();
construct_param.fee = additional_fee;
crypto::secret_key one_time_key = ionic_context.one_time_skey;
construct_param.crypt_address = m_account.get_public_address();
construct_param.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE;
construct_param.mark_tx_as_complete = true;
//build transaction
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
ftp.tx_version = this->get_current_tx_version();
ftp.gen_context = ionic_context.gen_context;
prepare_transaction(construct_param, ftp, msc);
try
{
finalize_transaction(ftp, result_tx, one_time_key, true);
}
catch (...)
{
clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception in finalize_transaction, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(result_tx)));
throw;
}
mark_transfers_as_spent(ftp.selected_transfers, std::string("Proposal has been accepted with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(result_tx))) + ">");
return true;
}
//----------------------------------------------------------------------------------------------------
// Signing and auth
bool wallet2::sign_buffer(const std::string& buff, crypto::signature& sig)
{
crypto::hash h = crypto::cn_fast_hash(buff.data(), buff.size());
crypto::generate_signature(h, m_account.get_public_address().spend_public_key, m_account.get_keys().spend_secret_key, sig);
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::validate_sign(const std::string& buff, const crypto::signature& sig, const crypto::public_key& pkey)
{
crypto::hash h = crypto::cn_fast_hash(buff.data(), buff.size());
return crypto::check_signature(h, pkey, sig);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::encrypt_buffer(const std::string& buff, std::string& res_buff)
{
res_buff = buff;
crypto::chacha_crypt(res_buff, m_account.get_keys().view_secret_key);
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::decrypt_buffer(const std::string& buff, std::string& res_buff)
{
res_buff = buff;
crypto::chacha_crypt(res_buff, m_account.get_keys().view_secret_key);
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
{
prepare_free_transfers_cache(fake_outputs_count);
@ -5271,16 +5606,21 @@ assets_selection_context wallet2::get_needed_money(uint64_t fee, const std::vect
amounts_map[currency::native_coin_asset_id].needed_amount = fee;
for(auto& dt : dsts)
{
if(dt.asset_id == currency::ffff_pkey)
if(dt.asset_id == currency::null_pkey)
continue; //this destination for emmition only
THROW_IF_TRUE_WALLET_EX(0 == dt.amount, error::zero_destination);
uint64_t money_to_add = dt.amount;
if (dt.amount_to_provide)
if (dt.amount_to_provide || dt.flags & tx_destination_entry_flags::tdef_explicit_amount_to_provide)
money_to_add = dt.amount_to_provide;
amounts_map[dt.asset_id].needed_amount += money_to_add;
THROW_IF_TRUE_WALLET_EX(amounts_map[dt.asset_id].needed_amount < money_to_add, error::tx_sum_overflow, dsts, fee);
//clean up empty entries
if (amounts_map[dt.asset_id].needed_amount == 0)
{
amounts_map.erase(amounts_map.find(dt.asset_id));
}
}
return std::move(amounts_map);
}
@ -5559,6 +5899,38 @@ bool wallet2::get_actual_offers(std::list<bc_services::offer_details_ex>& offers
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::expand_selection_with_zc_input(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes)
{
free_amounts_cache_type& found_free_amounts = m_found_free_amounts[currency::native_coin_asset_id];
auto& asset_needed_money_item = needed_money_map[currency::native_coin_asset_id];
//need to add ZC input
for (auto it = found_free_amounts.begin(); it != found_free_amounts.end(); it++)
{
for (auto it_in_amount = it->second.begin(); it_in_amount != it->second.end(); it_in_amount++)
{
if (!m_transfers[*it_in_amount].is_zc())
{
continue;
}
if (is_transfer_ready_to_go(m_transfers[*it->second.begin()], fake_outputs_count))
{
asset_needed_money_item.found_amount += it->first;
selected_indexes.push_back(*it_in_amount);
it->second.erase(it_in_amount);
if (!it->second.size())
{
found_free_amounts.erase(it);
}
return true;
}
}
}
WLT_THROW_IF_FALSE_WALLET_EX_MES(false , error::no_zc_inputs, "Missing ZC inputs for TX_FLAG_SIGNATURE_MODE_SEPARATE operation");
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes)
{
bool res = true;
@ -5570,6 +5942,24 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money
item.second.found_amount = select_indices_for_transfer(selected_indexes, asset_cashe_it->second, item.second.needed_amount, fake_outputs_count);
WLT_THROW_IF_FALSE_WALLET_EX_MES(item.second.found_amount >= item.second.needed_amount, error::not_enough_money, "", item.second.found_amount, item.second.needed_amount, 0, item.first);
}
if (m_current_context.pconstruct_tx_param && m_current_context.pconstruct_tx_param->need_at_least_1_zc)
{
bool found_zc_input = false;
for (auto i : selected_indexes)
{
if (m_transfers[i].is_zc())
{
found_zc_input = true;
break;
}
}
if (!found_zc_input)
{
expand_selection_with_zc_input(needed_money_map, fake_outputs_count, selected_indexes);
}
}
return res;
}
//----------------------------------------------------------------------------------------------------
@ -5577,6 +5967,7 @@ uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_in
{
WLT_LOG_GREEN("Selecting indices for transfer of " << print_money_brief(needed_money) << " with " << fake_outputs_count << " fake outs, found_free_amounts.size()=" << found_free_amounts.size() << "...", LOG_LEVEL_0);
uint64_t found_money = 0;
//uint64_t found_zc_input = false;
std::string selected_amounts_str;
while (found_money < needed_money && found_free_amounts.size())
{
@ -5598,6 +5989,7 @@ uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_in
found_free_amounts.erase(it);
}
WLT_LOG_GREEN("Found " << print_money_brief(found_money) << " as " << selected_indexes.size() << " out(s): " << selected_amounts_str << ", found_free_amounts.size()=" << found_free_amounts.size(), LOG_LEVEL_0);
return found_money;
}
@ -5721,11 +6113,16 @@ bool wallet2::read_money_transfer2_details_from_tx(const transaction& tx, const
else if (i.type() == typeid(currency::txin_zc_input))
{
const currency::txin_zc_input& in_zc = boost::get<currency::txin_zc_input>(i);
auto it = m_key_images.find(in_zc.k_image);
//should we panic if image not found?
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_key_images.end(), "[read_money_transfer2_details_from_tx]Unknown key image in tx: " << get_transaction_hash(tx));
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "[read_money_transfer2_details_from_tx]Index out of range for key image in tx: " << get_transaction_hash(tx));
wtd.spn.push_back(m_transfers[it->second].amount());
//@zoidberg: nope!
if (m_key_images.count(in_zc.k_image))
{
auto it = m_key_images.find(in_zc.k_image);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_key_images.end(), "[read_money_transfer2_details_from_tx]Unknown key image in tx: " << get_transaction_hash(tx));
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "[read_money_transfer2_details_from_tx]Index out of range for key image in tx: " << get_transaction_hash(tx));
wtd.spn.push_back(m_transfers[it->second].amount());
}
}
}
return true;
@ -5917,7 +6314,7 @@ void wallet2::prepare_tx_destinations(const assets_selection_context& needed_mon
{
// special case for asset minting destinations
for (auto& dst : dsts)
if (dst.asset_id == currency::ffff_pkey)
if (dst.asset_id == currency::null_pkey)
final_destinations.emplace_back(dst.amount, dst.addr, dst.asset_id);
// if there's not ehough destinations items (i.e. outputs), split the last one
@ -5976,20 +6373,29 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money,
}
}
//----------------------------------------------------------------------------------------------------
void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate /* = currency::transaction() */)
void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& mode_separatemode_separate)
{
SET_CONTEXT_OBJ_FOR_SCOPE(pconstruct_tx_param, ctp);
SET_CONTEXT_OBJ_FOR_SCOPE(pfinalize_tx_param, ftp);
SET_CONTEXT_OBJ_FOR_SCOPE(pmode_separate_context, mode_separatemode_separate);
TIME_MEASURE_START_MS(get_needed_money_time);
const currency::transaction& tx_for_mode_separate = mode_separatemode_separate.tx_for_mode_separate;
assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts);
//
// TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id
//
if (ctp.flags & TX_FLAG_SIGNATURE_MODE_SEPARATE && tx_for_mode_separate.vout.size() )
{
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(get_tx_flags(tx_for_mode_separate) & TX_FLAG_SIGNATURE_MODE_SEPARATE, "tx_param.flags differs from tx.flags");
needed_money_map[currency::null_pkey].needed_amount += (currency::get_outs_money_amount(tx_for_mode_separate) - get_inputs_money_amount(tx_for_mode_separate));
for (const auto& el : mode_separatemode_separate.proposal_info.to_alice)
{
needed_money_map[el.asset_id].needed_amount += el.amount;
}
ctp.need_at_least_1_zc = true;
}
TIME_MEASURE_FINISH_MS(get_needed_money_time);
@ -6004,15 +6410,15 @@ void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
{
//htlc
//@#@ need to do refactoring over this part to support hidden amounts and asset_id
prepare_tx_sources_htlc(ctp.htlc_tx_id, ctp.htlc_origin, ftp.sources, needed_money_map[currency::null_pkey].found_amount);
prepare_tx_sources_htlc(ctp.htlc_tx_id, ctp.htlc_origin, ftp.sources, needed_money_map[currency::native_coin_asset_id].found_amount);
WLT_THROW_IF_FALSE_WITH_CODE(ctp.dsts.size() == 1,
"htlc: unexpected ctp.dsts.size() =" << ctp.dsts.size(), API_RETURN_CODE_INTERNAL_ERROR);
WLT_THROW_IF_FALSE_WITH_CODE(needed_money_map[currency::null_pkey].found_amount > ctp.fee,
WLT_THROW_IF_FALSE_WITH_CODE(needed_money_map[currency::native_coin_asset_id].found_amount > ctp.fee,
"htlc: found money less then fee", API_RETURN_CODE_INTERNAL_ERROR);
//fill amount
ctp.dsts.begin()->amount = needed_money_map[currency::null_pkey].found_amount - ctp.fee;
ctp.dsts.begin()->amount = needed_money_map[currency::native_coin_asset_id].found_amount - ctp.fee;
}
else if (ctp.multisig_id != currency::null_hash)

View file

@ -44,6 +44,7 @@
#include "wallet_chain_shortener.h"
#include "tor-connect/torlib/tor_lib_iface.h"
#include "currency_core/pos_mining.h"
#include "view_iface.h"
#define WALLET_DEFAULT_TX_SPENDABLE_AGE 10
@ -126,6 +127,10 @@ namespace tools
virtual void on_transfer_canceled(const wallet_public::wallet_transfer_info& wti) {}
virtual void on_message(message_severity /*severity*/, const std::string& /*m*/) {}
virtual void on_tor_status_change(const std::string& state) {}
//mw api
virtual void on_mw_get_wallets(std::vector<wallet_public::wallet_entry_info>& wallets) {}
virtual bool on_mw_select_wallet(uint64_t wallet_id) { return true; }
};
struct tx_dust_policy
@ -295,8 +300,15 @@ namespace tools
uint8_t tx_outs_attr = 0;
bool shuffle = false;
bool perform_packing = false;
bool need_at_least_1_zc = false;
};
struct mode_separate_context
{
currency::transaction tx_for_mode_separate;
view::ionic_swap_proposal_info proposal_info;
};
struct selection_for_amount
{
@ -458,6 +470,21 @@ namespace tools
crypto::hash related_tx_id = currency::null_hash; // tx id which caused money lock, if any (ex: escrow proposal transport tx)
};
/*
This might be not the best solution so far, but after discussion with @sowle we came up to conclusion
that passing great variety of arguments through the long call stack of different member functions of the wallet will
only complicate codebase and make it harder to understand.
current_operation_context will keep pointers to some useful data, and every function that use it, should
make sure(!!!) that pointer got nulled before pointed object got destroyed, likely by using SET_CONTEXT_OBJ_FOR_SCOPE macro
*/
struct current_operation_context
{
construct_tx_param* pconstruct_tx_param = nullptr;
currency::finalize_tx_param* pfinalize_tx_param = nullptr;
const mode_separate_context* pmode_separate_context = nullptr;
};
typedef std::unordered_multimap<std::string, payment_details> payment_container;
@ -559,6 +586,7 @@ namespace tools
//i_wallet2_callback* callback() const { return m_wcallback; }
//void callback(i_wallet2_callback* callback) { m_callback = callback; }
void callback(std::shared_ptr<i_wallet2_callback> callback) { m_wcallback = callback; m_do_rise_transfer = (callback != nullptr); }
i_wallet2_callback* get_callback() { return m_wcallback.get(); }
void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; }
bool has_related_alias_entry_unconfirmed(const currency::transaction& tx);
@ -903,7 +931,7 @@ namespace tools
const std::list<expiration_entry_info>& get_expiration_entries() const { return m_money_expirations; };
bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const;
void prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate = currency::transaction());
void prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& emode_separate = mode_separate_context());
void finalize_transaction(const currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key = true);
void finalize_transaction(const currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key = true );
@ -934,13 +962,29 @@ namespace tools
void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin, currency::transaction& result_tx);
void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin);
bool check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& origin, crypto::hash& redeem_tx_id);
// ionic swaps:
bool create_ionic_swap_proposal(const wallet_public::ionic_swap_proposal_info& proposal_details, const currency::account_public_address& destination_addr, wallet_public::ionic_swap_proposal& proposal);
bool build_ionic_swap_template(const wallet_public::ionic_swap_proposal_info& proposal_detais, const currency::account_public_address& destination_addr,
wallet_public::ionic_swap_proposal& proposal,
std::vector<uint64_t>& selected_transfers_for_template);
bool get_ionic_swap_proposal_info(const std::string&raw_proposal, wallet_public::ionic_swap_proposal_info& proposal_info);
bool get_ionic_swap_proposal_info(const wallet_public::ionic_swap_proposal& proposal, wallet_public::ionic_swap_proposal_info& proposal_info);
bool get_ionic_swap_proposal_info(const wallet_public::ionic_swap_proposal& proposal, wallet_public::ionic_swap_proposal_info& proposal_info, wallet_public::ionic_swap_proposal_context& ionic_context);
bool accept_ionic_swap_proposal(const std::string& raw_proposal, currency::transaction& result_tx);
bool accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposal& proposal, currency::transaction& result_tx);
// Signing and auth
bool sign_buffer(const std::string& buff, crypto::signature& sig);
bool validate_sign(const std::string& buff, const crypto::signature& sig, const crypto::public_key& pkey);
bool encrypt_buffer(const std::string& buff, std::string& res_buff);
bool decrypt_buffer(const std::string& buff, std::string& res_buff);
private:
// -------- t_transport_state_notifier ------------------------------------------------
virtual void notify_state_change(const std::string& state_code, const std::string& details = std::string());
// ------------------------------------------------------------------------------------
void add_transfers_to_expiration_list(const std::vector<uint64_t>& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id);
void remove_transfer_from_expiration_list(uint64_t transfer_index);
void load_keys(const std::string& keys_file_name, const std::string& password, uint64_t file_signature, keys_file_data& kf_data);
@ -1081,7 +1125,7 @@ private:
bool is_in_hardfork_zone(uint64_t hardfork_index) const;
uint8_t out_get_mixin_attr(const currency::tx_out_v& out_t);
const crypto::public_key& out_get_pub_key(const currency::tx_out_v& out_t, std::list<currency::htlc_info>& htlc_info_list);
bool expand_selection_with_zc_input(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes);
void push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector<currency::extra_v>& extra);
void remove_transfer_from_amount_gindex_map(uint64_t tid);
@ -1146,6 +1190,8 @@ private:
mutable uint64_t m_current_wallet_file_size;
bool m_use_deffered_global_outputs;
bool m_disable_tor_relay;
mutable current_operation_context m_current_context;
//this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions
friend class test_generator;

View file

@ -380,6 +380,17 @@ namespace tools
uint64_t m_fee;
crypto::public_key m_asset_id;
};
struct no_zc_inputs : public transfer_error
{
no_zc_inputs(const std::string& /*v*/): transfer_error(std::string(""), API_RETURN_CODE_MISSING_ZC_INPUTS)
{}
virtual const char* what() const noexcept
{
return API_RETURN_CODE_MISSING_ZC_INPUTS;
}
};
//----------------------------------------------------------------------------------------------------
struct not_enough_outs_to_mix : public transfer_error
{

View file

@ -17,6 +17,10 @@ public:
virtual void on_sync_progress(size_t wallet_id, const uint64_t& /*percents*/) {}
virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti) {}
virtual void on_tor_status_change(size_t wallet_id, const std::string& state) {}
virtual void on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets) {}
virtual bool on_mw_select_wallet(uint64_t wallet_id) { return true; }
};
struct i_wallet_to_i_backend_adapter: public tools::i_wallet2_callback
@ -45,6 +49,16 @@ struct i_wallet_to_i_backend_adapter: public tools::i_wallet2_callback
m_pbackend->on_tor_status_change(m_wallet_id, state);
}
virtual void on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets)
{
m_pbackend->on_mw_get_wallets(wallets);
}
virtual bool on_mw_select_wallet(uint64_t wallet_id)
{
return m_pbackend->on_mw_select_wallet(wallet_id);
}
private:
i_backend_wallet_callback* m_pbackend;
size_t m_wallet_id;

View file

@ -1179,6 +1179,310 @@ namespace wallet_public
};
};
struct asset_funds
{
crypto::public_key asset_id;
uint64_t amount;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id)
KV_SERIALIZE(amount)
END_KV_SERIALIZE_MAP()
};
struct ionic_swap_proposal_info
{
std::vector<asset_funds> to_bob; //assets that funded by side that making proposal(Alice) and addressed to receiver of proposal (Bob)
std::vector<asset_funds> to_alice; //assets expected to be funded by the side that receiving proposal (Bob) and addressed to Alice
uint64_t mixins;
uint64_t fee_paid_by_a;
uint64_t expiration_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(to_bob)
KV_SERIALIZE(to_alice)
KV_SERIALIZE(mixins)
KV_SERIALIZE(fee_paid_by_a)
KV_SERIALIZE(expiration_time)
END_KV_SERIALIZE_MAP()
};
struct ionic_swap_proposal_context
{
currency::tx_generation_context gen_context;
crypto::secret_key one_time_skey;
BEGIN_SERIALIZE_OBJECT()
VERSION()
CURRENT_VERSION(0)
FIELD(gen_context)
FIELD(one_time_skey)
END_SERIALIZE()
};
struct ionic_swap_proposal
{
currency::transaction tx_template;
std::string encrypted_context; //ionic_swap_proposal_context encrypted with derivation
BEGIN_SERIALIZE_OBJECT()
VERSION()
CURRENT_VERSION(0)
FIELD(tx_template)
FIELD(encrypted_context)
END_SERIALIZE()
};
struct create_ionic_swap_proposal_request
{
uint64_t wallet_id;
ionic_swap_proposal_info proposal_info;
std::string destination_add;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wallet_id)
KV_SERIALIZE(proposal_info)
KV_SERIALIZE(destination_add)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_IONIC_SWAP_GENERATE_PROPOSAL
{
struct request
{
ionic_swap_proposal_info proposal;
std::string destination_address;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(proposal)
KV_SERIALIZE(destination_address)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string hex_raw_proposal;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(hex_raw_proposal)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO
{
struct request
{
std::string hex_raw_proposal;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(hex_raw_proposal)
END_KV_SERIALIZE_MAP()
};
struct response
{
ionic_swap_proposal_info proposal;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(proposal)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL
{
struct request
{
std::string hex_raw_proposal;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(hex_raw_proposal)
END_KV_SERIALIZE_MAP()
};
struct response
{
crypto::hash result_tx_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(result_tx_id)
END_KV_SERIALIZE_MAP()
};
};
struct wallet_info
{
std::list<tools::wallet_public::asset_balance_entry> balances;
uint64_t mined_total;
std::string address;
std::string view_sec_key;
std::string path;
bool is_auditable;
bool is_watch_only;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balances)
KV_SERIALIZE(mined_total)
KV_SERIALIZE(address)
KV_SERIALIZE(view_sec_key)
KV_SERIALIZE(path)
KV_SERIALIZE(is_auditable);
KV_SERIALIZE(is_watch_only);
END_KV_SERIALIZE_MAP()
};
struct wallet_entry_info
{
wallet_info wi;
uint64_t wallet_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wi)
KV_SERIALIZE(wallet_id)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_MW_GET_WALLETS
{
struct request
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
struct response
{
std::vector<wallet_entry_info> wallets;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wallets)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_MW_SELECT_WALLET
{
struct request
{
uint64_t wallet_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wallet_id)
END_KV_SERIALIZE_MAP()
};
struct response
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_SIGN_MESSAGE
{
struct request
{
std::string buff; //base64 encoded data
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(buff)
END_KV_SERIALIZE_MAP()
};
struct response
{
crypto::signature sig;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(sig)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_VALIDATE_SIGNATURE
{
struct request
{
std::string buff; //base64 encoded data
crypto::signature sig;
crypto::public_key pkey;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(buff)
KV_SERIALIZE_POD_AS_HEX_STRING(sig)
KV_SERIALIZE_POD_AS_HEX_STRING(pkey)
END_KV_SERIALIZE_MAP()
};
struct response
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_ENCRYPT_DATA
{
struct request
{
std::string buff; //base64 encoded data
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(buff)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string res_buff; //base64 encoded encrypted data
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(res_buff)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_DECRYPT_DATA
{
struct request
{
std::string buff; //base64 encoded encrypted data
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(buff)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string res_buff; //base64 encoded data
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(res_buff)
END_KV_SERIALIZE_MAP()
};
};
struct assets_whitelist
{
std::vector<currency::asset_descriptor_with_id> assets;
@ -1212,6 +1516,10 @@ namespace wallet_public
}
}
inline bool operator==(const asset_funds& lhs, const asset_funds& rhs)
{
return lhs.amount == rhs.amount && lhs.asset_id == rhs.asset_id;
}
} // namespace wallet_rpc
} // namespace tools

View file

@ -56,13 +56,18 @@ namespace tools
command_line::add_arg(desc, arg_deaf_mode);
}
//------------------------------------------------------------------------------------------------------------------------------
wallet_rpc_server::wallet_rpc_server(wallet2& w)
: m_wallet(w)
wallet_rpc_server::wallet_rpc_server(std::shared_ptr<wallet2> wptr)
: m_pwallet(wptr)
, m_do_mint(false)
, m_deaf(false)
, m_last_wallet_store_height(0)
{}
//------------------------------------------------------------------------------------------------------------------------------
std::shared_ptr<wallet2> wallet_rpc_server::get_wallet()
{
return std::shared_ptr<wallet2>(m_pwallet);
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address)
{
static const uint64_t wallet_rpc_idle_work_period_ms = 2000;
@ -79,7 +84,7 @@ namespace tools
bool received_money = false, ok = false;
std::atomic<bool> stop(false);
LOG_PRINT_L2("wallet RPC idle: refreshing...");
m_wallet.refresh(blocks_fetched, received_money, ok, stop);
get_wallet()->refresh(blocks_fetched, received_money, ok, stop);
if (stop)
{
LOG_PRINT_L1("wallet RPC idle: refresh failed");
@ -88,24 +93,24 @@ namespace tools
bool has_related_alias_in_unconfirmed = false;
LOG_PRINT_L2("wallet RPC idle: scanning tx pool...");
m_wallet.scan_tx_pool(has_related_alias_in_unconfirmed);
get_wallet()->scan_tx_pool(has_related_alias_in_unconfirmed);
if (m_do_mint)
{
LOG_PRINT_L2("wallet RPC idle: trying to do PoS iteration...");
m_wallet.try_mint_pos(miner_address);
get_wallet()->try_mint_pos(miner_address);
}
//auto-store wallet in server mode, let's do it every 24-hour
if (m_wallet.get_top_block_height() < m_last_wallet_store_height)
if (get_wallet()->get_top_block_height() < m_last_wallet_store_height)
{
LOG_ERROR("Unexpected m_last_wallet_store_height = " << m_last_wallet_store_height << " or " << m_wallet.get_top_block_height());
LOG_ERROR("Unexpected m_last_wallet_store_height = " << m_last_wallet_store_height << " or " << get_wallet()->get_top_block_height());
}
else if (m_wallet.get_top_block_height() - m_last_wallet_store_height > CURRENCY_BLOCKS_PER_DAY)
else if (get_wallet()->get_top_block_height() - m_last_wallet_store_height > CURRENCY_BLOCKS_PER_DAY)
{
//store wallet
m_wallet.store();
m_last_wallet_store_height = m_wallet.get_top_block_height();
get_wallet()->store();
m_last_wallet_store_height = get_wallet()->get_top_block_height();
}
}
catch (error::no_connection_to_daemon&)
@ -141,14 +146,14 @@ namespace tools
if (command_line::has_arg(vm, arg_miner_text_info))
{
m_wallet.set_miner_text_info(command_line::get_arg(vm, arg_miner_text_info));
get_wallet()->set_miner_text_info(command_line::get_arg(vm, arg_miner_text_info));
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::init(const boost::program_options::variables_map& vm)
{
m_last_wallet_store_height = m_wallet.get_top_block_height();
m_last_wallet_store_height = get_wallet()->get_top_block_height();
m_net_server.set_threads_prefix("RPC");
bool r = handle_command_line(vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server");
@ -187,7 +192,7 @@ namespace tools
try
{
uint64_t stub_mined = 0; // unused
bool r = m_wallet.balance(res.balances, stub_mined);
bool r = get_wallet()->balance(res.balances, stub_mined);
CHECK_AND_ASSERT_THROW_MES(r, "m_wallet.balance failed");
for (auto it = res.balances.begin(); it != res.balances.end(); ++it)
{
@ -212,7 +217,7 @@ namespace tools
{
try
{
res.address = m_wallet.get_account().get_public_address_str();
res.address = get_wallet()->get_account().get_public_address_str();
}
catch (std::exception& e)
{
@ -226,17 +231,17 @@ namespace tools
{
try
{
res.address = m_wallet.get_account().get_public_address_str();
res.is_whatch_only = m_wallet.is_watch_only();
res.path = epee::string_encoding::convert_to_ansii(m_wallet.get_wallet_path());
res.transfers_count = m_wallet.get_recent_transfers_total_count();
res.transfer_entries_count = m_wallet.get_transfer_entries_count();
res.address = get_wallet()->get_account().get_public_address_str();
res.is_whatch_only = get_wallet()->is_watch_only();
res.path = epee::string_encoding::convert_to_ansii(get_wallet()->get_wallet_path());
res.transfers_count = get_wallet()->get_recent_transfers_total_count();
res.transfer_entries_count = get_wallet()->get_transfer_entries_count();
std::map<uint64_t, uint64_t> distribution;
m_wallet.get_utxo_distribution(distribution);
get_wallet()->get_utxo_distribution(distribution);
for (const auto& ent : distribution)
res.utxo_distribution.push_back(currency::print_money_brief(ent.first) + ":" + std::to_string(ent.second));
res.current_height = m_wallet.get_top_block_height();
res.current_height = get_wallet()->get_top_block_height();
return true;
}
catch (std::exception& e)
@ -250,7 +255,7 @@ namespace tools
{
try
{
res.seed_phrase = m_wallet.get_account().get_seed_phrase(req.seed_password);
res.seed_phrase = get_wallet()->get_account().get_seed_phrase(req.seed_password);
return true;
}
catch (std::exception& e)
@ -271,21 +276,21 @@ namespace tools
{
if (req.update_provision_info)
{
res.pi.balance = m_wallet.balance(res.pi.unlocked_balance);
res.pi.transfer_entries_count = m_wallet.get_transfer_entries_count();
res.pi.transfers_count = m_wallet.get_recent_transfers_total_count();
res.pi.curent_height = m_wallet.get_top_block_height();
res.pi.balance = get_wallet()->balance(res.pi.unlocked_balance);
res.pi.transfer_entries_count = get_wallet()->get_transfer_entries_count();
res.pi.transfers_count = get_wallet()->get_recent_transfers_total_count();
res.pi.curent_height = get_wallet()->get_top_block_height();
}
if (req.offset == 0 && !req.exclude_unconfirmed)
m_wallet.get_unconfirmed_transfers(res.transfers, req.exclude_mining_txs);
get_wallet()->get_unconfirmed_transfers(res.transfers, req.exclude_mining_txs);
bool start_from_end = true;
if (req.order == ORDER_FROM_BEGIN_TO_END)
{
start_from_end = false;
}
m_wallet.get_recent_transfers_history(res.transfers, req.offset, req.count, res.total_transfers, res.last_item_index, req.exclude_mining_txs, start_from_end);
get_wallet()->get_recent_transfers_history(res.transfers, req.offset, req.count, res.total_transfers, res.last_item_index, req.exclude_mining_txs, start_from_end);
return true;
}
@ -299,10 +304,10 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
if (req.fee < m_wallet.get_core_runtime_config().tx_pool_min_fee)
if (req.fee < get_wallet()->get_core_runtime_config().tx_pool_min_fee)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = std::string("Given fee is too low: ") + epee::string_tools::num_to_string_fast(req.fee) + ", minimum is: " + epee::string_tools::num_to_string_fast(m_wallet.get_core_runtime_config().tx_pool_min_fee);
er.message = std::string("Given fee is too low: ") + epee::string_tools::num_to_string_fast(req.fee) + ", minimum is: " + epee::string_tools::num_to_string_fast(get_wallet()->get_core_runtime_config().tx_pool_min_fee);
return false;
}
@ -314,7 +319,7 @@ namespace tools
return false;
}
construct_tx_param ctp = m_wallet.get_default_construct_tx_param_inital();
construct_tx_param ctp = get_wallet()->get_default_construct_tx_param_inital();
if (req.service_entries_permanent)
{
//put it to extra
@ -357,7 +362,7 @@ namespace tools
wrap = true;
//encrypt body with a special way
}
else if(!m_wallet.get_transfer_address(it->address, de.addr.back(), embedded_payment_id))
else if(!get_wallet()->get_transfer_address(it->address, de.addr.back(), embedded_payment_id))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
@ -396,7 +401,7 @@ namespace tools
if (req.push_payer && !wrap)
{
currency::create_and_add_tx_payer_to_container_from_address(extra, m_wallet.get_account().get_keys().account_address, m_wallet.get_top_block_height(), m_wallet.get_core_runtime_config());
currency::create_and_add_tx_payer_to_container_from_address(extra, get_wallet()->get_account().get_keys().account_address, get_wallet()->get_top_block_height(), get_wallet()->get_core_runtime_config());
}
if (!req.hide_receiver)
@ -404,7 +409,7 @@ namespace tools
for (auto& d : dsts)
{
for (auto& a : d.addr)
currency::create_and_add_tx_receiver_to_container_from_address(extra, a, m_wallet.get_top_block_height(), m_wallet.get_core_runtime_config());
currency::create_and_add_tx_receiver_to_container_from_address(extra, a, get_wallet()->get_top_block_height(), get_wallet()->get_core_runtime_config());
}
}
@ -412,8 +417,8 @@ namespace tools
std::string unsigned_tx_blob_str;
ctp.fee = req.fee;
ctp.fake_outputs_count = req.mixin;
m_wallet.transfer(ctp, result, true, &unsigned_tx_blob_str);
if (m_wallet.is_watch_only())
get_wallet()->transfer(ctp, result, true, &unsigned_tx_blob_str);
if (get_wallet()->is_watch_only())
{
res.tx_unsigned_hex = epee::string_tools::buff_to_hex_nodelimer(unsigned_tx_blob_str); // watch-only wallets could not sign and relay transactions
// leave res.tx_hash empty, because tx hash will change after signing
@ -449,9 +454,9 @@ namespace tools
bool wallet_rpc_server::on_store(const wallet_public::COMMAND_RPC_STORE::request& req, wallet_public::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.store();
get_wallet()->store();
boost::system::error_code ec = AUTO_VAL_INIT(ec);
res.wallet_file_size = m_wallet.get_wallet_file_size();
res.wallet_file_size = get_wallet()->get_wallet_file_size();
WALLET_RPC_CATCH_TRY_ENTRY();
return true;
}
@ -468,7 +473,7 @@ namespace tools
res.payments.clear();
std::list<wallet2::payment_details> payment_list;
m_wallet.get_payments(payment_id, payment_list);
get_wallet()->get_payments(payment_id, payment_list);
for (auto payment : payment_list)
{
if (payment.m_unlock_time && !req.allow_locked_transactions)
@ -505,7 +510,7 @@ namespace tools
}
std::list<wallet2::payment_details> payment_list;
m_wallet.get_payments(payment_id, payment_list, req.min_block_height);
get_wallet()->get_payments(payment_id, payment_list, req.min_block_height);
for (auto & payment : payment_list)
{
@ -553,7 +558,7 @@ namespace tools
crypto::generate_random_bytes(payment_id.size(), &payment_id.front());
}
res.integrated_address = currency::get_account_address_and_payment_id_as_str(m_wallet.get_account().get_public_address(), payment_id);
res.integrated_address = currency::get_account_address_and_payment_id_as_str(get_wallet()->get_account().get_public_address(), payment_id);
res.payment_id = epee::string_tools::buff_to_hex_nodelimer(payment_id);
return !res.integrated_address.empty();
@ -587,7 +592,7 @@ namespace tools
currency::account_public_address addr;
currency::payment_id_t integrated_payment_id;
if (!m_wallet.get_transfer_address(req.address, addr, integrated_payment_id))
if (!get_wallet()->get_transfer_address(req.address, addr, integrated_payment_id))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("Invalid address: ") + req.address;
@ -606,10 +611,10 @@ namespace tools
payment_id = integrated_payment_id;
}
if (req.fee < m_wallet.get_core_runtime_config().tx_pool_min_fee)
if (req.fee < get_wallet()->get_core_runtime_config().tx_pool_min_fee)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = std::string("Given fee is too low: ") + epee::string_tools::num_to_string_fast(req.fee) + ", minimum is: " + epee::string_tools::num_to_string_fast(m_wallet.get_core_runtime_config().tx_pool_min_fee);
er.message = std::string("Given fee is too low: ") + epee::string_tools::num_to_string_fast(req.fee) + ", minimum is: " + epee::string_tools::num_to_string_fast(get_wallet()->get_core_runtime_config().tx_pool_min_fee);
return false;
}
@ -620,14 +625,14 @@ namespace tools
uint64_t amount_total = 0, amount_swept = 0;
std::string unsigned_tx_blob_str;
m_wallet.sweep_below(req.mixin, addr, req.amount, payment_id, req.fee, outs_total, amount_total, outs_swept, amount_swept, &tx, &unsigned_tx_blob_str);
get_wallet()->sweep_below(req.mixin, addr, req.amount, payment_id, req.fee, outs_total, amount_total, outs_swept, amount_swept, &tx, &unsigned_tx_blob_str);
res.amount_swept = amount_swept;
res.amount_total = amount_total;
res.outs_swept = outs_swept;
res.outs_total = outs_total;
if (m_wallet.is_watch_only())
if (get_wallet()->is_watch_only())
{
res.tx_unsigned_hex = epee::string_tools::buff_to_hex_nodelimer(unsigned_tx_blob_str); // watch-only wallets can't sign and relay transactions
// leave res.tx_hash empty, because tx has will change after signing
@ -673,7 +678,7 @@ namespace tools
return false;
}
std::string tx_signed_blob;
m_wallet.sign_transfer(tx_unsigned_blob, tx_signed_blob, tx);
get_wallet()->sign_transfer(tx_unsigned_blob, tx_signed_blob, tx);
res.tx_signed_hex = epee::string_tools::buff_to_hex_nodelimer(tx_signed_blob);
res.tx_hash = epee::string_tools::pod_to_hex(currency::get_transaction_hash(tx));
@ -693,7 +698,7 @@ namespace tools
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction tx = AUTO_VAL_INIT(tx);
m_wallet.submit_transfer(tx_signed_blob, tx);
get_wallet()->submit_transfer(tx_signed_blob, tx);
res.tx_hash = epee::string_tools::pod_to_hex(currency::get_transaction_hash(tx));
WALLET_RPC_CATCH_TRY_ENTRY();
@ -705,7 +710,7 @@ namespace tools
bool tx_id_specified = req.tx_id != currency::null_hash;
// process confirmed txs
m_wallet.enumerate_transfers_history([&](const wallet_public::wallet_transfer_info& wti) -> bool {
get_wallet()->enumerate_transfers_history([&](const wallet_public::wallet_transfer_info& wti) -> bool {
if (tx_id_specified)
{
@ -741,7 +746,7 @@ namespace tools
// process unconfirmed txs
if (req.pool)
{
m_wallet.enumerate_unconfirmed_transfers([&](const wallet_public::wallet_transfer_info& wti) -> bool {
get_wallet()->enumerate_unconfirmed_transfers([&](const wallet_public::wallet_transfer_info& wti) -> bool {
if ((wti.is_income && req.in) || (!wti.is_income && req.out))
res.pool.push_back(wti);
return true; // continue
@ -752,7 +757,7 @@ namespace tools
}
bool wallet_rpc_server::on_get_mining_history(const wallet_public::COMMAND_RPC_GET_MINING_HISTORY::request& req, wallet_public::COMMAND_RPC_GET_MINING_HISTORY::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
m_wallet.get_mining_history(res, req.v);
get_wallet()->get_mining_history(res, req.v);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@ -775,7 +780,7 @@ namespace tools
}
currency::transaction tx = AUTO_VAL_INIT(tx);
m_wallet.request_alias_registration(ai, tx, m_wallet.get_default_fee(), 0, req.authority_key);
get_wallet()->request_alias_registration(ai, tx, get_wallet()->get_default_fee(), 0, req.authority_key);
res.tx_id = get_transaction_hash(tx);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
@ -786,7 +791,7 @@ namespace tools
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction tx = AUTO_VAL_INIT(tx);
currency::transaction template_tx = AUTO_VAL_INIT(template_tx);
m_wallet.send_escrow_proposal(req, tx, template_tx);
get_wallet()->send_escrow_proposal(req, tx, template_tx);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
@ -794,7 +799,7 @@ namespace tools
bool wallet_rpc_server::on_contracts_accept_proposal(const wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL::request& req, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.accept_proposal(req.contract_id, req.acceptance_fee);
get_wallet()->accept_proposal(req.contract_id, req.acceptance_fee);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
@ -803,7 +808,7 @@ namespace tools
{
WALLET_RPC_BEGIN_TRY_ENTRY();
tools::wallet2::escrow_contracts_container ecc;
m_wallet.get_contracts(ecc);
get_wallet()->get_contracts(ecc);
res.contracts.resize(ecc.size());
size_t i = 0;
for (auto& c : ecc)
@ -819,7 +824,7 @@ namespace tools
bool wallet_rpc_server::on_contracts_release(const wallet_public::COMMAND_CONTRACTS_RELEASE::request& req, wallet_public::COMMAND_CONTRACTS_RELEASE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.finish_contract(req.contract_id, req.release_type);
get_wallet()->finish_contract(req.contract_id, req.release_type);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
@ -827,7 +832,7 @@ namespace tools
bool wallet_rpc_server::on_contracts_request_cancel(const wallet_public::COMMAND_CONTRACTS_REQUEST_CANCEL::request& req, wallet_public::COMMAND_CONTRACTS_REQUEST_CANCEL::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.request_cancel_contract(req.contract_id, req.fee, req.expiration_period);
get_wallet()->request_cancel_contract(req.contract_id, req.fee, req.expiration_period);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
@ -835,7 +840,7 @@ namespace tools
bool wallet_rpc_server::on_contracts_accept_cancel(const wallet_public::COMMAND_CONTRACTS_ACCEPT_CANCEL::request& req, wallet_public::COMMAND_CONTRACTS_ACCEPT_CANCEL::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.accept_cancel_contract(req.contract_id);
get_wallet()->accept_cancel_contract(req.contract_id);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
@ -843,9 +848,9 @@ namespace tools
bool wallet_rpc_server::on_marketplace_get_my_offers(const wallet_public::COMMAND_MARKETPLACE_GET_MY_OFFERS::request& req, wallet_public::COMMAND_MARKETPLACE_GET_MY_OFFERS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.get_actual_offers(res.offers);
get_wallet()->get_actual_offers(res.offers);
size_t offers_count_before_filtering = res.offers.size();
bc_services::filter_offers_list(res.offers, req.filter, m_wallet.get_core_runtime_config().get_core_time());
bc_services::filter_offers_list(res.offers, req.filter, get_wallet()->get_core_runtime_config().get_core_time());
LOG_PRINT("get_my_offers(): " << res.offers.size() << " offers returned (" << offers_count_before_filtering << " was before filter)", LOG_LEVEL_1);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
@ -855,7 +860,7 @@ namespace tools
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction res_tx = AUTO_VAL_INIT(res_tx);
m_wallet.push_offer(req.od, res_tx);
get_wallet()->push_offer(req.od, res_tx);
res.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx));
res.tx_blob_size = currency::get_object_blobsize(res_tx);
@ -868,7 +873,7 @@ namespace tools
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction res_tx = AUTO_VAL_INIT(res_tx);
m_wallet.update_offer_by_id(req.tx_id, req.no, req.od, res_tx);
get_wallet()->update_offer_by_id(req.tx_id, req.no, req.od, res_tx);
res.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx));
res.tx_blob_size = currency::get_object_blobsize(res_tx);
@ -880,7 +885,7 @@ namespace tools
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction res_tx = AUTO_VAL_INIT(res_tx);
m_wallet.cancel_offer_by_id(req.tx_id, req.no, req.fee, res_tx);
get_wallet()->cancel_offer_by_id(req.tx_id, req.no, req.fee, res_tx);
res.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx));
res.tx_blob_size = currency::get_object_blobsize(res_tx);
@ -892,7 +897,7 @@ namespace tools
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction tx = AUTO_VAL_INIT(tx);
m_wallet.create_htlc_proposal(req.amount, req.counterparty_address, req.lock_blocks_count, tx, req.htlc_hash, res.derived_origin_secret);
get_wallet()->create_htlc_proposal(req.amount, req.counterparty_address, req.lock_blocks_count, tx, req.htlc_hash, res.derived_origin_secret);
res.result_tx_blob = currency::tx_to_blob(tx);
res.result_tx_id = get_transaction_hash(tx);
WALLET_RPC_CATCH_TRY_ENTRY();
@ -902,7 +907,7 @@ namespace tools
bool wallet_rpc_server::on_get_list_of_active_htlc(const wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC::request& req, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.get_list_of_active_htlc(res.htlcs, req.income_redeem_only);
get_wallet()->get_list_of_active_htlc(res.htlcs, req.income_redeem_only);
WALLET_RPC_CATCH_TRY_ENTRY();
return true;
}
@ -911,7 +916,7 @@ namespace tools
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction tx = AUTO_VAL_INIT(tx);
m_wallet.redeem_htlc(req.tx_id, req.origin_secret, tx);
get_wallet()->redeem_htlc(req.tx_id, req.origin_secret, tx);
res.result_tx_blob = currency::tx_to_blob(tx);
res.result_tx_id = get_transaction_hash(tx);
WALLET_RPC_CATCH_TRY_ENTRY();
@ -921,11 +926,150 @@ namespace tools
bool wallet_rpc_server::on_check_htlc_redeemed(const wallet_public::COMMAND_CHECK_HTLC_REDEEMED::request& req, wallet_public::COMMAND_CHECK_HTLC_REDEEMED::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
m_wallet.check_htlc_redeemed(req.htlc_tx_id, res.origin_secrete, res.redeem_tx_id);
get_wallet()->check_htlc_redeemed(req.htlc_tx_id, res.origin_secrete, res.redeem_tx_id);
WALLET_RPC_CATCH_TRY_ENTRY();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_ionic_swap_generate_proposal(const wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL::request& req, wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
currency::account_public_address destination_addr = AUTO_VAL_INIT(destination_addr);
currency::payment_id_t integrated_payment_id;
if (!get_wallet()->get_transfer_address(req.destination_address, destination_addr, integrated_payment_id))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS";
return false;
}
if (integrated_payment_id.size())
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS - integrated address is noit supported yet";
return false;
}
wallet_public::ionic_swap_proposal proposal = AUTO_VAL_INIT(proposal);
bool r = get_wallet()->create_ionic_swap_proposal(req.proposal, destination_addr, proposal);
if (!r)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT - Error creating proposal";
return false;
}
res.hex_raw_proposal = epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(proposal));
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_ionic_swap_get_proposal_info(const wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO::request& req, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string raw_tx_template;
bool r = epee::string_tools::parse_hexstr_to_binbuff(req.hex_raw_proposal, raw_tx_template);
if (!r)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT - failed to parse template from hex";
return false;
}
if (!get_wallet()->get_ionic_swap_proposal_info(raw_tx_template, res.proposal))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT - get_ionic_swap_proposal_info";
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_ionic_swap_accept_proposal(const wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL::request& req, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string raw_tx_template;
bool r = epee::string_tools::parse_hexstr_to_binbuff(req.hex_raw_proposal, raw_tx_template);
if (!r)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT - failed to parse template from hex";
return false;
}
currency::transaction result_tx = AUTO_VAL_INIT(result_tx);
if (!get_wallet()->accept_ionic_swap_proposal(raw_tx_template, result_tx))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT - failed to accept_ionic_swap_proposal()";
return false;
}
res.result_tx_id = currency::get_transaction_hash(result_tx);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_mw_get_wallets(const wallet_public::COMMAND_MW_GET_WALLETS::request& req, wallet_public::COMMAND_MW_GET_WALLETS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
i_wallet2_callback* pcallback = get_wallet()->get_callback();
if (!pcallback)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
return false;
}
pcallback->on_mw_get_wallets(res.wallets);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_mw_select_wallet(const wallet_public::COMMAND_MW_SELECT_WALLET::request& req, wallet_public::COMMAND_MW_SELECT_WALLET::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
i_wallet2_callback* pcallback = get_wallet()->get_callback();
if (!pcallback)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
return false;
}
pcallback->on_mw_select_wallet(req.wallet_id);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_sign_message(const wallet_public::COMMAND_SIGN_MESSAGE::request& req, wallet_public::COMMAND_SIGN_MESSAGE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string buff = epee::string_encoding::base64_decode(req.buff);
get_wallet()->sign_buffer(buff, res.sig);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_validate_signature(const wallet_public::COMMAND_VALIDATE_SIGNATURE::request& req, wallet_public::COMMAND_VALIDATE_SIGNATURE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string buff = epee::string_encoding::base64_decode(req.buff);
bool r = get_wallet()->validate_sign(buff, req.sig, req.pkey);
if (!r)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT";
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_encrypt_data(const wallet_public::COMMAND_ENCRYPT_DATA::request& req, wallet_public::COMMAND_ENCRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string buff = epee::string_encoding::base64_decode(req.buff);
bool r = get_wallet()->encrypt_buffer(buff, res.res_buff);
res.res_buff = epee::string_encoding::base64_encode(res.res_buff);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string buff = epee::string_encoding::base64_decode(req.buff);
bool r = get_wallet()->encrypt_buffer(buff, res.res_buff);
res.res_buff = epee::string_encoding::base64_encode(res.res_buff);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::reset_active_wallet(std::shared_ptr<wallet2> w)
{
m_pwallet = w;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
} // namespace tools

View file

@ -22,7 +22,7 @@ namespace tools
public:
typedef epee::net_utils::connection_context_base connection_context;
wallet_rpc_server(wallet2& cr);
wallet_rpc_server(std::shared_ptr<wallet2> wptr);
const static command_line::arg_descriptor<std::string> arg_rpc_bind_port;
const static command_line::arg_descriptor<std::string> arg_rpc_bind_ip;
@ -73,6 +73,20 @@ namespace tools
MAP_JON_RPC_WE("atomics_redeem_htlc", on_redeem_htlc, wallet_public::COMMAND_REDEEM_HTLC)
MAP_JON_RPC_WE("atomics_check_htlc_redeemed", on_check_htlc_redeemed, wallet_public::COMMAND_CHECK_HTLC_REDEEMED)
//IONIC_SWAPS API
MAP_JON_RPC_WE("ionic_swap_generate_proposal", on_ionic_swap_generate_proposal, wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL)
MAP_JON_RPC_WE("ionic_swap_get_proposal_info", on_ionic_swap_get_proposal_info, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO)
MAP_JON_RPC_WE("ionic_swap_accept_proposal", on_ionic_swap_accept_proposal, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL)
//MULTIWALLET APIs
MAP_JON_RPC_WE("mw_get_wallets", on_mw_get_wallets, wallet_public::COMMAND_MW_GET_WALLETS)
MAP_JON_RPC_WE("mw_select_wallet", on_mw_select_wallet, wallet_public::COMMAND_MW_SELECT_WALLET)
//basic crypto operations
MAP_JON_RPC_WE("sign_message", on_sign_message, wallet_public::COMMAND_SIGN_MESSAGE)
MAP_JON_RPC_WE("validate_signature", on_validate_signature, wallet_public::COMMAND_VALIDATE_SIGNATURE)
MAP_JON_RPC_WE("encrypt_data", on_encrypt_data, wallet_public::COMMAND_ENCRYPT_DATA)
MAP_JON_RPC_WE("decrypt_data", on_decrypt_data, wallet_public::COMMAND_DECRYPT_DATA)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -114,11 +128,28 @@ namespace tools
bool on_redeem_htlc(const wallet_public::COMMAND_REDEEM_HTLC::request& req, wallet_public::COMMAND_REDEEM_HTLC::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_check_htlc_redeemed(const wallet_public::COMMAND_CHECK_HTLC_REDEEMED::request& req, wallet_public::COMMAND_CHECK_HTLC_REDEEMED::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_ionic_swap_generate_proposal(const wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL::request& req, wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_ionic_swap_get_proposal_info(const wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO::request& req, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_ionic_swap_accept_proposal(const wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL::request& req, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_mw_get_wallets(const wallet_public::COMMAND_MW_GET_WALLETS::request& req, wallet_public::COMMAND_MW_GET_WALLETS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_mw_select_wallet(const wallet_public::COMMAND_MW_SELECT_WALLET::request& req, wallet_public::COMMAND_MW_SELECT_WALLET::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_sign_message(const wallet_public::COMMAND_SIGN_MESSAGE::request& req, wallet_public::COMMAND_SIGN_MESSAGE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_validate_signature(const wallet_public::COMMAND_VALIDATE_SIGNATURE::request& req, wallet_public::COMMAND_VALIDATE_SIGNATURE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_encrypt_data(const wallet_public::COMMAND_ENCRYPT_DATA::request& req, wallet_public::COMMAND_ENCRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx);
std::shared_ptr<wallet2> get_wallet();
bool reset_active_wallet(std::shared_ptr<wallet2> w);
bool handle_command_line(const boost::program_options::variables_map& vm);
private:
wallet2& m_wallet;
std::weak_ptr<wallet2> m_pwallet;
std::string m_port;
std::string m_bind_ip;
bool m_do_mint;

View file

@ -802,7 +802,7 @@ void wallets_manager::init_wallet_entry(wallet_vs_options& wo, uint64_t id)
wo.m_pproxy_diagnostig_info = m_rpc_proxy->get_proxy_diagnostic_info();
wo.pview = m_pview;
wo.has_related_alias_in_unconfirmed = false;
wo.rpc_wrapper.reset(new tools::wallet_rpc_server(*wo.w.unlocked_get().get()));
wo.rpc_wrapper.reset(new tools::wallet_rpc_server(wo.w.unlocked_get()));
if (m_remote_node_mode)
wo.core_conf = currency::get_default_core_runtime_config();
else
@ -876,6 +876,80 @@ std::string wallets_manager::get_fav_offers(const std::list<bc_services::offer_i
#endif
}
std::string wallets_manager::create_ionic_swap_proposal(uint64_t wallet_id, const tools::wallet_public::create_ionic_swap_proposal_request& proposal_req, std::string& result_proposal_hex)
{
GET_WALLET_OPT_BY_ID(wallet_id, wo);
try {
currency::account_public_address dest_account = AUTO_VAL_INIT(dest_account);
if (!currency::get_account_address_from_str(dest_account, proposal_req.destination_add))
{
return API_RETURN_CODE_BAD_ARG;
}
tools::wallet_public::ionic_swap_proposal proposal = AUTO_VAL_INIT(proposal);
bool r = wo.w->get()->create_ionic_swap_proposal(proposal_req.proposal_info, dest_account, proposal);
if (!r)
{
return API_RETURN_CODE_FAIL;
}
else
{
result_proposal_hex = epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(proposal));
return API_RETURN_CODE_OK;
}
}
catch (...)
{
return API_RETURN_CODE_FAIL;
}
return API_RETURN_CODE_OK;
}
std::string wallets_manager::get_ionic_swap_proposal_info(uint64_t wallet_id, std::string&raw_tx_template_hex, tools::wallet_public::ionic_swap_proposal_info& proposal)
{
GET_WALLET_OPT_BY_ID(wallet_id, wo);
try {
std::string raw_tx_template;
bool r = epee::string_tools::parse_hexstr_to_binbuff(raw_tx_template_hex, raw_tx_template);
if (!r)
{
return API_RETURN_CODE_BAD_ARG;
}
if (!wo.w->get()->get_ionic_swap_proposal_info(raw_tx_template, proposal))
{
return API_RETURN_CODE_FAIL;
}
}
catch (...)
{
return API_RETURN_CODE_FAIL;
}
return API_RETURN_CODE_OK;
}
std::string wallets_manager::accept_ionic_swap_proposal(uint64_t wallet_id, std::string&raw_tx_template_hex, std::string& result_raw_tx_hex)
{
GET_WALLET_OPT_BY_ID(wallet_id, wo);
try {
std::string raw_tx_template;
bool r = epee::string_tools::parse_hexstr_to_binbuff(raw_tx_template_hex, raw_tx_template);
if (!r)
{
return API_RETURN_CODE_BAD_ARG;
}
currency::transaction result_tx = AUTO_VAL_INIT(result_tx);
if (!wo.w->get()->accept_ionic_swap_proposal(raw_tx_template, result_tx))
{
return API_RETURN_CODE_FAIL;
}
result_raw_tx_hex = epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(result_tx));
}
catch (...)
{
return API_RETURN_CODE_FAIL;
}
return API_RETURN_CODE_OK;
}
std::string wallets_manager::get_my_offers(const bc_services::core_offers_filter& filter, std::list<bc_services::offer_details_ex>& offers)
{
if (m_remote_node_mode)
@ -1297,6 +1371,8 @@ std::string wallets_manager::get_alias_info_by_name(const std::string& name, cur
if (!r)
return API_RETURN_CODE_FAIL;
if (res.status == API_RETURN_CODE_NOT_FOUND)
return API_RETURN_CODE_NOT_FOUND;
res_details.alias = name;
res_details.details = res.alias_details;
@ -1923,7 +1999,13 @@ void wallets_manager::on_transfer_canceled(size_t wallet_id, const tools::wallet
tei.ti = wti;
SHARED_CRITICAL_REGION_LOCAL(m_wallets_lock);
auto& w = m_wallets[wallet_id].w;
auto it = m_wallets.find(wallet_id);
if (it == m_wallets.end())
{
LOG_ERROR(get_wallet_log_prefix(wallet_id) + "on_transfer_canceled() wallet with id = " << wallet_id << " not found");
return;
}
auto& w = it->second.w;
if (w->get() != nullptr)
{
w->get()->balance(tei.balances, tei.total_mined);
@ -1931,7 +2013,7 @@ void wallets_manager::on_transfer_canceled(size_t wallet_id, const tools::wallet
}
else
{
LOG_ERROR(get_wallet_log_prefix(wallet_id) + "on_transfer() wallet with id = " << wallet_id << " not found");
LOG_ERROR(get_wallet_log_prefix(wallet_id) + "on_transfer_canceled() wallet with id = " << wallet_id << " has nullptr");
}
m_pview->money_transfer_cancel(tei);
}
@ -1942,6 +2024,31 @@ void wallets_manager::on_tor_status_change(size_t wallet_id, const std::string&
m_pview->update_tor_status(tsu);
}
void wallets_manager::on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets)
{
std::list<view::open_wallet_response> opened_wallets;
this->get_opened_wallets(opened_wallets);
wallets.resize(opened_wallets.size());
size_t i = 0;
for (const auto& item : opened_wallets)
{
wallets[i].wi = item.wi;
wallets[i].wallet_id = item.wallet_id;
i++;
}
}
bool wallets_manager::on_mw_select_wallet(uint64_t wallet_id)
{
SHARED_CRITICAL_REGION_LOCAL(m_wallets_lock);
auto it = m_wallets.find(wallet_id);
if (it == m_wallets.end())
return false;
auto& wo = it->second;
//m_wallet_rpc_server.reset_active_wallet(wo.w);
return false;
}
void wallets_manager::wallet_vs_options::worker_func()
{
LOG_PRINT_GREEN("[WALLET_HANDLER] Wallet handler thread started, addr: " << w->get()->get_account().get_public_address_str(), LOG_LEVEL_0);

View file

@ -136,6 +136,9 @@ public:
std::string backup_wallet(uint64_t wallet_id, const std::wstring& path);
std::string reset_wallet_password(uint64_t wallet_id, const std::string& pass);
std::string is_wallet_password_valid(uint64_t wallet_id, const std::string& pass);
std::string create_ionic_swap_proposal(uint64_t wallet_id, const tools::wallet_public::create_ionic_swap_proposal_request& proposal, std::string& result_proposal_hex);
std::string get_ionic_swap_proposal_info(uint64_t wallet_id, std::string&raw_tx_template_hex, tools::wallet_public::ionic_swap_proposal_info& proposal);
std::string accept_ionic_swap_proposal(uint64_t wallet_id, std::string&raw_tx_template_hex, std::string& result_raw_tx);
std::string get_my_offers(const bc_services::core_offers_filter& filter, std::list<bc_services::offer_details_ex>& offers);
std::string get_fav_offers(const std::list<bc_services::offer_id>& hashes, const bc_services::core_offers_filter& filter, std::list<bc_services::offer_details_ex>& offers);
std::string get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res);
@ -190,6 +193,10 @@ private:
virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti);
virtual void on_tor_status_change(size_t wallet_id, const std::string& state);
virtual void on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets) override;
virtual bool on_mw_select_wallet(uint64_t wallet_id) override;
//--------
std::thread m_main_worker_thread;

View file

@ -2229,7 +2229,10 @@ bool shuffle_source_entries(std::vector<tx_source_entry>& sources)
//------------------------------------------------------------------------------
test_chain_unit_base::test_chain_unit_base()
{
m_hardforks = get_default_core_runtime_config().hard_forks; // set default hardforks for tests (will be overriden by test if necessary)
}
void test_chain_unit_base::register_callback(const std::string& cb_name, verify_callback cb)
{
m_callbacks[cb_name] = cb;
@ -2287,8 +2290,6 @@ test_chain_unit_enchanced::test_chain_unit_enchanced()
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_offers_count);
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_hardfork_active);
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_hardfork_inactive);
m_hardforks = get_default_core_runtime_config().hard_forks; // set default hardforks for tests (will be overriden by test if necessary)
}
bool test_chain_unit_enchanced::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)

View file

@ -230,6 +230,8 @@ class test_generator;
class test_chain_unit_base
{
public:
test_chain_unit_base();
typedef boost::function<bool(currency::core& c, size_t ev_index, const std::vector<test_event_entry> &events)> verify_callback;
typedef std::map<std::string, verify_callback> callbacks_map;

View file

@ -1085,6 +1085,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(zarcanum_basic_test);
GENERATE_AND_PLAY(multiassets_basic_test);
GENERATE_AND_PLAY(ionic_swap_basic_test);
GENERATE_AND_PLAY(zarcanum_test_n_inputs_validation);
GENERATE_AND_PLAY(zarcanum_gen_time_balance);
GENERATE_AND_PLAY(zarcanum_txs_with_big_shuffled_decoy_set_shuffled);

View file

@ -42,3 +42,4 @@
#include "isolate_auditable_and_proof.h"
#include "zarcanum_test.h"
#include "multiassets_test.h"
#include "ionic_swap_tests.h"

View file

@ -81,7 +81,7 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(12)), false, "");
// wallet RPC server
tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt);
tools::wallet_rpc_server miner_wlt_rpc(miner_wlt);
epee::json_rpc::error je;
tools::wallet_rpc_server::connection_context ctx;
@ -161,7 +161,7 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons
bob_wlt->callback(std::make_shared<tools::i_wallet2_callback>()); // clear callback
// Before HF2: Bob (auditable address) -> Alice with payer info requested (should NOT put tx_payer or tx_payer_old)
tools::wallet_rpc_server bob_wlt_rpc(*bob_wlt);
tools::wallet_rpc_server bob_wlt_rpc(bob_wlt);
tools::wallet_public::COMMAND_RPC_TRANSFER::request req_c = AUTO_VAL_INIT(req_c);
req_c.destinations.push_back(tools::wallet_public::transfer_destination{ MK_TEST_COINS(1), m_accounts[ALICE_ACC_IDX].get_public_address_str() });
req_c.fee = TESTS_DEFAULT_FEE;
@ -328,7 +328,7 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, 0), false, "");
// wallet RPC server
tools::wallet_rpc_server alice_wlt_rpc(*alice_wlt);
tools::wallet_rpc_server alice_wlt_rpc(alice_wlt);
epee::json_rpc::error je;
tools::wallet_rpc_server::connection_context ctx;

View file

@ -0,0 +1,203 @@
// Copyright (c) 2014-2022 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chaingen.h"
#include "ionic_swap_tests.h"
#include "wallet_test_core_proxy.h"
#include "random_helper.h"
#include "tx_builder.h"
#define AMOUNT_TO_TRANSFER_MULTIASSETS_BASIC (TESTS_DEFAULT_FEE)
#define AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC 500000000000000000
ionic_swap_basic_test::ionic_swap_basic_test()
{
REGISTER_CALLBACK_METHOD(ionic_swap_basic_test, configure_core);
REGISTER_CALLBACK_METHOD(ionic_swap_basic_test, c1);
m_hardforks.set_hardfork_height(1, 1);
m_hardforks.set_hardfork_height(2, 1);
m_hardforks.set_hardfork_height(3, 1);
m_hardforks.set_hardfork_height(4, 2);
}
bool ionic_swap_basic_test::generate(std::vector<test_event_entry>& events) const
{
// NOTE: This test is made deterministic to be able to correctly set up checkpoint.
random_state_test_restorer::reset_random(); // random generator's state was previously stored, will be restore on dtor (see also m_random_state_test_restorer)
uint64_t ts = 1450000000;
test_core_time::adjust(ts);
ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
currency::account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
currency::account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
currency::account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
//account_base& carol_acc = m_accounts[CAROL_ACC_IDX]; carol_acc.generate(); carol_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
DO_CALLBACK(events, "c1");
return true;
}
bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
miner_wlt->get_account().set_createtime(0);
//std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
//std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
// check passing over the hardfork
CHECK_AND_ASSERT_MES(c.get_blockchain_storage().is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM), false, "ZANO_HARDFORK_04_ZARCANUM is active");
currency::account_base alice_acc;
alice_acc.generate();
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, alice_acc);
alice_wlt->get_account().set_createtime(0);
currency::account_base bob_acc;
bob_acc.generate();
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, bob_acc);
bob_wlt->get_account().set_createtime(0);
miner_wlt->refresh();
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
adb.total_max_supply = 1000000000000000000; //1M coins
adb.full_name = "Test coins";
adb.ticker = "TCT";
adb.decimal_point = 12;
std::vector<currency::tx_destination_entry> destinations(2);
destinations[0].addr.push_back(bob_wlt->get_account().get_public_address());
destinations[0].amount = AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC;
destinations[0].asset_id = currency::null_pkey;
destinations[1].addr.push_back(alice_wlt->get_account().get_public_address());
destinations[1].amount = AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC;
destinations[1].asset_id = currency::null_pkey;
LOG_PRINT_MAGENTA("destinations[0].asset_id:" << destinations[0].asset_id, LOG_LEVEL_0);
LOG_PRINT_MAGENTA("destinations[1].asset_id:" << destinations[1].asset_id, LOG_LEVEL_0);
LOG_PRINT_MAGENTA("currency::null_pkey:" << currency::null_pkey, LOG_LEVEL_0);
currency::transaction tx = AUTO_VAL_INIT(tx);
crypto::public_key asset_id = currency::null_pkey;
miner_wlt->publish_new_asset(adb, destinations, tx, asset_id);
LOG_PRINT_L0("Published new asset: " << asset_id << ", tx_id: " << currency::get_transaction_hash(tx));
currency::transaction res_tx = AUTO_VAL_INIT(res_tx);
miner_wlt->transfer(COIN, alice_wlt->get_account().get_public_address(), res_tx);
miner_wlt->transfer(COIN, bob_wlt->get_account().get_public_address(), res_tx);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
bob_wlt->refresh();
alice_wlt->refresh();
uint64_t mined = 0;
std::unordered_map<crypto::public_key, tools::wallet_public::asset_balance_entry_base> balances;
bob_wlt->balance(balances, mined);
auto it_asset = balances.find(asset_id);
auto it_native = balances.find(currency::native_coin_asset_id);
CHECK_AND_ASSERT_MES(it_asset != balances.end() && it_native != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == COIN, false, "Failed to find needed asset in result balances");
uint64_t mined_balance = it_native->second.total;
balances.clear();
alice_wlt->balance(balances, mined);
it_asset = balances.find(asset_id);
it_native = balances.find(currency::native_coin_asset_id);
CHECK_AND_ASSERT_MES(it_asset != balances.end() && it_native != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == COIN, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
const uint64_t assets_to_exchange = 10 * COIN;
const uint64_t native_tokens_to_exchange = COIN/2;
//alice_wlt want to trade with bob_wlt, to exchange 10.0 TCT to 1.0 ZANO
view::ionic_swap_proposal_info proposal_details = AUTO_VAL_INIT(proposal_details);
proposal_details.expiration_time = alice_wlt->get_core_runtime_config().get_core_time() + 10 * 60;
proposal_details.fee_paid_by_a = TESTS_DEFAULT_FEE;
proposal_details.mixins = 10;
proposal_details.to_bob.push_back(view::asset_funds{ asset_id , assets_to_exchange });
proposal_details.to_alice.push_back(view::asset_funds{ currency::native_coin_asset_id , native_tokens_to_exchange });
tools::wallet_public::ionic_swap_proposal proposal = AUTO_VAL_INIT(proposal);
alice_wlt->create_ionic_swap_proposal(proposal_details, bob_wlt->get_account().get_public_address(), proposal);
view::ionic_swap_proposal_info proposal_decoded_info = AUTO_VAL_INIT(proposal_decoded_info);
bob_wlt->get_ionic_swap_proposal_info(proposal, proposal_decoded_info);
//Validate proposal
if (proposal_decoded_info.to_bob != proposal_details.to_bob
|| proposal_decoded_info.to_alice != proposal_details.to_alice
|| proposal_decoded_info.fee_paid_by_a != proposal_details.fee_paid_by_a
|| proposal_decoded_info.mixins != proposal_details.mixins
)
{
CHECK_AND_ASSERT_MES(false, false, "proposal actual and proposals decoded mismatch");
}
currency::transaction res_tx2 = AUTO_VAL_INIT(res_tx2);
r = bob_wlt->accept_ionic_swap_proposal(proposal, res_tx2);
CHECK_AND_ASSERT_MES(r, false, "Failed to accept ionic proposal");
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
bob_wlt->refresh();
alice_wlt->refresh();
balances.clear();
alice_wlt->balance(balances, mined);
it_asset = balances.find(asset_id);
it_native = balances.find(currency::native_coin_asset_id);
CHECK_AND_ASSERT_MES(it_asset != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == native_tokens_to_exchange + COIN - TESTS_DEFAULT_FEE, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC - assets_to_exchange, false, "Failed to find needed asset in result balances");
balances.clear();
bob_wlt->balance(balances, mined);
it_asset = balances.find(asset_id);
it_native = balances.find(currency::native_coin_asset_id);
CHECK_AND_ASSERT_MES(it_asset != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == COIN - native_tokens_to_exchange, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC + assets_to_exchange, false, "Failed to find needed asset in result balances");
//TODO:
// add fee paid by bob scenario
// add transfer of tokens without native coins
// different fail combination
return true;
}

View file

@ -0,0 +1,18 @@
// Copyright (c) 2014-2022 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "chaingen.h"
#include "wallet_tests_basic.h"
#include "random_helper.h"
struct ionic_swap_basic_test : public wallet_test
{
ionic_swap_basic_test();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
private:
random_state_test_restorer m_random_state_test_restorer;
};

View file

@ -111,7 +111,7 @@ bool isolate_auditable_and_proof::c1(currency::core& c, size_t ev_index, const s
epee::json_rpc::error je;
tools::wallet_rpc_server::connection_context ctx;
tools::wallet_rpc_server miner_wlt_rpc(*auditable_test_instance);
tools::wallet_rpc_server miner_wlt_rpc(auditable_test_instance);
tools::wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request req = AUTO_VAL_INIT(req);
tools::wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response res = AUTO_VAL_INIT(res);
req.count = 100;

View file

@ -70,14 +70,14 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
std::vector<currency::tx_destination_entry> destinations(2);
destinations[0].addr.push_back(miner_wlt->get_account().get_public_address());
destinations[0].amount = AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC;
destinations[0].asset_id = currency::ffff_pkey;
destinations[0].asset_id = currency::null_pkey;
destinations[1].addr.push_back(alice_wlt->get_account().get_public_address());
destinations[1].amount = AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC;
destinations[1].asset_id = currency::ffff_pkey;
destinations[1].asset_id = currency::null_pkey;
LOG_PRINT_MAGENTA("destinations[0].asset_id:" << destinations[0].asset_id, LOG_LEVEL_0);
LOG_PRINT_MAGENTA("destinations[1].asset_id:" << destinations[1].asset_id, LOG_LEVEL_0);
LOG_PRINT_MAGENTA("currency::ffff_pkey: " << currency::ffff_pkey, LOG_LEVEL_0);
LOG_PRINT_MAGENTA("currency::null_pkey: " << currency::null_pkey, LOG_LEVEL_0);
currency::transaction tx = AUTO_VAL_INIT(tx);
crypto::public_key asset_id = currency::null_pkey;

View file

@ -66,8 +66,9 @@ void transfer_multisig(tools::wallet2& w,
ftp.tx_version = tx_version;
w.prepare_transaction(ctp, ftp, tx);
tools::mode_separate_context emode_separate = AUTO_VAL_INIT(emode_separate);
emode_separate.tx_for_mode_separate = tx;
w.prepare_transaction(ctp, ftp, emode_separate);
crypto::secret_key sk = AUTO_VAL_INIT(sk);
w.finalize_transaction(ftp, tx, sk, false);

View file

@ -28,7 +28,7 @@ bool wallet_rpc_integrated_address::generate(std::vector<test_event_entry>& even
CREATE_TEST_WALLET(miner_wlt, miner_acc, blk_0);
// wallet RPC server
tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt);
tools::wallet_rpc_server miner_wlt_rpc(miner_wlt);
epee::json_rpc::error je;
tools::wallet_rpc_server::connection_context ctx;
@ -110,7 +110,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind
std::string alice_integrated_address = get_account_address_and_payment_id_as_str(m_accounts[ALICE_ACC_IDX].get_public_address(), payment_id);
// wallet RPC server
tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt);
tools::wallet_rpc_server miner_wlt_rpc(miner_wlt);
epee::json_rpc::error je;
tools::wallet_rpc_server::connection_context ctx;
@ -226,7 +226,7 @@ bool wallet_rpc_transfer::c1(currency::core& c, size_t ev_index, const std::vect
miner_wlt->refresh();
// wallet RPC server
tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt);
tools::wallet_rpc_server miner_wlt_rpc(miner_wlt);
epee::json_rpc::error je;
tools::wallet_rpc_server::connection_context ctx;

View file

@ -1,5 +1,4 @@
// Copyright (c) 2014-2022 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

View file

@ -1,5 +1,4 @@
// Copyright (c) 2014-2022 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once