forked from lthn/blockchain
in the middle of prepare_tx_sources_htlc
This commit is contained in:
parent
0b8e651ce2
commit
a31670f225
8 changed files with 166 additions and 37 deletions
|
|
@ -39,3 +39,4 @@
|
|||
#define API_RETURN_CODE_UNINITIALIZED "UNINITIALIZED"
|
||||
#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"
|
||||
|
|
|
|||
|
|
@ -56,4 +56,12 @@ namespace crypto {
|
|||
return h;
|
||||
}
|
||||
|
||||
hash RIPEMD160_hash_256(const void *data, size_t length)
|
||||
{
|
||||
hash160 h = RIPEMD160_hash(data, length);
|
||||
hash h256 = AUTO_VAL_INIT(h256);
|
||||
memcpy(&h256, &h, sizeof(h));
|
||||
return h256;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ namespace crypto {
|
|||
|
||||
void RIPEMD160_hash(const void *data, size_t length, hash160 &h);
|
||||
hash160 RIPEMD160_hash(const void *data, size_t length);
|
||||
hash RIPEMD160_hash_256(const void *data, size_t length);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -591,11 +591,11 @@ namespace currency
|
|||
// return true;
|
||||
// }
|
||||
//---------------------------------------------------------------
|
||||
std::string generate_origin_for_htlc(const crypto::public_key& redeem, const crypto::public_key& refund, const account_keys& acc_keys)
|
||||
std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys)
|
||||
{
|
||||
std::string blob;
|
||||
string_tools::apped_pod_to_strbuff(blob, redeem);
|
||||
string_tools::apped_pod_to_strbuff(blob, refund);
|
||||
string_tools::apped_pod_to_strbuff(blob, htlc.pkey_redeem);
|
||||
string_tools::apped_pod_to_strbuff(blob, htlc.pkey_refund);
|
||||
string_tools::apped_pod_to_strbuff(blob, acc_keys.spend_secret_key);
|
||||
crypto::hash origin_hs = crypto::cn_fast_hash(blob.data(), blob.size());
|
||||
std::string origin_blob;
|
||||
|
|
@ -635,12 +635,13 @@ namespace currency
|
|||
|
||||
tx_out out;
|
||||
out.amount = de.amount;
|
||||
if (de.htlc)
|
||||
if (de.additional_options.type() == typeid(destination_option_htlc_out))
|
||||
{
|
||||
const destination_option_htlc_out& htlc_dest = boost::get<destination_option_htlc_out>(de.additional_options);
|
||||
//out htlc
|
||||
CHECK_AND_ASSERT_MES(target_keys.size() == 1, false, "Unexpected htl keys count = " << target_keys.size() << ", expected ==1");
|
||||
txout_htlc htlc = AUTO_VAL_INIT(htlc);
|
||||
htlc.expiration = de.unlock_time;
|
||||
htlc.expiration = htlc_dest.expiration;
|
||||
htlc.flags = 0; //0 - SHA256, 1 - RIPEMD160, by default leave SHA256
|
||||
//receiver key
|
||||
htlc.pkey_redeem = *target_keys.begin();
|
||||
|
|
@ -651,10 +652,10 @@ namespace currency
|
|||
CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address");
|
||||
htlc.pkey_refund = out_eph_public_key;
|
||||
|
||||
if (de.htlc_hash == null_hash)
|
||||
if (htlc_dest.htlc_hash == null_hash)
|
||||
{
|
||||
//we use deterministic origin, to make possible access origin on different wallets copies
|
||||
std::string hltc_origin = generate_origin_for_htlc(htlc.pkey_redeem, htlc.pkey_refund, self);
|
||||
std::string hltc_origin = generate_origin_for_htlc(htlc, self);
|
||||
|
||||
//calculate hash
|
||||
if (htlc.flags&CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK)
|
||||
|
|
@ -669,7 +670,7 @@ namespace currency
|
|||
}
|
||||
else
|
||||
{
|
||||
htlc.htlc_hash = de.htlc_hash;
|
||||
htlc.htlc_hash = htlc_dest.htlc_hash;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ namespace currency
|
|||
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);
|
||||
uint64_t get_timstamp_from_word(std::string word, bool& password_used);
|
||||
std::string generate_origin_for_htlc(const crypto::public_key& redeem, const crypto::public_key& refund, const account_keys& acc_keys);
|
||||
std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys);
|
||||
template<class t_txin_v>
|
||||
typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type& get_txin_etc_options(t_txin_v& in)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace currency
|
|||
size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs
|
||||
size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container
|
||||
bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
|
||||
std::string htlc_origin; //for htlc, specify origin
|
||||
|
||||
bool is_multisig() const { return ms_sigs_count > 0; }
|
||||
|
||||
|
|
@ -42,23 +43,43 @@ namespace currency
|
|||
FIELD(ms_sigs_count)
|
||||
FIELD(ms_keys_count)
|
||||
FIELD(separately_signed_tx_complete)
|
||||
END_SERIALIZE()
|
||||
FIELD(htlc_origin)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct destination_option_void
|
||||
{
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//if this struct is present, then creating htlc out, expiration -> number of blocks that htlc proposal is active
|
||||
struct destination_option_htlc_out
|
||||
{
|
||||
uint64_t expiration;
|
||||
crypto::hash htlc_hash;
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(transfer)
|
||||
FIELD(origin)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
typedef boost::variant<destination_option_void, destination_option_htlc_out> destination_option_v;
|
||||
|
||||
struct tx_destination_entry
|
||||
{
|
||||
uint64_t amount; //money
|
||||
std::list<account_public_address> addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
|
||||
size_t minimum_sigs; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
|
||||
uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions
|
||||
uint64_t amount; //money
|
||||
std::list<account_public_address> addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
|
||||
size_t minimum_sigs; //if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
|
||||
uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions
|
||||
uint64_t unlock_time;
|
||||
bool htlc; //if this flag is set, then creating htlc out, unlock_time -> number of blocks that htlc proposal is active
|
||||
crypto::hash htlc_hash;
|
||||
|
||||
tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc(false), htlc_hash(null_hash){}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc(false), htlc_hash(null_hash) {}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(ut), htlc(false), htlc_hash(null_hash) {}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0), unlock_time(0), htlc(false), htlc_hash(null_hash) {}
|
||||
destination_option_v additional_options; //additional options
|
||||
|
||||
|
||||
tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0), unlock_time(0), additional_options(destination_option_void()){}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(0), additional_options(destination_option_void()) {}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(ut), additional_options(destination_option_void()) {}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0), unlock_time(0), additional_options(destination_option_void()) {}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(amount)
|
||||
|
|
@ -66,8 +87,7 @@ namespace currency
|
|||
FIELD(minimum_sigs)
|
||||
FIELD(amount_to_provide)
|
||||
FIELD(unlock_time)
|
||||
FIELD(htlc)
|
||||
FIELD(htlc_hash)
|
||||
FIELD(additional_options)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4021,9 +4021,10 @@ void wallet2::create_htlc_proposal(uint64_t amount, const currency::account_publ
|
|||
dst.resize(1);
|
||||
dst.back().addr.push_back(addr);
|
||||
dst.back().amount = amount;
|
||||
dst.back().htlc = true;
|
||||
dst.back().htlc_hash = htlc_hash;
|
||||
dst.back().unlock_time = 740; //about 12 hours
|
||||
destination_option_htlc_out htlc_option = AUTO_VAL_INIT(htlc_option);
|
||||
htlc_option.expiration = 740; //about 12 hours
|
||||
htlc_option.htlc_hash = htlc_hash;
|
||||
dst.back().additional_options = htlc_option;
|
||||
|
||||
transaction result_tx = AUTO_VAL_INIT(result_tx);
|
||||
this->transfer(dst, 0, 0, TX_DEFAULT_FEE, extra, attachments, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx);
|
||||
|
|
@ -4050,15 +4051,45 @@ void wallet2::get_list_of_active_htlc(bool only_redeem_txs, std::list<wallet_pub
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin)
|
||||
void wallet2::redeem_htlc(const crypto::hash& htlc_tx_id, std::string origin)
|
||||
{
|
||||
//lets figure out, if we have active htlc for this htlc
|
||||
auto it = m_active_htlcs_txid.find(htlc_tx_id);
|
||||
if (it == m_active_htlcs_txid.end())
|
||||
//have correct origin, let's create transaction
|
||||
std::vector<tx_destination_entry> dst;
|
||||
dst.resize(1);
|
||||
dst.back().addr.push_back(m_account.get_keys().account_address);
|
||||
dst.back().amount = 0;
|
||||
|
||||
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
ctp.fee = TX_DEFAULT_FEE;
|
||||
ctp.htlc_tx_id = htlc_tx_id;
|
||||
ctp.htlc_origin = origin;
|
||||
|
||||
/*
|
||||
struct destination_option_htlc_in
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(false,
|
||||
"htlc not found with tx_id = " << htlc_tx_id, API_RETURN_CODE_NOT_FOUND);
|
||||
}
|
||||
uint64_t transfer;
|
||||
std::string origin;
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(transfer)
|
||||
FIELD(origin)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
transfer(const construct_tx_param& ctp,
|
||||
currency::transaction &tx,
|
||||
bool send_to_network,
|
||||
std::string* p_unsigned_filename_or_tx_blob_str);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
currency::transaction result_tx = AUTO_VAL_INIT(tx);
|
||||
transaction result_tx = AUTO_VAL_INIT(result_tx);
|
||||
this->transfer(ctp, result_tx, true, nullptr);
|
||||
|
||||
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
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)
|
||||
|
|
@ -4232,6 +4263,55 @@ bool wallet2::prepare_tx_sources(crypto::hash multisig_id, std::vector<currency:
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
bool wallet2::prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string& origin, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money)
|
||||
{
|
||||
//lets figure out, if we have active htlc for this htlc
|
||||
auto it = m_active_htlcs_txid.find(htlc_tx_id);
|
||||
if (it == m_active_htlcs_txid.end())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(false,
|
||||
"htlc not found with tx_id = " << htlc_tx_id, API_RETURN_CODE_NOT_FOUND);
|
||||
}
|
||||
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(m_transfers.size() > it->second,
|
||||
"Internal error: index in m_active_htlcs_txid <" << it->second << "> is bigger then size of m_transfers <" << m_transfers.size() << ">", API_RETURN_CODE_INTERNAL_ERROR);
|
||||
|
||||
const transfer_details& td = m_transfers[it->second];
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].target.type() == typeid(txout_htlc),
|
||||
"Unexpected type in active htlc", API_RETURN_CODE_INTERNAL_ERROR);
|
||||
|
||||
const txout_htlc& htlc_out = boost::get<txout_htlc>(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].target);
|
||||
bool use_sha256 = !(htlc_out.flags&CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK);
|
||||
|
||||
//check origin
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(origin.size() != 0,
|
||||
"Origin for htlc is empty", API_RETURN_CODE_BAD_ARG);
|
||||
|
||||
crypto::hash htlc_calculated_hash = currency::null_hash;
|
||||
if (use_sha256)
|
||||
{
|
||||
htlc_calculated_hash = crypto::sha256_hash(origin.data(), origin.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
htlc_calculated_hash = crypto::RIPEMD160_hash_256(origin.data(), origin.size());
|
||||
}
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(htlc_calculated_hash == htlc_out.htlc_hash,
|
||||
"Origin hash is missmatched with txout_htlc", API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED);
|
||||
|
||||
sources.push_back(AUTO_VAL_INIT(currency::tx_source_entry()));
|
||||
currency::tx_source_entry& src = sources.back();
|
||||
src.amount = found_money = td.amount();
|
||||
src.real_output_in_tx_index = td.m_internal_output_index;
|
||||
src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx);
|
||||
src.htlc_origin = origin;
|
||||
//src.multisig_id = multisig_id;
|
||||
//src.ms_sigs_count = ms_out.minimum_sigs;
|
||||
//src.ms_keys_count = ms_out.keys.size();
|
||||
return true;
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts)
|
||||
{
|
||||
uint64_t needed_money = fee;
|
||||
|
|
@ -4247,6 +4327,7 @@ uint64_t wallet2::get_needed_money(uint64_t fee, const std::vector<currency::tx_
|
|||
}
|
||||
return needed_money;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
void wallet2::send_transaction_to_network(const transaction& tx)
|
||||
{
|
||||
|
|
@ -4793,11 +4874,24 @@ void wallet2::prepare_transaction(const construct_tx_param& ctp, finalize_tx_par
|
|||
|
||||
TIME_MEASURE_START_MS(prepare_tx_sources_time);
|
||||
if (ctp.perform_packing)
|
||||
{
|
||||
prepare_tx_sources_for_packing(WALLET_DEFAULT_POS_MINT_PACKING_SIZE, 0, ftp.sources, ftp.selected_transfers, found_money);
|
||||
else if (ctp.multisig_id == currency::null_hash)
|
||||
prepare_tx_sources(needed_money, ctp.fake_outputs_count, ctp.dust_policy.dust_threshold, ftp.sources, ftp.selected_transfers, found_money);
|
||||
else
|
||||
}
|
||||
else if (ctp.htlc_tx_id != currency::null_hash)
|
||||
{
|
||||
//htlc
|
||||
bool prepare_tx_sources_htlc(htlc_tx_id, ctp.htlc_origin, sources, found_money);
|
||||
}
|
||||
else if (ctp.multisig_id != currency::null_hash)
|
||||
{
|
||||
//multisig
|
||||
prepare_tx_sources(ctp.multisig_id, ftp.sources, found_money);
|
||||
}
|
||||
else
|
||||
{
|
||||
//regular tx
|
||||
prepare_tx_sources(needed_money, ctp.fake_outputs_count, ctp.dust_policy.dust_threshold, ftp.sources, ftp.selected_transfers, found_money);
|
||||
}
|
||||
TIME_MEASURE_FINISH_MS(prepare_tx_sources_time);
|
||||
|
||||
TIME_MEASURE_START_MS(prepare_tx_destinations_time);
|
||||
|
|
|
|||
|
|
@ -273,6 +273,9 @@ namespace tools
|
|||
uint8_t split_strategy_id;
|
||||
bool mark_tx_as_complete;
|
||||
|
||||
crypto::hash htlc_tx_id;
|
||||
std::string htlc_origin;
|
||||
|
||||
// constructing tx
|
||||
uint64_t unlock_time;
|
||||
std::vector<currency::extra_v> extra;
|
||||
|
|
@ -835,7 +838,7 @@ namespace tools
|
|||
void create_htlc_proposal(uint64_t amount, const currency::account_public_address& addr, uint64_t lock_blocks_count,
|
||||
currency::transaction &tx, const crypto::hash& htlc_hash = currency::null_hash);
|
||||
void get_list_of_active_htlc(bool only_redeem_txs, std::list<wallet_public::htlc_entry_info>& htlcs);
|
||||
void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin);
|
||||
void redeem_htlc(const crypto::hash& htlc_tx_id, std::string origin);
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -895,6 +898,7 @@ private:
|
|||
bool prepare_tx_sources(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
|
||||
bool prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
|
||||
bool prepare_tx_sources(crypto::hash multisig_id, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
|
||||
bool prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string& origin, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
|
||||
bool 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);
|
||||
void prefetch_global_indicies_if_needed(std::vector<uint64_t>& selected_indicies);
|
||||
uint64_t get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue