1
0
Fork 0
forked from lthn/blockchain

multiple fixes over ionic_swap proposal

This commit is contained in:
cryptozoidberg 2023-04-20 22:08:20 +02:00
parent aa8d3207a4
commit 4acb2bae03
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
7 changed files with 175 additions and 64 deletions

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)
@ -2271,7 +2271,7 @@ namespace currency
{
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)
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,
@ -2317,8 +2317,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
@ -2357,10 +2365,9 @@ namespace currency
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())
@ -2369,6 +2376,7 @@ 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.input_amounts[i_ + input_starter_index] = source_entry.amount;
}
else
{

View file

@ -142,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;
@ -156,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
@ -174,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()

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()
};
//---------------------------------------------------------------
@ -218,6 +225,7 @@ namespace currency
asset_id_blinding_masks.resize(outs_count);
amounts.resize(outs_count);
amount_blinding_masks.resize(outs_count);
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> input_amounts; // all inputs, including non ZC
// common data: inputs
crypto::point_t pseudo_out_amount_commitments_sum = crypto::c_point_0; // generate_tx_balance_proof generate_ZC_sig
@ -273,6 +282,7 @@ namespace currency
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(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)
@ -298,6 +308,7 @@ namespace currency
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(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)

View file

@ -5011,34 +5011,38 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal
construct_tx_param ctp = get_default_construct_tx_param();
ctp.fake_outputs_count = proposal_detais.mixins;
ctp.fee = 0;
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.from.size() + proposal_detais.to.size());
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.from.size(); i++)
for (; i != proposal_detais.to_bob.size(); i++)
{
ctp.dsts[i].amount = proposal_detais.from[i].amount;
ctp.dsts[i].amount_to_provide = proposal_detais.from[i].amount;
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.from[i].asset_id;
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.size(); j++, i++)
for (size_t j = 0; j != proposal_detais.to_alice.size(); j++, i++)
{
ctp.dsts[i].amount = proposal_detais.to[j].amount;
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[j].asset_id;
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);
@ -5053,7 +5057,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal
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(proposal_context_blob, finalize_result.derivation);
proposal.encrypted_context = crypto::chacha_crypt(static_cast<const std::string&>(proposal_context_blob), finalize_result.derivation);
return true;
}
//----------------------------------------------------------------------------------------------------
@ -5093,53 +5097,115 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
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> ammounts_to;
std::unordered_map<crypto::public_key, uint64_t> ammounts_from;
std::vector<bool> third_party_outs;
size_t i = 0;
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() > i, "Tx gen context has mismatch with tx(asset_ids) ");
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids[i].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[i].m_u64[0] == o.amount, "Tx gen context has mismatch with tx(amount != amount)");
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[o.asset_id] += o.amount;
third_party_outs[i] = false;
i++;
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 (!third_party_outs[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_from[asset_id] += amount;
ammounts_to_a[asset_id] += amount;
}
for (const auto& a : ammounts_to)
proposal_info.to.push_back(view::asset_funds{ a.first, a.second });
for (const auto& a : ammounts_from)
proposal_info.from.push_back(view::asset_funds{ a.first, a.second });
for (const auto&in : tx.vin)
//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++)
{
if (in.type() != typeid(currency::txin_zc_input))
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.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;
size_t mx = boost::get<currency::txin_zc_input>(in).key_offsets.size() - 1;
}
amounts_provided_by_a[in_asset_id] += amount;
if (proposal_info.mixins == 0 || proposal_info.mixins > mx)
{
proposal_info.mixins = mx;
}
}
proposal_info.fee = currency::get_tx_fee(tx);
//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))
{
@ -5174,7 +5240,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
this->balance(balances, mined);
//validate balances needed
uint64_t native_amount_required = 0;
for (const auto& item : msc.proposal_info.to)
for (const auto& item : msc.proposal_info.to_alice)
{
if (balances[item.asset_id].unlocked < item.amount)
{
@ -5188,9 +5254,9 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
// balances is ok, check if fee is added to tx
uint64_t additional_fee = 0;
if (msc.proposal_info.fee < m_core_runtime_config.tx_default_fee)
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;
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;
@ -5540,11 +5606,16 @@ assets_selection_context wallet2::get_needed_money(uint64_t fee, const std::vect
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);
}
@ -6253,7 +6324,7 @@ void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
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");
for (const auto& el : mode_separatemode_separate.proposal_info.to)
for (const auto& el : mode_separatemode_separate.proposal_info.to_alice)
{
needed_money_map[el.asset_id].needed_amount += el.amount;
}

View file

@ -1195,18 +1195,18 @@ namespace wallet_public
struct ionic_swap_proposal_info
{
std::vector<asset_funds> from;
std::vector<asset_funds> to;
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;
uint64_t fee_paid_by_a;
uint64_t expiration_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(from)
KV_SERIALIZE(to)
KV_SERIALIZE(to_bob)
KV_SERIALIZE(to_alice)
KV_SERIALIZE(mixins)
KV_SERIALIZE(fee)
KV_SERIALIZE(fee_paid_by_a)
KV_SERIALIZE(expiration_time)
END_KV_SERIALIZE_MAP()

View file

@ -29,7 +29,12 @@ ionic_swap_basic_test::ionic_swap_basic_test()
bool ionic_swap_basic_test::generate(std::vector<test_event_entry>& events) const
{
uint64_t ts = test_core_time::get_time();
// 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);
@ -126,19 +131,23 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
//alice_wlt want to trade with miner_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 = TESTS_DEFAULT_FEE;
proposal_details.fee_paid_by_a = TESTS_DEFAULT_FEE;
proposal_details.mixins = 10;
proposal_details.from.push_back(view::asset_funds{ asset_id , assets_to_exchange });
proposal_details.to.push_back(view::asset_funds{ currency::native_coin_asset_id , native_tokens_to_exchange });
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, miner_wlt->get_account().get_public_address(), proposal);
view::ionic_swap_proposal_info proposal_decoded_info;
view::ionic_swap_proposal_info proposal_decoded_info = AUTO_VAL_INIT(proposal_decoded_info);
miner_wlt->get_ionic_swap_proposal_info(proposal, proposal_decoded_info);
//Validate proposal
if (proposal_decoded_info.from != proposal_details.from || proposal_decoded_info.to != proposal_details.to)
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");
}
@ -171,6 +180,12 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
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 == mined_balance - 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

@ -4,12 +4,15 @@
#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;
};