1
0
Fork 0
forked from lthn/blockchain

Merge branch 'offsig'

This commit is contained in:
sowle 2019-04-30 18:48:14 +02:00
commit 2d3ef5e41f
37 changed files with 1813 additions and 1065 deletions

View file

@ -422,7 +422,6 @@ namespace epee
std::string get_usage()
{
std::stringstream ss;
ss << "Commands: " << ENDL;
size_t max_command_len = 0;
for(auto& x:m_command_handlers)
if(x.first.size() > max_command_len)
@ -430,8 +429,7 @@ namespace epee
for(auto& x:m_command_handlers)
{
ss.width(max_command_len + 3);
ss << " " << std::left << x.first << " " << x.second.second << ENDL;
ss << " " << std::left << std::setw(max_command_len + 3) << x.first << " " << x.second.second << ENDL;
}
return ss.str();
}

View file

@ -83,7 +83,7 @@ namespace epee
bool load_from_binary(const binarybuffer& target);
template<class trace_policy>
bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
bool dump_as_json(std::string& targetObj, size_t indent = 0);
bool dump_as_json(std::string& targetObj, size_t indent = 0, end_of_line_t eol = eol_crlf);
bool load_from_json(const std::string& source);
private:
@ -106,11 +106,11 @@ namespace epee
#pragma pack(pop)
};
inline
bool portable_storage::dump_as_json(std::string& buff, size_t indent)
bool portable_storage::dump_as_json(std::string& buff, size_t indent /* = 0 */, end_of_line_t eol /* = eol_crlf */)
{
TRY_ENTRY();
std::stringstream ss;
epee::serialization::dump_as_json(ss, m_root, indent);
epee::serialization::dump_as_json(ss, m_root, indent, eol);
buff = ss.str();
return true;
CATCH_ENTRY("portable_storage::dump_as_json", false)

View file

@ -69,6 +69,8 @@ namespace epee
{
namespace serialization
{
enum end_of_line_t { eol_crlf = 0, eol_lf = 1, eol_cr = 2, eol_space = 3 };
struct section;
/************************************************************************/

View file

@ -56,16 +56,16 @@ namespace epee
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
bool store_t_to_json(const t_struct& str_in, std::string& json_buff, size_t indent = 0)
bool store_t_to_json(const t_struct& str_in, std::string& json_buff, size_t indent = 0, end_of_line_t eol = eol_crlf)
{
portable_storage ps;
str_in.store(ps);
ps.dump_as_json(json_buff, indent);
ps.dump_as_json(json_buff, indent, eol);
return true;
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
std::string store_t_to_json(const t_struct& str_in, size_t indent = 0)
std::string store_t_to_json(const t_struct& str_in, size_t indent = 0, end_of_line_t eol = eol_crlf)
{
std::string json_buff;
store_t_to_json(str_in, json_buff, indent);

View file

@ -37,23 +37,23 @@ namespace epee
{
template<class t_stream>
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent);
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent);
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const std::string& v, size_t indent);
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent);
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent);
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const bool& v, size_t indent);
void dump_as_json(t_stream& strm, const bool& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const double& v, size_t indent);
void dump_as_json(t_stream& strm, const double& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream, class t_type>
void dump_as_json(t_stream& strm, const t_type& v, size_t indent);
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const section& sec, size_t indent);
void dump_as_json(t_stream& strm, const section& sec, size_t indent, end_of_line_t eol = eol_crlf);
inline std::string make_indent(size_t indent)
@ -66,7 +66,13 @@ namespace epee
{
t_stream& m_strm;
size_t m_indent;
array_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent){}
end_of_line_t m_eol;
array_entry_store_to_json_visitor(t_stream& strm, size_t indent, end_of_line_t eol)
: m_strm(strm)
, m_indent(indent)
, m_eol(eol)
{}
template<class t_type>
void operator()(const array_entry_t<t_type>& a)
@ -77,7 +83,7 @@ namespace epee
auto last_it = --a.m_array.end();
for(auto it = a.m_array.begin(); it != a.m_array.end(); it++)
{
dump_as_json(m_strm, *it, m_indent);
dump_as_json(m_strm, *it, m_indent, m_eol);
if(it != last_it)
m_strm << ",";
}
@ -91,50 +97,56 @@ namespace epee
{
t_stream& m_strm;
size_t m_indent;
storage_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent)
end_of_line_t m_eol;
storage_entry_store_to_json_visitor(t_stream& strm, size_t indent, end_of_line_t eol)
: m_strm(strm)
, m_indent(indent)
, m_eol(eol)
{}
//section, array_entry
template<class visited_type>
void operator()(const visited_type& v)
{
dump_as_json(m_strm, v, m_indent);
dump_as_json(m_strm, v, m_indent, m_eol);
}
};
template<class t_stream>
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent)
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, end_of_line_t eol)
{
array_entry_store_to_json_visitor<t_stream> aesv(strm, indent);
array_entry_store_to_json_visitor<t_stream> aesv(strm, indent, eol);
boost::apply_visitor(aesv, ae);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent)
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, end_of_line_t eol)
{
storage_entry_store_to_json_visitor<t_stream> sv(strm, indent);
storage_entry_store_to_json_visitor<t_stream> sv(strm, indent, eol);
boost::apply_visitor(sv, se);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const std::string& v, size_t indent)
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, end_of_line_t eol)
{
strm << "\"" << misc_utils::parse::transform_to_json_escape_sequence(v) << "\"";
}
template<class t_stream>
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent)
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, end_of_line_t eol)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent)
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, end_of_line_t eol)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const bool& v, size_t indent)
void dump_as_json(t_stream& strm, const bool& v, size_t indent, end_of_line_t eol)
{
if(v)
strm << "true";
@ -143,23 +155,34 @@ namespace epee
}
template<class t_stream>
void dump_as_json(t_stream& strm, const double& v, size_t indent)
void dump_as_json(t_stream& strm, const double& v, size_t indent, end_of_line_t eol)
{
strm.precision(8);
strm << std::fixed << v;
}
template<class t_stream, class t_type>
void dump_as_json(t_stream& strm, const t_type& v, size_t /*indent*/)
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, end_of_line_t eol)
{
strm << v;
}
template<class t_stream>
void dump_as_json(t_stream& strm, const section& sec, size_t indent)
void dump_as_json(t_stream& strm, const section& sec, size_t indent, end_of_line_t eol)
{
auto put_eol = [&]() {
switch (eol)
{
case eol_lf: strm << "\n"; break;
case eol_cr: strm << "\r"; break;
case eol_space: strm << " "; break;
default: strm << "\r\n"; break;
}
};
size_t local_indent = indent + 1;
strm << "{\r\n";
strm << "{";
put_eol();
std::string indent_str = make_indent(local_indent);
if(sec.m_entries.size())
{
@ -167,10 +190,10 @@ namespace epee
for(auto it = sec.m_entries.begin(); it!= sec.m_entries.end();it++)
{
strm << indent_str << "\"" << misc_utils::parse::transform_to_json_escape_sequence(it->first) << "\"" << ": ";
dump_as_json(strm, it->second, local_indent);
dump_as_json(strm, it->second, local_indent, eol);
if(it_last != it)
strm << ",";
strm << "\r\n";
put_eol();
}
}
strm << make_indent(indent) << "}";

View file

@ -648,9 +648,6 @@ POP_WARNINGS
return res;
}
//----------------------------------------------------------------------------
inline std::string cut_off_extension(const std::string& str)
{
std::string res;
@ -661,7 +658,17 @@ POP_WARNINGS
res = str.substr(0, pos);
return res;
}
//----------------------------------------------------------------------------
inline std::wstring cut_off_extension(const std::wstring& str)
{
std::wstring res;
std::wstring::size_type pos = str.rfind('.');
if (std::wstring::npos == pos)
return str;
res = str.substr(0, pos);
return res;
}
//----------------------------------------------------------------------------
// replaces all non-ascii characters with mask_character
inline std::string mask_non_ascii_chars(const std::string& str, const char mask_character = '?')

View file

@ -9,7 +9,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "zlib.h"
#include "../zlib.h"
/* get definition of internal structure so we can mess with it (see pull()),
and so we can call inflate_trees() (see cover5()) */

View file

@ -15,7 +15,7 @@
/* @(#) $Id$ */
#include "zlib.h"
#include "../zlib.h"
#include <stdio.h>
#ifdef STDC

View file

@ -16,8 +16,11 @@ namespace command_line
const arg_descriptor<std::string> arg_config_file = { "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") };
const arg_descriptor<bool> arg_os_version = { "os-version", "" };
const arg_descriptor<std::string> arg_log_dir = { "log-dir", "", "", true};
const arg_descriptor<int> arg_log_level = { "log-level", "", LOG_LEVEL_0, true};
const arg_descriptor<std::string> arg_log_file = { "log-file", "", "" };
const arg_descriptor<int> arg_log_level = { "log-level", "", LOG_LEVEL_0, true };
const arg_descriptor<bool> arg_console = { "no-console", "Disable daemon console commands" };
const arg_descriptor<bool> arg_show_details = { "currency-details", "Display currency details" };
const arg_descriptor<bool> arg_show_rpc_autodoc = { "show_rpc_autodoc", "Display rpc auto-generated documentation template" };

View file

@ -179,6 +179,7 @@ namespace command_line
extern const arg_descriptor<std::string> arg_config_file;
extern const arg_descriptor<bool> arg_os_version;
extern const arg_descriptor<std::string> arg_log_dir;
extern const arg_descriptor<std::string> arg_log_file;
extern const arg_descriptor<int> arg_log_level;
extern const arg_descriptor<bool> arg_console;
extern const arg_descriptor<bool> arg_show_details;

View file

@ -0,0 +1,127 @@
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <string>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
namespace tools
{
template<typename pod_t>
class pod_array_file_container
{
public:
pod_array_file_container()
{}
~pod_array_file_container()
{
close();
}
bool open(const std::wstring& filename, bool create_if_not_exist, bool* p_corrupted = nullptr, std::string* p_reason = nullptr)
{
if (!create_if_not_exist && !boost::filesystem::exists(filename))
{
if (p_reason)
*p_reason = "file doest not exist";
return false;
}
m_stream.open(filename, std::ios::binary | std::ios::app | std::ios::in);
if (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)
{
if (p_reason)
*p_reason = "file could not be opened";
return false;
}
if (p_corrupted)
*p_corrupted = false;
size_t file_size = size_bytes();
if (file_size % sizeof(pod_t) != 0)
{
// currupted
if (p_corrupted)
*p_corrupted = true;
size_t corrected_size = file_size - file_size % sizeof(pod_t);
// truncate to nearest item boundary
close();
boost::filesystem::resize_file(filename, corrected_size);
m_stream.open(filename, std::ios::binary | std::ios::app | std::ios::in);
if ((m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit) ||
size_bytes() != corrected_size)
{
if (p_reason)
*p_reason = "truncation failed";
return false;
}
if (p_reason)
*p_reason = std::string("file was corrupted, truncated: ") + epee::string_tools::num_to_string_fast(file_size) + " -> " + epee::string_tools::num_to_string_fast(corrected_size);
}
return true;
}
void close()
{
m_stream.close();
}
bool push_back(const pod_t& item)
{
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
return false;
m_stream.seekp(0, std::ios_base::end);
m_stream.write(reinterpret_cast<const char*>(&item), sizeof item);
if (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)
return false;
m_stream.flush();
return true;
}
bool get_item(size_t index, pod_t& result) const
{
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
return false;
size_t offset = index * sizeof result;
m_stream.seekg(offset);
if (m_stream.rdstate() != std::ios::goodbit)
return false;
m_stream.read(reinterpret_cast<char*>(&result), sizeof result);
return m_stream.gcount() == sizeof result;
}
size_t size_bytes() const
{
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
return 0;
m_stream.seekg(0, std::ios_base::end);
return m_stream.tellg();
}
size_t size() const
{
return size_bytes() / sizeof(pod_t);
}
private:
mutable boost::filesystem::fstream m_stream;
};
} // namespace tools

View file

@ -78,10 +78,7 @@ namespace crypto {
buff = decrypted_buff;
return true;
}
// inline bool chacha_decrypt(std::string& buff, const std::string& pass)
// {
// return chacha_crypt(buff, pass);
// }
template<typename pod_to_encrypt, typename pod_pass>
inline bool chacha_crypt(pod_to_encrypt& crypt, const pod_pass& pass)
{
@ -91,6 +88,7 @@ namespace crypto {
memcpy(&crypt, buff.data(), sizeof(crypt));
return true;
}
template<typename pod_pass>
inline bool chacha_crypt(std::string& buff, const pod_pass& pass)
{
@ -101,6 +99,15 @@ namespace crypto {
return true;
}
template<typename pod_pass>
inline std::string chacha_crypt(const std::string& input, const pod_pass& pass)
{
std::string result;
result.resize(input.size());
if (chacha_crypt(input.data(), input.size(), (void*)result.data(), &pass, sizeof pass))
return result;
return "";
}
}

View file

@ -229,7 +229,7 @@ namespace crypto {
}
POD_MAKE_COMPARABLE(crypto, public_key)
POD_MAKE_HASHABLE(crypto, public_key)
POD_MAKE_COMPARABLE(crypto, secret_key)
POD_MAKE_HASHABLE(crypto, key_image)
POD_MAKE_COMPARABLE(crypto, signature)

View file

@ -122,11 +122,16 @@ namespace currency
return get_account_address_as_str(m_keys.m_account_address);
}
//-----------------------------------------------------------------
void account_base::make_account_watch_only()
{
m_keys.m_spend_secret_key = currency::null_skey;
}
//-----------------------------------------------------------------
std::string transform_addr_to_str(const account_public_address& addr)
{
return get_account_address_as_str(addr);
}
//-----------------------------------------------------------------
account_public_address transform_str_to_addr(const std::string& str)
{
account_public_address ad = AUTO_VAL_INIT(ad);

View file

@ -63,6 +63,8 @@ namespace currency
bool load(const std::string& file_path);
bool store(const std::string& file_path);
void make_account_watch_only();
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int /*ver*/)
{

View file

@ -51,7 +51,7 @@ namespace currency
const static crypto::signature null_sig = AUTO_VAL_INIT(null_sig);
const static crypto::key_derivation null_derivation = AUTO_VAL_INIT(null_derivation);
typedef std::string payment_id_t;
/************************************************************************/
@ -563,7 +563,8 @@ namespace currency
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(keyimage)
END_KV_SERIALIZE_MAP()
};
}
} // namespace currency
POD_MAKE_HASHABLE(currency, account_public_address);

View file

@ -212,7 +212,7 @@
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+62)
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+63)
#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31)

View file

@ -2443,7 +2443,7 @@ namespace currency
return true;
}
//-----------------------------------------------------------------------
bool is_payment_id_size_ok(const std::string& payment_id)
bool is_payment_id_size_ok(const payment_id_t& payment_id)
{
return payment_id.size() <= BC_PAYMENT_ID_SERVICE_SIZE_MAX;
}
@ -2453,7 +2453,7 @@ namespace currency
return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr));
}
//-----------------------------------------------------------------------
std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const std::string& payment_id)
std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const payment_id_t& payment_id)
{
return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id);
}
@ -2464,7 +2464,7 @@ namespace currency
return get_account_address_and_payment_id_from_str(addr, integrated_payment_id, str);
}
//-----------------------------------------------------------------------
bool get_account_address_and_payment_id_from_str(account_public_address& addr, std::string& payment_id, const std::string& str)
bool get_account_address_and_payment_id_from_str(account_public_address& addr, payment_id_t& payment_id, const std::string& str)
{
static const size_t addr_blob_size = sizeof(account_public_address);
blobdata blob;
@ -2516,6 +2516,11 @@ namespace currency
return true;
}
//---------------------------------------------------------------
bool parse_payment_id_from_hex_str(const std::string& payment_id_str, payment_id_t& payment_id)
{
return epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id);
}
//------------------------------------------------------------------
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median)
{

View file

@ -68,12 +68,26 @@ namespace currency
crypto::public_key real_out_tx_key; //real output's transaction's public key
size_t real_output_in_tx_index; //index in transaction outputs vector
uint64_t amount; //money
uint64_t transfer_index; //money
crypto::hash multisig_id; //if txin_multisig: multisig output id
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
bool is_multisig() const { return ms_sigs_count > 0; }
BEGIN_SERIALIZE_OBJECT()
FIELD(outputs)
FIELD(real_output)
FIELD(real_out_tx_key)
FIELD(real_output_in_tx_index)
FIELD(amount)
FIELD(transfer_index)
FIELD(multisig_id)
FIELD(ms_sigs_count)
FIELD(ms_keys_count)
FIELD(separately_signed_tx_complete)
END_SERIALIZE()
};
struct tx_destination_entry
@ -86,6 +100,13 @@ namespace currency
tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0){}
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0){}
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){}
BEGIN_SERIALIZE_OBJECT()
FIELD(amount)
FIELD(addr)
FIELD(minimum_sigs)
FIELD(amount_to_provide)
END_SERIALIZE()
};
struct tx_extra_info
@ -383,11 +404,12 @@ namespace currency
size_t get_max_tx_size();
bool get_block_reward(bool is_pos, size_t median_size, size_t current_block_size, const boost::multiprecision::uint128_t& already_generated_coins, uint64_t &reward, uint64_t height);
uint64_t get_base_block_reward(bool is_pos, const boost::multiprecision::uint128_t& already_generated_coins, uint64_t height);
bool is_payment_id_size_ok(const std::string& payment_id);
bool is_payment_id_size_ok(const payment_id_t& payment_id);
std::string get_account_address_as_str(const account_public_address& addr);
std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const std::string& payment_id);
std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const payment_id_t& payment_id);
bool get_account_address_from_str(account_public_address& addr, const std::string& str);
bool get_account_address_and_payment_id_from_str(account_public_address& addr, std::string& payment_id, const std::string& str);
bool get_account_address_and_payment_id_from_str(account_public_address& addr, payment_id_t& payment_id, const std::string& str);
bool parse_payment_id_from_hex_str(const std::string& payment_id_str, payment_id_t& payment_id);
bool is_coinbase(const transaction& tx);
bool is_coinbase(const transaction& tx, bool& pos_coinbase);
bool have_attachment_service_in_container(const std::vector<attachment_v>& av, const std::string& service_id, const std::string& instruction);

View file

@ -235,7 +235,7 @@ namespace currency
if (it != m_blocks_id_que.end())
{
//already have this block handler in que
LOG_PRINT("Block " << block_id << " already in processing que", LOG_LEVEL_2);
LOG_PRINT("Block " << block_id << " already in processing que", LOG_LEVEL_3);
return 1;
}
else

View file

@ -650,7 +650,7 @@ bool MainWindow::update_wallet_status(const view::wallet_status_info& wsi)
TRY_ENTRY();
m_wallet_states->operator [](wsi.wallet_id) = wsi.wallet_state;
std::string json_str;
epee::serialization::store_t_to_json(wsi, json_str);
epee::serialization::store_t_to_json(wsi, json_str, 0, epee::serialization::eol_lf);
LOG_PRINT_L0(get_wallet_log_prefix(wsi.wallet_id) + "SENDING SIGNAL -> [update_wallet_status]:" << std::endl << json_str );
QMetaObject::invokeMethod(this, "update_wallet_status", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
return true;
@ -660,7 +660,7 @@ bool MainWindow::set_options(const view::gui_options& opt)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(opt, json_str);
epee::serialization::store_t_to_json(opt, json_str, 0, epee::serialization::eol_lf);
LOG_PRINT_L0("SENDING SIGNAL -> [set_options]:" << std::endl << json_str);
QMetaObject::invokeMethod(this, "set_options", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
return true;
@ -688,7 +688,7 @@ bool MainWindow::update_wallets_info(const view::wallets_summary_info& wsi)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(wsi, json_str);
epee::serialization::store_t_to_json(wsi, json_str, 0, epee::serialization::eol_lf);
LOG_PRINT_L0("SENDING SIGNAL -> [update_wallets_info]"<< std::endl << json_str );
QMetaObject::invokeMethod(this, "update_wallets_info", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
@ -700,7 +700,7 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(tei, json_str);
epee::serialization::store_t_to_json(tei, json_str, 0, epee::serialization::eol_lf);
LOG_PRINT_L0(get_wallet_log_prefix(tei.wallet_id) + "SENDING SIGNAL -> [money_transfer]" << std::endl << json_str);
//this->money_transfer(json_str.c_str());
@ -745,7 +745,7 @@ bool MainWindow::money_transfer_cancel(const view::transfer_event_info& tei)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(tei, json_str);
epee::serialization::store_t_to_json(tei, json_str, 0, epee::serialization::eol_lf);
LOG_PRINT_L0(get_wallet_log_prefix(tei.wallet_id) + "SENDING SIGNAL -> [money_transfer_cancel]");
//this->money_transfer_cancel(json_str.c_str());
@ -760,7 +760,7 @@ bool MainWindow::wallet_sync_progress(const view::wallet_sync_progres_param& p)
TRY_ENTRY();
LOG_PRINT_L2(get_wallet_log_prefix(p.wallet_id) + "SENDING SIGNAL -> [wallet_sync_progress]" << " wallet_id: " << p.wallet_id << ": " << p.progress << "%");
//this->wallet_sync_progress(epee::serialization::store_t_to_json(p).c_str());
QMetaObject::invokeMethod(this, "wallet_sync_progress", Qt::QueuedConnection, Q_ARG(QString, epee::serialization::store_t_to_json(p).c_str()));
QMetaObject::invokeMethod(this, "wallet_sync_progress", Qt::QueuedConnection, Q_ARG(QString, epee::serialization::store_t_to_json(p, 0, epee::serialization::eol_lf).c_str()));
return true;
CATCH_ENTRY2(false);
}
@ -811,7 +811,7 @@ QString MainWindow::get_alias_coast(const QString& param)
PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type<std::string>, lvl);
view::get_alias_coast_response resp;
resp.error_code = m_backend.get_alias_coast(lvl.v, resp.coast);
return epee::serialization::store_t_to_json(resp).c_str();
return epee::serialization::store_t_to_json(resp, 0, epee::serialization::eol_lf).c_str();
CATCH_ENTRY_FAIL_API_RESPONCE();
}
@ -836,7 +836,7 @@ QString MainWindow::set_localization_strings(const QString param)
resp.error_code = API_RETURN_CODE_OK;
LOG_PRINT_L0("New localization set, language title: " << lr.language_title << ", strings " << lr.strings.size());
}
return epee::serialization::store_t_to_json(resp).c_str();
return epee::serialization::store_t_to_json(resp, 0, epee::serialization::eol_lf).c_str();
CATCH_ENTRY_FAIL_API_RESPONCE();
}
@ -1292,7 +1292,7 @@ QString MainWindow::show_openfile_dialog(const QString& param)
if (!epee::serialization::load_t_from_json(ofdr, param.toStdString()))
{
ofdres.error_code = API_RETURN_CODE_BAD_ARG;
return epee::serialization::store_t_to_json(ofdres).c_str();
return epee::serialization::store_t_to_json(ofdres, 0, epee::serialization::eol_lf).c_str();
}
QString path = QFileDialog::getOpenFileName(this, ofdr.caption.c_str(),
@ -1302,7 +1302,7 @@ QString MainWindow::show_openfile_dialog(const QString& param)
if (!path.length())
{
ofdres.error_code = API_RETURN_CODE_CANCELED;
return epee::serialization::store_t_to_json(ofdres).c_str();
return epee::serialization::store_t_to_json(ofdres, 0, epee::serialization::eol_lf).c_str();
}
ofdres.error_code = API_RETURN_CODE_OK;
@ -1325,7 +1325,7 @@ QString MainWindow::show_savefile_dialog(const QString& param)
if (!path.length())
{
ofdres.error_code = API_RETURN_CODE_CANCELED;
return epee::serialization::store_t_to_json(ofdres).c_str();
return epee::serialization::store_t_to_json(ofdres, 0, epee::serialization::eol_lf).c_str();
}
ofdres.error_code = API_RETURN_CODE_OK;

View file

@ -9,28 +9,12 @@
#include <vector>
#include <list>
//#include "serialization.h"
template <template <bool> class Archive, class T>
bool do_serialize(Archive<false> &ar, std::vector<T> &v);
template <template <bool> class Archive, class T>
bool do_serialize(Archive<true> &ar, std::vector<T> &v);
namespace serialization
{
namespace detail
{
template <typename Archive, class T>
bool serialize_container_element(Archive& ar, T& e)
{
return ::do_serialize(ar, e);
}
template <typename Archive>
bool serialize_container_element(Archive& ar, uint64_t& e)
{
ar.serialize_varint(e);
return true;
}
bool serialize_container_element(Archive& ar, T& e);
}
}
@ -266,3 +250,22 @@ bool do_serialize(Archive<true> &ar, std::vector<bool> &v)
ar.end_array();
return true;
}
namespace serialization
{
namespace detail
{
template <typename Archive, class T>
bool serialize_container_element(Archive& ar, T& e)
{
return ::do_serialize(ar, e);
}
template <typename Archive>
bool serialize_container_element(Archive& ar, uint64_t& e)
{
ar.serialize_varint(e);
return true;
}
}
}

View file

@ -47,7 +47,7 @@ namespace
const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of default", 0};
const command_line::arg_descriptor<uint32_t> arg_log_level = {"set-log", "", 0, true};
const command_line::arg_descriptor<bool> arg_do_pos_mining = { "do-pos-mining", "Do PoS mining", false, false };
const command_line::arg_descriptor<bool> arg_offline_mode = { "offline-mode", "Don't connect to daemon, work offline (for cold-signing process)", false, true };
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
@ -156,10 +156,7 @@ std::string simple_wallet::get_commands_str()
{
std::stringstream ss;
ss << "Commands: " << ENDL;
std::string usage = m_cmd_binder.get_usage();
boost::replace_all(usage, "\n", "\n ");
usage.insert(0, " ");
ss << usage << ENDL;
ss << m_cmd_binder.get_usage() << ENDL;
return ss.str();
}
@ -172,10 +169,11 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
simple_wallet::simple_wallet()
: m_daemon_port(0),
m_print_brain_wallet(false),
m_do_refresh(false),
m_do_refresh_after_load(false),
m_do_not_set_date(false),
m_do_pos_mining(false),
m_refresh_progress_reporter(*this)
m_refresh_progress_reporter(*this),
m_offline_mode(false)
{
m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining <threads_count> - Start mining in daemon");
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
@ -185,6 +183,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, _1), "incoming_transfers counts");
m_cmd_binder.set_handler("list_recent_transfers", boost::bind(&simple_wallet::list_recent_transfers, this, _1), "list_recent_transfers - Show recent maximum 1000 transfers");
m_cmd_binder.set_handler("list_recent_transfers_ex", boost::bind(&simple_wallet::list_recent_transfers_ex, this, _1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt");
m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, _1), "list_outputs [spent|unspent] - Lists all the outputs that have ever been sent to this wallet if called without arguments, otherwise it lists only the spent or unspent outputs");
m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, _1), "dump_transfers - Write transfers in json to dump_transfers.txt");
m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, _1), "dump_keyimages - Write key_images in json to dump_key_images.txt");
m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, _1), "payments <payment_id_1> [<payment_id_2> ... <payment_id_N>] - Show payments <payment_id_1>, ... <payment_id_N>");
@ -203,7 +202,11 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("scan_transfers_for_id", boost::bind(&simple_wallet::scan_transfers_for_id, this, _1), "Rescan transfers for tx_id");
m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this, _1), "Rescan transfers for key image");
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::integrated_address, this, _1), "integrated_address [<payment_id>|<integrated_address] - encodes given payment_id along with wallet's address into an integrated address (random payment_id will be used if none is provided). Decodes given integrated_address into standard address");
m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), "Get transaction one-time secret key (r) for a given <txid>");
m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "save_watch_only <filename> <password> - save as watch-only wallet file.");
m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), "sign_transfer <unsgined_tx_file> <signed_tx_file> - sign unsigned tx from a watch-only wallet");
m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), "submit_transfer <signed_tx_file> - broadcast signed tx");
}
//----------------------------------------------------------------------------------------------------
@ -278,10 +281,10 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
}
m_do_refresh = true;
m_do_refresh_after_load = true;
if (command_line::has_arg(vm, arg_dont_refresh))
{
m_do_refresh = false;
m_do_refresh_after_load = false;
}
if (command_line::has_arg(vm, arg_print_brain_wallet))
@ -388,8 +391,8 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
try
{
m_wallet->load(epee::string_encoding::convert_to_unicode(m_wallet_file), password);
message_writer(epee::log_space::console_color_white, true) << "Opened wallet: " << m_wallet->get_account().get_public_address_str();
message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
if (m_print_brain_wallet)
std::cout << "Brain wallet: " << m_wallet->get_account().get_restore_braindata() << std::endl << std::flush;
@ -411,7 +414,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
m_wallet->init(m_daemon_address);
if (!m_do_refresh)
if (m_do_refresh_after_load && !m_offline_mode)
refresh(std::vector<std::string>());
success_msg_writer() <<
@ -538,6 +541,12 @@ void simple_wallet::on_money_spent(uint64_t height, const currency::transaction&
//----------------------------------------------------------------------------------------------------
bool simple_wallet::refresh(const std::vector<std::string>& args)
{
if (m_offline_mode)
{
success_msg_writer() << "refresh is meaningless in OFFLINE MODE";
return true;
}
if (!try_connect_to_daemon())
return true;
@ -1075,7 +1084,11 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
currency::transaction tx;
std::vector<extra_v> extra;
m_wallet->transfer(dsts, fake_outs_count, 0, m_wallet->get_core_runtime_config().tx_default_fee, extra, attachments, tx);
success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx) << ", " << get_object_blobsize(tx) << " bytes";
if (!m_wallet->is_watch_only())
success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx) << ", " << get_object_blobsize(tx) << " bytes";
else
success_msg_writer(true) << "Transaction prepared for signing and saved into \"zano_tx_unsigned\" file, use full wallet to sign transfer and then use \"submit_transfer\" on this wallet to broadcast the transaction to the network";
}
catch (const tools::error::daemon_busy&)
{
@ -1158,7 +1171,12 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
bool simple_wallet::run()
{
std::string addr_start = m_wallet->get_account().get_public_address_str().substr(0, 6);
return m_cmd_binder.run_handling("[" CURRENCY_NAME_BASE " wallet " + addr_start + "]: ", "");
std::string prompt;
if (m_wallet->is_watch_only())
prompt = "[" CURRENCY_NAME_BASE " WO wallet " + addr_start + "]: ";
else
prompt = "[" CURRENCY_NAME_BASE " wallet " + addr_start + "]: ";
return m_cmd_binder.run_handling(prompt, "");
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::stop()
@ -1236,6 +1254,158 @@ bool simple_wallet::integrated_address(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
{
std::vector<std::string> local_args = args_;
if (local_args.size() != 1) {
fail_msg_writer() << "usage: get_tx_key <txid>";
return true;
}
currency::blobdata txid_data;
if (!epee::string_tools::parse_hexstr_to_binbuff(local_args.front(), txid_data) || txid_data.size() != sizeof(crypto::hash))
{
fail_msg_writer() << "failed to parse txid";
return true;
}
crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
crypto::secret_key tx_key;
std::vector<crypto::secret_key> amount_keys;
if (m_wallet->get_tx_key(txid, tx_key))
{
success_msg_writer() << "tx one-time secret key: " << epee::string_tools::pod_to_hex(tx_key);
return true;
}
else
{
fail_msg_writer() << "no tx keys found for this txid";
return true;
}
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::set_offline_mode(bool offline_mode)
{
if (offline_mode && !m_offline_mode)
{
message_writer(epee::log_space::console_color_yellow, true, std::string(), LOG_LEVEL_0)
<< "WARNING: the wallet is running in OFFLINE MODE!";
}
m_offline_mode = offline_mode;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::save_watch_only(const std::vector<std::string> &args)
{
if (args.size() < 2)
{
fail_msg_writer() << "wrong parameters, expected filename and password";
return true;
}
try
{
m_wallet->store_watch_only(epee::string_encoding::convert_to_unicode(args[0]), args[1]);
success_msg_writer() << "Watch-only wallet has been stored to " << args[0];
}
catch (const std::exception& e)
{
LOG_ERROR("unexpected error: " << e.what());
fail_msg_writer() << "unexpected error: " << e.what();
}
catch (...)
{
LOG_ERROR("Unknown error");
fail_msg_writer() << "unknown error";
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::list_outputs(const std::vector<std::string> &args)
{
if (args.size() > 1)
{
fail_msg_writer() << "invalid syntax: one or none parameters are expected, " << args.size() << " was given";
return true;
}
bool include_spent = true, include_unspent = true;
if (args.size() == 1)
{
if (args[0] == "unspent" || args[0] == "available")
include_spent = false;
else if (args[0] == "spent" || args[0] == "unavailable")
include_unspent = false;
else
{
fail_msg_writer() << "invalid parameter: " << args[0];
return true;
}
}
success_msg_writer() << "list of all the outputs that have ever been sent to this wallet:" << ENDL <<
m_wallet->get_transfers_str(include_spent, include_unspent);
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sign_transfer(const std::vector<std::string> &args)
{
if (m_wallet->is_watch_only())
{
fail_msg_writer() << "You can't sign transaction in watch-only wallet";
return true;
}
if (args.size() < 2)
{
fail_msg_writer() << "wrong parameters, expected: <unsigned_tx_file> <signed_tx_file>";
return true;
}
try
{
currency::transaction res_tx;
m_wallet->sign_transfer_files(args[0], args[1], res_tx);
success_msg_writer(true) << "transaction signed and stored to file: " << args[1] << ", transaction " << get_transaction_hash(res_tx) << ", " << get_object_blobsize(res_tx) << " bytes";
}
catch (const std::exception& e)
{
LOG_ERROR("unexpected error: " << e.what());
fail_msg_writer() << "unexpected error: " << e.what();
}
catch (...)
{
LOG_ERROR("Unknown error");
fail_msg_writer() << "unknown error";
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::submit_transfer(const std::vector<std::string> &args)
{
if (args.size() < 1)
{
fail_msg_writer() << "wrong parameters, expected filename";
return true;
}
try
{
currency::transaction res_tx;
m_wallet->submit_transfer_files(args[0], res_tx);
success_msg_writer(true) << "transaction " << get_transaction_hash(res_tx) << " was successfully sent, size: " << get_object_blobsize(res_tx) << " bytes";
}
catch (const std::exception& e)
{
LOG_ERROR("unexpected error: " << e.what());
fail_msg_writer() << "unexpected error: " << e.what();
}
catch (...)
{
LOG_ERROR("Unknown error");
fail_msg_writer() << "unknown error";
}
return true;
}
//----------------------------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
#ifdef WIN32
@ -1270,13 +1440,17 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_dont_set_date);
command_line::add_arg(desc_params, arg_print_brain_wallet);
command_line::add_arg(desc_params, arg_do_pos_mining);
command_line::add_arg(desc_params, arg_offline_mode);
command_line::add_arg(desc_params, command_line::arg_log_file);
command_line::add_arg(desc_params, command_line::arg_log_level);
tools::wallet_rpc_server::init_options(desc_params);
po::positional_options_description positional_options;
positional_options.add(arg_command.name, -1);
shared_ptr<currency::simple_wallet> sw(new currency::simple_wallet);
po::options_description desc_all;
desc_all.add(desc_general).add(desc_params);
po::variables_map vm;
@ -1286,9 +1460,8 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
simple_wallet w;
success_msg_writer() << "Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>]";
success_msg_writer() << desc_all << '\n' << w.get_commands_str();
success_msg_writer() << desc_all << '\n' << sw->get_commands_str();
return false;
}
else if (command_line::get_arg(vm, command_line::arg_version))
@ -1307,22 +1480,32 @@ int main(int argc, char* argv[])
//set up logging options
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
log_space::log_singletone::add_logger(LOGGER_FILE,
log_space::log_singletone::get_default_log_file().c_str(),
log_space::log_singletone::get_default_log_folder().c_str(), LOG_LEVEL_4);
boost::filesystem::path log_file_path(command_line::get_arg(vm, command_line::arg_log_file));
if (log_file_path.empty())
log_file_path = log_space::log_singletone::get_default_log_file();
std::string log_dir;
log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder();
log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str(), LOG_LEVEL_4);
message_writer(epee::log_space::console_color_white, true) << CURRENCY_NAME << " wallet v" << PROJECT_VERSION_LONG;
if(command_line::has_arg(vm, arg_log_level))
if (command_line::has_arg(vm, arg_log_level))
{
LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level));
log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level));
}
if (command_line::has_arg(vm, command_line::arg_log_level))
{
LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, command_line::arg_log_level));
log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, command_line::arg_log_level));
}
bool offline_mode = command_line::get_arg(vm, arg_offline_mode);
if(command_line::has_arg(vm, tools::wallet_rpc_server::arg_rpc_bind_port))
{
// runs wallet as RPC server
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2);
sw->set_offline_mode(offline_mode);
LOG_PRINT_L0("Starting wallet RPC server...");
if (!command_line::has_arg(vm, arg_wallet_file) || command_line::get_arg(vm, arg_wallet_file).empty())
@ -1331,7 +1514,7 @@ int main(int argc, char* argv[])
return 1;
}
if (!command_line::has_arg(vm, arg_daemon_address) )
if (!command_line::has_arg(vm, arg_daemon_address) && !command_line::has_arg(vm, arg_offline_mode))
{
LOG_ERROR("Daemon address is not set.");
return 1;
@ -1384,7 +1567,8 @@ int main(int argc, char* argv[])
wal.init(daemon_address);
if (command_line::get_arg(vm, arg_generate_new_wallet).size())
return 1;
wal.refresh();
if (!offline_mode)
wal.refresh();
LOG_PRINT_GREEN("Loaded ok", LOG_LEVEL_0);
}
catch (const std::exception& e)
@ -1404,7 +1588,7 @@ int main(int argc, char* argv[])
wrpc.send_stop_signal();
});
LOG_PRINT_L0("Starting wallet rpc server");
wrpc.run(command_line::get_arg(vm, arg_do_pos_mining) );
wrpc.run(command_line::get_arg(vm, arg_do_pos_mining), offline_mode);
LOG_PRINT_L0("Stopped wallet rpc server");
try
{
@ -1419,8 +1603,8 @@ int main(int argc, char* argv[])
}
}else
{
shared_ptr<currency::simple_wallet> sw(new currency::simple_wallet);
//runs wallet with console interface
sw->set_offline_mode(offline_mode);
r = sw->init(vm);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
if (command_line::get_arg(vm, arg_generate_new_wallet).size())

View file

@ -33,6 +33,7 @@ namespace currency
bool deinit();
bool run();
void stop();
void set_offline_mode(bool offline_mode);
//wallet *create_wallet();
bool process_command(const std::vector<std::string> &args);
@ -57,6 +58,7 @@ namespace currency
bool dump_key_images(const std::vector<std::string>& args);
bool show_incoming_transfers(const std::vector<std::string> &args);
bool show_incoming_transfers_counts(const std::vector<std::string> &args);
bool list_outputs(const std::vector<std::string> &args);
bool show_payments(const std::vector<std::string> &args);
bool get_transfer_info(const std::vector<std::string> &args);
bool scan_for_key_image_collisions(const std::vector<std::string> &args);
@ -72,6 +74,10 @@ namespace currency
bool set_log(const std::vector<std::string> &args);
bool enable_concole_logger(const std::vector<std::string> &args);
bool integrated_address(const std::vector<std::string> &args);
bool get_tx_key(const std::vector<std::string> &args_);
bool save_watch_only(const std::vector<std::string> &args);
bool sign_transfer(const std::vector<std::string> &args);
bool submit_transfer(const std::vector<std::string> &args);
bool get_alias_from_daemon(const std::string& alias_name, currency::extra_alias_entry_base& ai);
bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr);
@ -145,10 +151,11 @@ namespace currency
std::string m_daemon_address;
std::string m_daemon_host;
int m_daemon_port;
bool m_do_refresh;
bool m_do_refresh_after_load;
bool m_do_not_set_date;
bool m_print_brain_wallet;
bool m_do_pos_mining;
bool m_offline_mode;
epee::console_handlers_binder m_cmd_binder;

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,7 @@
#include "currency_core/offers_services_helpers.h"
#include "currency_core/bc_offers_serialization.h"
#include "currency_core/bc_escrow_service.h"
#include "common/pod_array_file_container.h"
#define WALLET_DEFAULT_TX_SPENDABLE_AGE 10
@ -106,22 +107,210 @@ namespace tools
, addr_for_dust(an_addr_for_dust)
{
}
};
BEGIN_SERIALIZE_OBJECT()
FIELD(dust_threshold)
FIELD(add_to_fee)
FIELD(addr_for_dust)
END_SERIALIZE()
};
class test_generator;
#pragma pack(push, 1)
struct out_key_to_ki
{
out_key_to_ki() {}
out_key_to_ki(const crypto::public_key& out_key, const crypto::key_image& key_image) : out_key(out_key), key_image(key_image) {}
crypto::public_key out_key;
crypto::key_image key_image;
};
#pragma pack(pop)
typedef tools::pod_array_file_container<out_key_to_ki> pending_ki_file_container_t;
namespace detail
{
//----------------------------------------------------------------------------------------------------
inline void digit_split_strategy(const std::vector<currency::tx_destination_entry>& dsts,
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
splitted_dsts.clear();
dust = 0;
for(auto& de : dsts)
{
if (de.addr.size() > 1)
{
//for multisig we don't split
splitted_dsts.push_back(de);
}
else
{
currency::decompose_amount_into_digits(de.amount, dust_threshold,
[&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, de.addr)); },
[&](uint64_t a_dust) { splitted_dsts.push_back(currency::tx_destination_entry(a_dust, de.addr)); }, max_output_allowed);
}
}
if (change_dst.amount > 0)
{
if (change_dst.addr.size() > 1)
{
//for multisig we don't split
splitted_dsts.push_back(change_dst);
}
else
{
currency::decompose_amount_into_digits(change_dst.amount, dust_threshold,
[&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, change_dst.addr)); },
[&](uint64_t a_dust) { dust = a_dust; }, max_output_allowed);
}
}
}
//----------------------------------------------------------------------------------------------------
inline void null_split_strategy(const std::vector<currency::tx_destination_entry>& dsts,
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
splitted_dsts = dsts;
dust = 0;
uint64_t change = change_dst.amount;
if (0 < dust_threshold)
{
for (uint64_t order = 10; order <= 10 * dust_threshold; order *= 10)
{
uint64_t dust_candidate = change_dst.amount % order;
uint64_t change_candidate = (change_dst.amount / order) * order;
if (dust_candidate <= dust_threshold)
{
dust = dust_candidate;
change = change_candidate;
}
else
{
break;
}
}
}
if (0 != change)
{
splitted_dsts.push_back(currency::tx_destination_entry(change, change_dst.addr));
}
}
//----------------------------------------------------------------------------------------------------
inline void void_split_strategy(const std::vector<currency::tx_destination_entry>& dsts,
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
splitted_dsts = dsts;
if (change_dst.amount > 0)
splitted_dsts.push_back(change_dst);
}
//----------------------------------------------------------------------------------------------------
enum split_strategy_id_t { ssi_none = 0, ssi_digit = 1, ssi_null = 2, ssi_void = 3 };
//----------------------------------------------------------------------------------------------------
inline bool apply_split_strategy_by_id(split_strategy_id_t id, const std::vector<currency::tx_destination_entry>& dsts,
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
switch (id)
{
case ssi_digit:
digit_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed);
return true;
case ssi_null:
null_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed);
return true;
case ssi_void:
void_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed);
return true;
default:
return false;
}
}
} // namespace detail
struct construct_tx_param
{
// preparing data for tx
std::vector<currency::tx_destination_entry> dsts;
size_t fake_outputs_count;
uint64_t fee;
tx_dust_policy dust_policy;
crypto::hash multisig_id;
uint8_t flags;
uint8_t split_strategy_id;
bool mark_tx_as_complete;
// constructing tx
uint64_t unlock_time;
std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments;
currency::account_public_address crypt_address;
uint8_t tx_outs_attr;
bool shuffle;
};
struct finalize_tx_param
{
uint64_t unlock_time;
std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments;
currency::account_public_address crypt_address;
uint8_t tx_outs_attr;
bool shuffle;
uint8_t flags;
crypto::hash multisig_id;
std::vector<currency::tx_source_entry> sources;
std::vector<uint64_t> selected_transfers;
std::vector<currency::tx_destination_entry> prepared_destinations;
crypto::public_key spend_pub_key; // only for validations
BEGIN_SERIALIZE_OBJECT()
FIELD(unlock_time)
FIELD(extra)
FIELD(attachments)
FIELD(crypt_address)
FIELD(tx_outs_attr)
FIELD(shuffle)
FIELD(flags)
FIELD(multisig_id)
FIELD(sources)
FIELD(selected_transfers)
FIELD(prepared_destinations)
FIELD(spend_pub_key)
END_SERIALIZE()
};
struct finalized_tx
{
currency::transaction tx;
crypto::secret_key one_time_key;
finalize_tx_param ftp;
std::vector<std::pair<uint64_t, crypto::key_image>> outs_key_images; // pairs (out_index, key_image) for each change output
BEGIN_SERIALIZE_OBJECT()
FIELD(tx)
FIELD(one_time_key)
FIELD(ftp)
FIELD(outs_key_images)
END_SERIALIZE()
};
class wallet2
{
wallet2(const wallet2&) : m_stop(false),
m_wcallback(new i_wallet2_callback()),
m_height_of_start_sync(0),
m_last_sync_percent(0),
m_do_rise_transfer(false)
m_do_rise_transfer(false),
m_watch_only(false)
{};
public:
wallet2() : m_stop(false),
@ -132,16 +321,19 @@ namespace tools
m_last_sync_percent(0),
m_fake_outputs_count(0),
m_do_rise_transfer(false),
m_log_prefix("???")
m_log_prefix("???"),
m_watch_only(false)
{
m_core_runtime_config = currency::get_default_core_runtime_config();
};
#define WALLET_TRANSFER_DETAIL_FLAG_SPENT 0x00000001
#define WALLET_TRANSFER_DETAIL_FLAG_BLOCKED 0x00000002
#define WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION 0x00000004
#define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER 0x00000008
#define WALLET_TRANSFER_DETAIL_FLAG_SPENT uint32_t(1 << 0)
#define WALLET_TRANSFER_DETAIL_FLAG_BLOCKED uint32_t(1 << 1)
#define WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION uint32_t(1 << 2)
#define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER uint32_t(1 << 3)
#define WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION uint32_t(1 << 4) // transfer is reserved for cold-signing (unsigned tx was created and passed for signing)
static std::string transfer_flags_to_str(uint32_t flags);
static std::string transform_tx_to_str(const currency::transaction& tx);
static currency::transaction transform_str_to_tx(const std::string& tx_str);
@ -176,9 +368,9 @@ namespace tools
uint64_t amount() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index].amount; }
bool is_spent() const { return m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT; }
bool is_spendable() const { return (m_flags & (~WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER)) == 0; } // spenable = has no flags or mined flag only
BEGIN_KV_SERIALIZE_MAP()
//KV_SERIALIZE(*m_ptx_wallet_info)
KV_SERIALIZE_CUSTOM(m_ptx_wallet_info, const transaction_wallet_info&, tools::wallet2::transform_ptr_to_value, tools::wallet2::transform_value_to_ptr)
KV_SERIALIZE(m_internal_output_index)
KV_SERIALIZE(m_spent_height)
@ -255,6 +447,9 @@ namespace tools
void load(const std::wstring& wallet, const std::string& password);
void store();
void store(const std::wstring& path);
void store(const std::wstring& path, const std::string& password);
void store_watch_only(const std::wstring& path, const std::string& password) const;
bool store_keys(std::string& buff, const std::string& password, bool store_as_watch_only = false);
std::wstring get_wallet_path(){ return m_wallet_file; }
currency::account_base& get_account() { return m_account; }
const currency::account_base& get_account() const { return m_account; }
@ -299,44 +494,43 @@ namespace tools
void transfer(uint64_t amount, const currency::account_public_address& acc);
template<typename T>
void transfer(const std::vector<currency::tx_destination_entry>& dsts,
size_t fake_outputs_count,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
T destination_split_strategy,
const std::vector<currency::attachment_v>& attachments,
detail::split_strategy_id_t destination_split_strategy_id,
const tx_dust_policy& dust_policy);
template<typename destination_split_strategy_t>
void transfer(const std::vector<currency::tx_destination_entry>& dsts,
size_t fake_outputs_count,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
destination_split_strategy_t destination_split_strategy,
const std::vector<currency::attachment_v>& attachments,
detail::split_strategy_id_t destination_split_strategy_id,
const tx_dust_policy& dust_policy,
currency::transaction &tx,
uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED,
bool shuffle = true,
uint8_t flags = 0,
bool send_to_network = true);
bool send_to_network = true,
std::string* p_signed_tx_blob_str = nullptr);
void transfer(const std::vector<currency::tx_destination_entry>& dsts,
size_t fake_outputs_count,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments);
const std::vector<currency::attachment_v>& attachments);
void transfer(const std::vector<currency::tx_destination_entry>& dsts,
size_t fake_outputs_count,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
const std::vector<currency::attachment_v>& attachments,
currency::transaction& tx);
template<typename destination_split_strategy_t>
@ -348,7 +542,7 @@ namespace tools
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
const std::vector<currency::attachment_v>& attachments,
destination_split_strategy_t destination_split_strategy,
const tx_dust_policy& dust_policy,
currency::transaction &tx,
@ -379,7 +573,7 @@ namespace tools
const std::string& payment_id,
currency::transaction& tx,
std::vector<uint64_t>& selected_transfers,
currency::keypair& one_time_key);
crypto::secret_key& one_time_key);
void send_escrow_proposal(const bc_services::contract_private_details& ecrow_detaild,
size_t fake_outputs_count,
@ -389,18 +583,24 @@ namespace tools
uint64_t b_release_fee,
const std::string& payment_id,
currency::transaction &proposal_tx,
currency::transaction &escrow_template_tx /*,
crypto::hash& contract_id*/ );
currency::transaction &escrow_template_tx);
bool check_connection();
template<typename idle_condition_cb_t> //do refresh as external callback
static bool scan_pos(mining_context& cxt, std::atomic<bool>& stop, idle_condition_cb_t idle_condition_cb, const currency::core_runtime_config &runtime_config);
bool fill_mining_context(mining_context& ctx);
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
std::string get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/) const;
// Returns all payments by given id in unspecified order
void get_payments(const std::string& payment_id, std::list<payment_details>& payments) const;
void get_payments(const std::string& payment_id, std::list<payment_details>& payments, uint64_t min_height = 0) const;
bool is_watch_only() const { return m_watch_only; }
void sign_transfer(const std::string& tx_sources_blob, std::string& signed_tx_blob, currency::transaction& tx);
void sign_transfer_files(const std::string& tx_sources_file, const std::string& signed_tx_file, currency::transaction& tx);
void submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx);
void submit_transfer_files(const std::string& signed_tx_file, currency::transaction& tx);
bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id);
uint64_t get_blockchain_current_height() const { return m_blockchain.size(); }
template <class t_archive>
@ -412,8 +612,10 @@ namespace tools
a & m_transfers;
a & m_multisig_transfers;
a & m_key_images;
a & m_pending_key_images;
a & m_unconfirmed_txs;
a & m_unconfirmed_multisig_transfers;
a & m_tx_keys;
a & m_payments;
a & m_transfer_history;
a & m_unconfirmed_in_transfers;
@ -478,33 +680,16 @@ namespace tools
bool get_contracts(escrow_contracts_container& contracts);
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;
template<typename destination_split_strategy_t>
void prepare_transaction(const std::vector<currency::tx_destination_entry>& dsts,
size_t fake_outputs_count,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
destination_split_strategy_t destination_split_strategy,
const tx_dust_policy& dust_policy,
const currency::account_public_address& crypt_address,
currency::transaction &tx,
uint8_t tx_outs_attr,
bool shuffle,
bool mark_tx_as_complete,
uint8_t flags,
std::vector<uint64_t>& selected_transfers,
currency::keypair& one_time_key,
std::vector<currency::tx_destination_entry>& prepared_destinations,
crypto::hash multisig_id = currency::null_hash);
void prepare_transaction(const construct_tx_param& ctp, finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate = currency::transaction());
void finalize_transaction(const finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx);
std::string get_log_prefix() const { return m_log_prefix; }
private:
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);
bool store_keys(std::string& buff, const std::string& password);
void load_keys(const std::string& keys_file_name, const std::string& password);
void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b);
void detach_blockchain(uint64_t height);
@ -521,7 +706,7 @@ private:
uint64_t select_transfers(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust, std::vector<uint64_t>& selected_indicies);
void add_transfers_to_transfers_cache(const std::vector<uint64_t>& indexs);
void add_transfer_to_transfers_cache(uint64_t amount, uint64_t index);
bool prepare_file_names(const std::string& file_path);
bool prepare_file_names(const std::wstring& file_path);
void process_unconfirmed(const currency::transaction& tx, std::vector<std::string>& recipients, std::vector<std::string>& recipients_aliases);
void add_sent_unconfirmed_tx(const currency::transaction& tx,
const std::vector<std::string>& recipients,
@ -558,10 +743,9 @@ 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(crypto::hash multisig_id, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
uint64_t get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts);
template<class destination_split_strategy_t>
void prepare_tx_destinations(uint64_t needed_money,
uint64_t found_money,
destination_split_strategy_t destination_split_strategy,
detail::split_strategy_id_t destination_split_strategy_id,
const tx_dust_policy& dust_policy,
const std::vector<currency::tx_destination_entry>& dsts,
std::vector<currency::tx_destination_entry>& final_detinations);
@ -577,7 +761,7 @@ private:
uint64_t get_tx_expiration_median() const;
void print_tx_sent_message(const currency::transaction& tx, const std::string& description, uint64_t fee);
void print_tx_sent_message(const currency::transaction& tx, const std::string& description, uint64_t fee = UINT64_MAX);
// Validates escrow template tx in assumption it's related to wallet's account (wallet's account is either A or B party in escrow process)
bool validate_escrow_proposal(const wallet_rpc::wallet_transfer_info& wti, const bc_services::proposal_body& prop,
@ -601,54 +785,27 @@ private:
void print_source_entry(const currency::tx_source_entry& src) const;
void init_log_prefix();
struct construct_tx_param
{
std::vector<currency::tx_destination_entry> dsts;
size_t fake_outputs_count;
uint64_t unlock_time;
uint64_t fee;
std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments;
tx_dust_policy dust_policy;
currency::account_public_address crypt_address;
uint8_t tx_outs_attr;
bool shuffle;
bool mark_tx_as_complete;
uint8_t flags;
crypto::hash multisig_id;
};
struct constructed_tx_data
{
std::vector<currency::tx_destination_entry> prepared_destinations;
currency::transaction tx;
std::vector<uint64_t> selected_transfers;
currency::keypair one_time_key;
};
template<typename destination_split_strategy_t>
void prepare_transaction(const construct_tx_param& construct_tx_data,
constructed_tx_data& res, destination_split_strategy_t destination_split_strategy);
void load_keys2ki(bool create_if_not_exist, bool& need_to_resync);
void send_transaction_to_network(const currency::transaction& tx);
void add_sent_tx_detailed_info(const currency::transaction& tx,
const std::vector<currency::tx_destination_entry>& destinations,
const std::vector<uint64_t>& selected_indicies);
void mark_transfers_as_spent(const std::vector<uint64_t>& selected_transfers, const std::string& reason = std::string());
void mark_transfers_with_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason = std::string());
void mark_transfers_with_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason = std::string(), bool throw_if_flag_already_set = false);
void clear_transfers_from_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason = std::string());
void exception_handler();
void exception_handler() const;
uint64_t get_minimum_allowed_fee_for_contract(const crypto::hash& ms_id);
currency::account_base m_account;
bool m_watch_only;
std::string m_log_prefix; // part of pub address, prefix for logging functions
std::wstring m_wallet_file;
std::wstring m_pending_ki_file;
std::string m_password;
std::vector<crypto::hash> m_blockchain;
std::atomic<uint64_t> m_local_bc_height; //temporary workaround
@ -659,6 +816,8 @@ private:
multisig_transfer_container m_multisig_transfers;
payment_container m_payments;
std::unordered_map<crypto::key_image, size_t> m_key_images;
std::unordered_map<crypto::public_key, crypto::key_image> m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key
pending_ki_file_container_t m_pending_key_images_file_container;
uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
std::atomic<bool> m_stop;
@ -666,6 +825,7 @@ private:
std::unordered_map<crypto::hash, currency::transaction> m_unconfirmed_in_transfers;
std::unordered_map<crypto::hash, tools::wallet_rpc::wallet_transfer_info> m_unconfirmed_txs;
std::unordered_set<crypto::hash> m_unconfirmed_multisig_transfers;
std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys;
std::shared_ptr<i_core_proxy> m_core_proxy;
std::shared_ptr<i_wallet2_callback> m_wcallback;
@ -681,10 +841,9 @@ private:
std::string m_miner_text_info;
};
}
}; // class wallet2
} // namespace tools
BOOST_CLASS_VERSION(tools::wallet2, WALLET_FILE_SERIALIZATION_VERSION)
BOOST_CLASS_VERSION(tools::wallet_rpc::wallet_transfer_info, 9)
@ -815,322 +974,6 @@ namespace boost
namespace tools
{
namespace detail
{
//----------------------------------------------------------------------------------------------------
inline void digit_split_strategy(const std::vector<currency::tx_destination_entry>& dsts,
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
splitted_dsts.clear();
dust = 0;
BOOST_FOREACH(auto& de, dsts)
{
if (de.addr.size() > 1)
{
//for multisig we don't split
splitted_dsts.push_back(de);
}
else
{
currency::decompose_amount_into_digits(de.amount, dust_threshold,
[&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, de.addr)); },
[&](uint64_t a_dust) { splitted_dsts.push_back(currency::tx_destination_entry(a_dust, de.addr)); }, max_output_allowed);
}
}
if (change_dst.amount > 0)
{
if (change_dst.addr.size() > 1)
{
//for multisig we don't split
splitted_dsts.push_back(change_dst);
}
else
{
currency::decompose_amount_into_digits(change_dst.amount, dust_threshold,
[&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, change_dst.addr)); },
[&](uint64_t a_dust) { dust = a_dust; }, max_output_allowed);
}
}
}
//----------------------------------------------------------------------------------------------------
inline void null_split_strategy(const std::vector<currency::tx_destination_entry>& dsts,
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
splitted_dsts = dsts;
dust = 0;
uint64_t change = change_dst.amount;
if (0 < dust_threshold)
{
for (uint64_t order = 10; order <= 10 * dust_threshold; order *= 10)
{
uint64_t dust_candidate = change_dst.amount % order;
uint64_t change_candidate = (change_dst.amount / order) * order;
if (dust_candidate <= dust_threshold)
{
dust = dust_candidate;
change = change_candidate;
}
else
{
break;
}
}
}
if (0 != change)
{
splitted_dsts.push_back(currency::tx_destination_entry(change, change_dst.addr));
}
}
//----------------------------------------------------------------------------------------------------
inline void void_split_strategy(const std::vector<currency::tx_destination_entry>& dsts,
const currency::tx_destination_entry& change_dst, uint64_t dust_threshold,
std::vector<currency::tx_destination_entry>& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed)
{
splitted_dsts = dsts;
if (change_dst.amount > 0)
splitted_dsts.push_back(change_dst);
}
//----------------------------------------------------------------------------------------------------
}
//----------------------------------------------------------------------------------------------------
template<typename T>
void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, const std::vector<currency::extra_v>& extra, const std::vector<currency::attachment_v> attachments, T destination_split_strategy, const tx_dust_policy& dust_policy)
{
currency::transaction tx;
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, attachments, destination_split_strategy, dust_policy, tx);
}
//----------------------------------------------------------------------------------------------------
template<typename destination_split_strategy_t>
void wallet2::prepare_tx_destinations(uint64_t needed_money,
uint64_t found_money,
destination_split_strategy_t destination_split_strategy,
const tx_dust_policy& dust_policy,
const std::vector<currency::tx_destination_entry>& dsts,
std::vector<currency::tx_destination_entry>& final_detinations)
{
currency::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
if (needed_money < found_money)
{
change_dts.addr.push_back(m_account.get_keys().m_account_address);
change_dts.amount = found_money - needed_money;
}
THROW_IF_FALSE_WALLET_EX(found_money >= needed_money, error::wallet_internal_error, "needed_money(" + std::to_string(needed_money)
+ ") < found_money(" + std::to_string(found_money) + ") ");
uint64_t dust = 0;
destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, final_detinations, dust, WALLET_MAX_ALLOWED_OUTPUT_AMOUNT);
THROW_IF_FALSE_WALLET_EX(dust_policy.dust_threshold >= dust, error::wallet_internal_error, "invalid dust value: dust = " +
std::to_string(dust) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold));
//@#@
#ifdef _DEBUG
if (final_detinations.size() > 10)
{
WLT_LOG_L0("final_detinations.size()=" << final_detinations.size());
}
#endif
//@#@
if (0 != dust && !dust_policy.add_to_fee)
{
final_detinations.push_back(currency::tx_destination_entry(dust, dust_policy.addr_for_dust));
}
}
//----------------------------------------------------------------------------------------------------
template<typename destination_split_strategy_t>
void wallet2::prepare_transaction(const std::vector<currency::tx_destination_entry>& dsts,
size_t fake_outputs_count,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
destination_split_strategy_t destination_split_strategy,
const tx_dust_policy& dust_policy,
const currency::account_public_address& crypt_address,
currency::transaction &tx,
uint8_t tx_outs_attr,
bool shuffle,
bool mark_tx_as_complete,
uint8_t flags,
std::vector<uint64_t>& selected_transfers,
currency::keypair& one_time_key,
std::vector<currency::tx_destination_entry>& prepared_destinations,
crypto::hash multisig_id)
{
TIME_MEASURE_START_MS(get_needed_money_time);
uint64_t needed_money = get_needed_money(fee, dsts);
if (flags&TX_FLAG_SIGNATURE_MODE_SEPARATE && tx.vout.size())
{
needed_money += (currency::get_outs_money_amount(tx) - get_inputs_money_amount(tx));
}
TIME_MEASURE_FINISH_MS(get_needed_money_time);
std::vector<currency::tx_source_entry> sources;
uint64_t found_money = 0;
TIME_MEASURE_START_MS(prepare_tx_sources_time);
if (multisig_id == currency::null_hash)
{
prepare_tx_sources(needed_money, fake_outputs_count, dust_policy.dust_threshold, sources, selected_transfers, found_money);
}
else
{
prepare_tx_sources(multisig_id, sources, found_money);
}
TIME_MEASURE_FINISH_MS(prepare_tx_sources_time);
TIME_MEASURE_START_MS(prepare_tx_destinations_time);
prepare_tx_destinations(needed_money, found_money, destination_split_strategy, dust_policy, dsts, prepared_destinations);
TIME_MEASURE_FINISH_MS(prepare_tx_destinations_time);
if (mark_tx_as_complete && !sources.empty())
sources.back().separately_signed_tx_complete = true;
TIME_MEASURE_START_MS(construct_tx_time);
bool r = currency::construct_tx(m_account.get_keys(),
sources,
prepared_destinations,
extra,
attachments,
tx,
one_time_key.sec,
unlock_time,
crypt_address,
0,
tx_outs_attr,
shuffle,
flags);
TIME_MEASURE_FINISH_MS(construct_tx_time);
THROW_IF_TRUE_WALLET_EX(!r, error::tx_not_constructed, sources, prepared_destinations, unlock_time);
TIME_MEASURE_START_MS(sign_ms_input_time);
if (multisig_id != currency::null_hash)
{
// In case there's multisig input is used -- sign it partially with this wallet's keys (we don't have any others here).
// NOTE: this tx will not be ready to send until all other necessary signs for ms input would made.
auto it = m_multisig_transfers.find(multisig_id);
THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_multisig_transfers.end(), "can't find multisig_id: " << multisig_id);
const currency::transaction& ms_source_tx = it->second.m_ptx_wallet_info->m_tx;
bool is_tx_input_fully_signed = false;
r = sign_multisig_input_in_tx(tx, 0, m_account.get_keys(), ms_source_tx, &is_tx_input_fully_signed);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r && !is_tx_input_fully_signed, "sign_multisig_input_in_tx failed: r = " << r << ", is_tx_input_fully_signed = " << is_tx_input_fully_signed);
}
TIME_MEASURE_FINISH_MS(sign_ms_input_time);
THROW_IF_TRUE_WALLET_EX(CURRENCY_MAX_TRANSACTION_BLOB_SIZE <= get_object_blobsize(tx), error::tx_too_big, tx, m_upper_transaction_size_limit);
WLT_LOG_GREEN("[prepare_transaction]: get_needed_money_time: " << get_needed_money_time << " ms"
<< ", prepare_tx_sources_time: " << prepare_tx_sources_time << " ms"
<< ", prepare_tx_destinations_time: " << prepare_tx_destinations_time << " ms"
<< ", construct_tx_time: " << construct_tx_time << " ms"
<< ", sign_ms_input_time: " << sign_ms_input_time << " ms",
LOG_LEVEL_0);
}
template<typename destination_split_strategy_t>
void wallet2::prepare_transaction(const construct_tx_param& construct_tx_data, constructed_tx_data& res,
destination_split_strategy_t destination_split_strategy)
{
return prepare_transaction(construct_tx_data.dsts,
construct_tx_data.fake_outputs_count,
construct_tx_data.unlock_time,
construct_tx_data.fee,
construct_tx_data.extra,
construct_tx_data.attachments,
destination_split_strategy,
construct_tx_data.dust_policy,
construct_tx_data.crypt_address,
res.tx,
construct_tx_data.tx_outs_attr,
construct_tx_data.shuffle,
construct_tx_data.mark_tx_as_complete,
construct_tx_data.flags,
res.selected_transfers,
res.one_time_key,
res.prepared_destinations,
construct_tx_data.multisig_id);
}
//----------------------------------------------------------------------------------------------------
template<typename destination_split_strategy_t>
void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
size_t fake_outputs_count,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
destination_split_strategy_t destination_split_strategy,
const tx_dust_policy& dust_policy,
currency::transaction &tx,
uint8_t tx_outs_attr,
bool shuffle,
uint8_t flags,
bool send_to_network)
{
TIME_MEASURE_START(precalculation_time);
using namespace currency;
std::vector<uint64_t> selected_transfers;
std::vector<currency::tx_destination_entry> prepared_destinations;
account_public_address crypt_address = currency::get_crypt_address_from_destinations(m_account.get_keys(), dsts);
currency::keypair onetime_keys = AUTO_VAL_INIT(onetime_keys);
TIME_MEASURE_FINISH(precalculation_time);
TIME_MEASURE_START(prepare_transaction_time);
prepare_transaction(dsts,
fake_outputs_count,
unlock_time,
fee,
extra,
attachments,
destination_split_strategy,
dust_policy,
crypt_address,
tx,
tx_outs_attr,
shuffle,
false,
flags,
selected_transfers,
onetime_keys,
prepared_destinations);
TIME_MEASURE_FINISH(prepare_transaction_time);
TIME_MEASURE_START(send_transaction_to_network_time);
if (send_to_network)
send_transaction_to_network(tx);
TIME_MEASURE_FINISH(send_transaction_to_network_time);
TIME_MEASURE_START(mark_transfers_as_spent_time);
mark_transfers_as_spent(selected_transfers, std::string("money transfer"));
TIME_MEASURE_FINISH(mark_transfers_as_spent_time);
TIME_MEASURE_START(add_sent_tx_detailed_info_time);
add_sent_tx_detailed_info(tx, prepared_destinations, selected_transfers);
TIME_MEASURE_FINISH(add_sent_tx_detailed_info_time);
WLT_LOG_GREEN("[wallet::transfer] prepare_transaction_time: " << print_fixed_decimal_point(prepare_transaction_time, 3)
<< ", precalculation_time: " << print_fixed_decimal_point(precalculation_time, 3)
<< ", send_transaction_to_network_time: " << print_fixed_decimal_point(send_transaction_to_network_time, 3)
<< ", mark_transfers_as_spent_time: " << print_fixed_decimal_point(mark_transfers_as_spent_time, 3)
<< ", add_sent_tx_detailed_info_time: " << print_fixed_decimal_point(add_sent_tx_detailed_info_time, 3),
LOG_LEVEL_0);
//print_tx_sent_message(tx, std::string() + "(transaction)", fee);
}
//----------------------------------------------------------------------------------------------------
template<typename idle_condition_cb_t> //do refresh as external callback
bool wallet2::scan_pos(mining_context& cxt,
std::atomic<bool>& stop,
@ -1232,8 +1075,7 @@ namespace tools
return false;
}
}
} // namespace tools
#if !defined(KEEP_WALLET_LOG_MACROS)
#undef WLT_LOG_L0
@ -1250,6 +1092,7 @@ namespace tools
#undef WLT_LOG_YELLOW
#undef WLT_CHECK_AND_ASSERT_MES
#undef WLT_CHECK_AND_ASSERT_MES_NO_RET
// TODO update this list
#endif

View file

@ -124,6 +124,14 @@ namespace tools
}
};
//----------------------------------------------------------------------------------------------------
struct wallet_common_error : public wallet_runtime_error
{
explicit wallet_common_error(std::string&& loc, const std::string& message)
: wallet_runtime_error(std::move(loc), message)
{
}
};
//----------------------------------------------------------------------------------------------------
struct unexpected_txin_type : public wallet_internal_error
{
explicit unexpected_txin_type(std::string&& loc, const currency::transaction& tx)
@ -668,5 +676,15 @@ if (cond)
tools::error::throw_wallet_ex<tools::error::wallet_internal_error>(std::string(__FILE__ ":" STRINGIZE(__LINE__)), ss.str()); \
}
#define THROW_IF_FALSE_WALLET_INT_ERR_EX_NO_HANDLER(cond, mess) THROW_IF_TRUE_WALLET_INT_ERR_EX_NO_HANDLER((!(cond)), mess)
#define THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, mess) THROW_IF_TRUE_WALLET_INT_ERR_EX((!(cond)), mess)
#define THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, mess) \
if (!(cond)) \
{ \
std::stringstream ss; \
ss << mess; \
LOG_ERROR(" (" << #cond << ") is FALSE. THROW EXCEPTION: wallet_common_error"); \
tools::error::throw_wallet_ex<tools::error::wallet_common_error>(std::string(__FILE__ ":" STRINGIZE(__LINE__)), ss.str()); \
}

View file

@ -33,22 +33,26 @@ namespace tools
wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w), m_do_mint(false)
{}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::run(bool do_mint)
bool wallet_rpc_server::run(bool do_mint, bool offline_mode)
{
m_do_mint = do_mint;
m_net_server.add_idle_handler([this](){
size_t blocks_fetched = 0;
bool received_money = false;
bool ok;
std::atomic<bool> stop(false);
m_wallet.refresh(blocks_fetched, received_money, ok, stop);
if (stop)
return true;
if(m_do_mint)
m_wallet.try_mint_pos();
return true;
}, 2000);
if (!offline_mode)
{
m_net_server.add_idle_handler([this]() {
size_t blocks_fetched = 0;
bool received_money = false;
bool ok;
std::atomic<bool> stop(false);
m_wallet.refresh(blocks_fetched, received_money, ok, stop);
if (stop)
return true;
if (m_do_mint)
m_wallet.try_mint_pos();
return true;
}, 2000);
}
//DO NOT START THIS SERVER IN MORE THEN 1 THREADS WITHOUT REFACTORING
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::run(1, true);
@ -158,8 +162,17 @@ namespace tools
currency::transaction tx;
std::vector<currency::extra_v> extra;
m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, extra, attachments, tx);
res.tx_hash = epee::string_tools::pod_to_hex(currency::get_transaction_hash(tx));
std::string signed_tx_blob_str;
m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, CURRENCY_TO_KEY_OUT_RELAXED, true, 0, true, &signed_tx_blob_str);
if (m_wallet.is_watch_only())
{
res.tx_unsigned_hex = epee::string_tools::buff_to_hex_nodelimer(signed_tx_blob_str); // watch-only wallets can't sign and relay transactions
// leave res.tx_hash empty, because tx has will change after signing
}
else
{
res.tx_hash = epee::string_tools::pod_to_hex(currency::get_transaction_hash(tx));
}
return true;
}
catch (const tools::error::daemon_busy& e)
@ -201,7 +214,7 @@ namespace tools
bool wallet_rpc_server::on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string payment_id;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.payment_id, payment_id))
if (!currency::parse_payment_id_from_hex_str(req.payment_id, payment_id))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
er.message = std::string("invalid payment id given: \'") + req.payment_id + "\', hex-encoded string was expected";
@ -214,6 +227,7 @@ namespace tools
for (auto payment : payment_list)
{
wallet_rpc::payment_details rpc_payment;
rpc_payment.payment_id = req.payment_id;
rpc_payment.tx_hash = epee::string_tools::pod_to_hex(payment.m_tx_hash);
rpc_payment.amount = payment.m_amount;
rpc_payment.block_height = payment.m_block_height;
@ -224,6 +238,38 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_bulk_payments(const wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
res.payments.clear();
for (auto & payment_id_str : req.payment_ids)
{
currency::payment_id_t payment_id;
if (!currency::parse_payment_id_from_hex_str(payment_id_str, payment_id))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
er.message = std::string("invalid payment id given: \'") + payment_id_str + "\', hex-encoded string was expected";
return false;
}
std::list<wallet2::payment_details> payment_list;
m_wallet.get_payments(payment_id, payment_list, req.min_block_height);
for (auto & payment : payment_list)
{
wallet_rpc::payment_details rpc_payment;
rpc_payment.payment_id = payment_id_str;
rpc_payment.tx_hash = epee::string_tools::pod_to_hex(payment.m_tx_hash);
rpc_payment.amount = payment.m_amount;
rpc_payment.block_height = payment.m_block_height;
rpc_payment.unlock_time = payment.m_unlock_time;
res.payments.push_back(std::move(rpc_payment));
}
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_make_integrated_address(const wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string payment_id;
@ -269,276 +315,70 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_maketelepod(const wallet_rpc::COMMAND_RPC_MAKETELEPOD::request& req, wallet_rpc::COMMAND_RPC_MAKETELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx)
bool wallet_rpc_server::on_sign_transfer(const wallet_rpc::COMMAND_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_SIGN_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
//check available balance
if (m_wallet.unlocked_balance() <= req.amount)
{
res.status = "INSUFFICIENT_COINS";
return true;
}
currency::account_base acc;
acc.generate();
std::vector<currency::tx_destination_entry> dsts(1);
dsts.back().amount = req.amount;
dsts.back().addr.resize(1);
dsts.back().addr.back() = acc.get_keys().m_account_address;
currency::transaction tx = AUTO_VAL_INIT(tx);
try
{
std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments;
m_wallet.transfer(dsts, 0, 0, m_wallet.get_core_runtime_config().tx_default_fee, extra, attachments, tx);
}
catch (const std::runtime_error& er)
{
LOG_ERROR("Failed to send transaction: " << er.what());
res.status = "INTERNAL_ERROR";
return true;
}
res.tpd.basement_tx_id_hex = string_tools::pod_to_hex(currency::get_transaction_hash(tx));
std::string buff = epee::serialization::store_t_to_binary(acc);
res.tpd.account_keys_hex = string_tools::buff_to_hex_nodelimer(buff);
res.status = "OK";
LOG_PRINT_GREEN("TELEPOD ISSUED [" << currency::print_money(req.amount) << "BBR, base_tx_id: ]" << currency::get_transaction_hash(tx), LOG_LEVEL_0);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::build_transaction_from_telepod(const wallet_rpc::telepod& tlp, const currency::account_public_address& acc2, currency::transaction& tx2, std::string& status)
{
//check if base transaction confirmed
currency::COMMAND_RPC_GET_TRANSACTIONS::request get_tx_req = AUTO_VAL_INIT(get_tx_req);
currency::COMMAND_RPC_GET_TRANSACTIONS::response get_tx_rsp = AUTO_VAL_INIT(get_tx_rsp);
get_tx_req.txs_hashes.push_back(tlp.basement_tx_id_hex);
if (!m_wallet.get_core_proxy()->call_COMMAND_RPC_GET_TRANSACTIONS(get_tx_req, get_tx_rsp)
|| get_tx_rsp.status != CORE_RPC_STATUS_OK
|| !get_tx_rsp.txs_as_hex.size())
{
status = "UNCONFIRMED";
return false;
}
//extract account keys
std::string acc_buff;
currency::account_base acc = AUTO_VAL_INIT(acc);
if (!string_tools::parse_hexstr_to_binbuff(tlp.account_keys_hex, acc_buff))
{
LOG_ERROR("Failed to parse_hexstr_to_binbuff(tlp.account_keys_hex, acc_buff)");
status = "BAD";
return false;
}
if (!epee::serialization::load_t_from_binary(acc, acc_buff))
{
LOG_ERROR("Failed to load_t_from_binary(acc, acc_buff)");
status = "BAD";
return false;
}
//extract transaction
currency::transaction tx = AUTO_VAL_INIT(tx);
std::string buff;
if (!string_tools::parse_hexstr_to_binbuff(get_tx_rsp.txs_as_hex.back(), buff))
{
LOG_ERROR("Failed to parse_hexstr_to_binbuff(get_tx_rsp.txs_as_hex.back(), buff)");
status = "INTERNAL_ERROR";
return false;
}
if (!currency::parse_and_validate_tx_from_blob(buff, tx))
{
LOG_ERROR("Failed to currency::parse_and_validate_tx_from_blob(buff, tx)");
status = "INTERNAL_ERROR";
return false;
}
crypto::public_key tx_pub_key = currency::get_tx_pub_key_from_extra(tx);
if (tx_pub_key == currency::null_pkey)
{
LOG_ERROR("Failed to currency::get_tx_pub_key_from_extra(tx)");
status = "BAD";
return false;
}
//get transaction global output indices
currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request get_ind_req = AUTO_VAL_INIT(get_ind_req);
currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response get_ind_rsp = AUTO_VAL_INIT(get_ind_rsp);
get_ind_req.txid = currency::get_transaction_hash(tx);
if (!m_wallet.get_core_proxy()->call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(get_ind_req, get_ind_rsp)
|| get_ind_rsp.status != CORE_RPC_STATUS_OK
|| get_ind_rsp.o_indexes.size() != tx.vout.size())
{
LOG_ERROR("Problem with call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(....) ");
status = "INTERNAL_ERROR";
return false;
}
//prepare inputs
std::vector<currency::tx_source_entry> sources;
size_t i = 0;
uint64_t amount = 0;
for (auto& o : get_ind_rsp.o_indexes)
{
//check if input is for telepod's address
if (currency::is_out_to_acc(acc.get_keys(), boost::get<currency::txout_to_key>(tx.vout[i].target), tx_pub_key, i))
currency::transaction tx = AUTO_VAL_INIT(tx);
std::string tx_unsigned_blob;
if (!string_tools::parse_hexstr_to_binbuff(req.tx_unsigned_hex, tx_unsigned_blob))
{
//income output
amount += tx.vout[i].amount;
sources.resize(sources.size() + 1);
currency::tx_source_entry& tse = sources.back();
tse.amount = tx.vout[i].amount;
tse.outputs.push_back(currency::tx_source_entry::output_entry(o, boost::get<currency::txout_to_key>(tx.vout[i].target).key));
tse.real_out_tx_key = tx_pub_key;
tse.real_output = 0;
tse.real_output_in_tx_index = i;
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "tx_unsigned_hex is invalid";
return false;
}
++i;
std::string tx_signed_blob;
m_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));
}
//prepare outputs
std::vector<currency::tx_destination_entry> dsts(1);
currency::tx_destination_entry& dst = dsts.back();
dst.addr.push_back(acc2);
dst.amount = amount - m_wallet.get_core_runtime_config().tx_default_fee;
//generate transaction
const std::vector<currency::extra_v> extra;
const std::vector<currency::attachment_v> attachments;
crypto::secret_key sk;
bool r = currency::construct_tx(acc.get_keys(), sources, dsts, extra, attachments, tx2, sk, 0);
if (!r)
catch (const std::exception& e)
{
LOG_ERROR("Problem with construct_tx(....) ");
status = "INTERNAL_ERROR";
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
er.message = e.what();
return false;
}
if (CURRENCY_MAX_TRANSACTION_BLOB_SIZE <= get_object_blobsize(tx2))
catch (...)
{
LOG_ERROR("Problem with construct_tx(....), blobl size os too big: " << get_object_blobsize(tx2));
status = "INTERNAL_ERROR";
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_submit_transfer(const wallet_rpc::COMMAND_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::string tx_signed_blob;
if (!string_tools::parse_hexstr_to_binbuff(req.tx_signed_hex, tx_signed_blob))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
er.message = "tx_signed_hex is invalid";
return false;
}
try
{
currency::transaction tx = AUTO_VAL_INIT(tx);
m_wallet.submit_transfer(tx_signed_blob, tx);
res.tx_hash = epee::string_tools::pod_to_hex(currency::get_transaction_hash(tx));
}
catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
er.message = e.what();
return false;
}
catch (...)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_clonetelepod(const wallet_rpc::COMMAND_RPC_CLONETELEPOD::request& req, wallet_rpc::COMMAND_RPC_CLONETELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
currency::transaction tx2 = AUTO_VAL_INIT(tx2);
//new destination account
currency::account_base acc2 = AUTO_VAL_INIT(acc2);
acc2.generate();
if (!build_transaction_from_telepod(req.tpd, acc2.get_keys().m_account_address, tx2, res.status))
{
LOG_ERROR("Failed to build_transaction_from_telepod(...)");
return true;
}
//send transaction to daemon
currency::COMMAND_RPC_SEND_RAW_TX::request req_send_raw;
req_send_raw.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx2));
currency::COMMAND_RPC_SEND_RAW_TX::response rsp_send_raw;
bool r = m_wallet.get_core_proxy()->call_COMMAND_RPC_SEND_RAW_TX(req_send_raw, rsp_send_raw);
if (!r || rsp_send_raw.status != CORE_RPC_STATUS_OK)
{
LOG_ERROR("Problem with construct_tx(....), blobl size os too big: " << get_object_blobsize(tx2));
res.status = "INTERNAL_ERROR";
return true;
}
res.tpd.basement_tx_id_hex = string_tools::pod_to_hex(currency::get_transaction_hash(tx2));
std::string acc2_buff = epee::serialization::store_t_to_binary(acc2);
res.tpd.account_keys_hex = string_tools::buff_to_hex_nodelimer(acc2_buff);
res.status = "OK";
LOG_PRINT_GREEN("TELEPOD ISSUED [" << currency::print_money(currency::get_outs_money_amount(tx2)) << "BBR, base_tx_id: ]" << currency::get_transaction_hash(tx2), LOG_LEVEL_0);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_telepodstatus(const wallet_rpc::COMMAND_RPC_TELEPODSTATUS::request& req, wallet_rpc::COMMAND_RPC_TELEPODSTATUS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
currency::transaction tx2 = AUTO_VAL_INIT(tx2);
//new destination account
currency::account_base acc2 = AUTO_VAL_INIT(acc2);
acc2.generate();
if (!build_transaction_from_telepod(req.tpd, acc2.get_keys().m_account_address, tx2, res.status))
{
return true;
}
//check if transaction is spent
currency::COMMAND_RPC_CHECK_KEYIMAGES::request req_ki = AUTO_VAL_INIT(req_ki);
currency::COMMAND_RPC_CHECK_KEYIMAGES::response rsp_ki = AUTO_VAL_INIT(rsp_ki);
for (auto& i : tx2.vin)
req_ki.images.push_back(boost::get<currency::txin_to_key>(i).k_image);
if (!m_wallet.get_core_proxy()->call_COMMAND_RPC_COMMAND_RPC_CHECK_KEYIMAGES(req_ki, rsp_ki)
|| rsp_ki.status != CORE_RPC_STATUS_OK
|| rsp_ki.images_stat.size() != req_ki.images.size())
{
LOG_ERROR("Problem with call_COMMAND_RPC_COMMAND_RPC_CHECK_KEYIMAGES(....)");
res.status = "INTERNAL_ERROR";
return true;
}
for (auto s : rsp_ki.images_stat)
{
if (!s)
{
res.status = "SPENT";
return true;
}
}
res.status = "OK";
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_withdrawtelepod(const wallet_rpc::COMMAND_RPC_WITHDRAWTELEPOD::request& req, wallet_rpc::COMMAND_RPC_WITHDRAWTELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
currency::transaction tx2 = AUTO_VAL_INIT(tx2);
//parse destination add
currency::account_public_address acc_addr = AUTO_VAL_INIT(acc_addr);
if (!currency::get_account_address_from_str(acc_addr, req.addr))
{
LOG_ERROR("Failed to build_transaction_from_telepod(...)");
res.status = "BAD_ADDRESS";
return true;
}
if (!build_transaction_from_telepod(req.tpd, acc_addr, tx2, res.status))
{
LOG_ERROR("Failed to build_transaction_from_telepod(...)");
return true;
}
//send transaction to daemon
currency::COMMAND_RPC_SEND_RAW_TX::request req_send_raw;
req_send_raw.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx2));
currency::COMMAND_RPC_SEND_RAW_TX::response rsp_send_raw;
bool r = m_wallet.get_core_proxy()->call_COMMAND_RPC_SEND_RAW_TX(req_send_raw, rsp_send_raw);
if (!r || rsp_send_raw.status != CORE_RPC_STATUS_OK)
{
LOG_ERROR("Problem with construct_tx(....), blobl size os too big: " << get_object_blobsize(tx2));
res.status = "INTERNAL_ERROR";
return true;
}
res.status = "OK";
LOG_PRINT_GREEN("TELEPOD WITHDRAWN [" << currency::print_money(currency::get_outs_money_amount(tx2)) << "BBR, tx_id: ]" << currency::get_transaction_hash(tx2), LOG_LEVEL_0);
return true;
}
}
} // namespace tools

View file

@ -32,24 +32,22 @@ namespace tools
static void init_options(boost::program_options::options_description& desc);
bool init(const boost::program_options::variables_map& vm);
bool run(bool do_mint);
bool run(bool do_mint, bool offline_mode);
CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map
BEGIN_URI_MAP2()
BEGIN_JSON_RPC_MAP("/json_rpc")
MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_rpc::COMMAND_RPC_GET_ADDRESS)
MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE)
MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_rpc::COMMAND_RPC_GET_PAYMENTS)
MAP_JON_RPC_WE("make_integrated_address", on_make_integrated_address, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS)
MAP_JON_RPC_WE("split_integrated_address", on_split_integrated_address, wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS)
// supernet api
MAP_JON_RPC_WE("maketelepod", on_maketelepod, wallet_rpc::COMMAND_RPC_MAKETELEPOD)
MAP_JON_RPC_WE("clonetelepod", on_clonetelepod, wallet_rpc::COMMAND_RPC_CLONETELEPOD)
MAP_JON_RPC_WE("telepodstatus", on_telepodstatus, wallet_rpc::COMMAND_RPC_TELEPODSTATUS)
MAP_JON_RPC_WE("withdrawtelepod", on_withdrawtelepod, wallet_rpc::COMMAND_RPC_WITHDRAWTELEPOD)
MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_rpc::COMMAND_RPC_GET_ADDRESS)
MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE)
MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_rpc::COMMAND_RPC_GET_PAYMENTS)
MAP_JON_RPC_WE("get_bulk_payments", on_get_bulk_payments, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS)
MAP_JON_RPC_WE("make_integrated_address", on_make_integrated_address, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS)
MAP_JON_RPC_WE("split_integrated_address", on_split_integrated_address, wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS)
MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_rpc::COMMAND_SIGN_TRANSFER)
MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_rpc::COMMAND_SUBMIT_TRANSFER)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -59,15 +57,13 @@ namespace tools
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_bulk_payments(const wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_make_integrated_address(const wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_split_integrated_address(const wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_maketelepod(const wallet_rpc::COMMAND_RPC_MAKETELEPOD::request& req, wallet_rpc::COMMAND_RPC_MAKETELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_clonetelepod(const wallet_rpc::COMMAND_RPC_CLONETELEPOD::request& req, wallet_rpc::COMMAND_RPC_CLONETELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_telepodstatus(const wallet_rpc::COMMAND_RPC_TELEPODSTATUS::request& req, wallet_rpc::COMMAND_RPC_TELEPODSTATUS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_withdrawtelepod(const wallet_rpc::COMMAND_RPC_WITHDRAWTELEPOD::request& req, wallet_rpc::COMMAND_RPC_WITHDRAWTELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_sign_transfer(const wallet_rpc::COMMAND_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_SIGN_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_submit_transfer(const wallet_rpc::COMMAND_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool handle_command_line(const boost::program_options::variables_map& vm);
bool build_transaction_from_telepod(const wallet_rpc::telepod& tlp, const currency::account_public_address& acc2, currency::transaction& tx2, std::string& status);
private:
wallet2& m_wallet;
@ -75,4 +71,5 @@ namespace tools
std::string m_bind_ip;
bool m_do_mint;
};
}
} // namespace tools

View file

@ -231,9 +231,11 @@ namespace wallet_rpc
struct response
{
std::string tx_hash;
std::string tx_unsigned_hex; // for cold-signing process
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(tx_unsigned_hex)
END_KV_SERIALIZE_MAP()
};
};
@ -255,12 +257,14 @@ namespace wallet_rpc
struct payment_details
{
std::string payment_id;
std::string tx_hash;
uint64_t amount;
uint64_t block_height;
uint64_t unlock_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payment_id)
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(amount)
KV_SERIALIZE(block_height)
@ -289,6 +293,29 @@ namespace wallet_rpc
};
};
struct COMMAND_RPC_GET_BULK_PAYMENTS
{
struct request
{
std::vector<std::string> payment_ids;
uint64_t min_block_height;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payment_ids)
KV_SERIALIZE(min_block_height)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::list<payment_details> payments;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payments)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_MAKE_INTEGRATED_ADDRESS
{
struct request
@ -335,6 +362,51 @@ namespace wallet_rpc
};
};
struct COMMAND_SIGN_TRANSFER
{
struct request
{
std::string tx_unsigned_hex;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_unsigned_hex)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string tx_signed_hex;
std::string tx_hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_signed_hex)
KV_SERIALIZE(tx_hash)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_SUBMIT_TRANSFER
{
struct request
{
//std::string tx_unsigned_hex;
std::string tx_signed_hex;
BEGIN_KV_SERIALIZE_MAP()
//KV_SERIALIZE(tx_unsigned_hex)
KV_SERIALIZE(tx_signed_hex)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string tx_hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
END_KV_SERIALIZE_MAP()
};
};
/*stay-alone instance*/
struct telepod

View file

@ -12,3 +12,4 @@
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY -3
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4
#define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5
#define WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT -6

View file

@ -397,7 +397,7 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std
currency::transaction tx = AUTO_VAL_INIT(tx);
std::vector<tx_destination_entry> destinations{ tx_destination_entry(se.amount, wlt_to->get_account().get_public_address()) };
wlt_from->transfer(destinations, 0, 0, se.fee, empty_extra, empty_attachment, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
wlt_from->transfer(destinations, 0, 0, se.fee, empty_extra, empty_attachment, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
CHECK_AND_NO_ASSERT_MES(mine_next_block_with_tx(c, tx), false, "mine_next_block_with_tx failed");
mine_empty_block = false;

View file

@ -27,16 +27,15 @@ void exception_handler(){}
//==============================================================================================================================
// helper routine: creates multisig-spending tx using a wallet and keys of other ms-participants, then sends it to the core proxy
template<typename destination_split_strategy_t>
void transfer_multisig(tools::wallet2& w,
const std::list<currency::account_keys>& owner_keys,
crypto::hash multisig_id,
const crypto::hash& multisig_id,
const std::vector<currency::tx_destination_entry>& dsts,
uint64_t unlock_time,
uint64_t fee,
const std::vector<currency::extra_v>& extra,
const std::vector<currency::attachment_v> attachments,
destination_split_strategy_t destination_split_strategy,
const std::vector<currency::attachment_v>& attachments,
tools::detail::split_strategy_id_t split_strategy_id,
const tools::tx_dust_policy& dust_policy,
currency::transaction &tx,
uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED,
@ -44,31 +43,28 @@ void transfer_multisig(tools::wallet2& w,
bool shuffle = true,
bool send_to_network = true)
{
using namespace currency;
std::vector<uint64_t> selected_transfers;
std::vector<currency::tx_destination_entry> prepared_destinations;
currency::account_public_address crypt_address = get_crypt_address_from_destinations(w.get_account().get_keys(), dsts);
currency::keypair one_time_keys = AUTO_VAL_INIT(one_time_keys);
// prepare transaction will sign ms input partially with wallet's keys - it needed to be signed fully with the others
w.prepare_transaction(dsts,
0,
unlock_time,
fee,
extra,
attachments,
destination_split_strategy,
dust_policy,
crypt_address,
tx,
tx_outs_attr,
shuffle,
false,
flags,
selected_transfers,
one_time_keys,
prepared_destinations,
multisig_id);
tools::construct_tx_param ctp = AUTO_VAL_INIT(ctp);
tools::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
ctp.attachments = attachments;
ctp.crypt_address = crypt_address;
ctp.dsts = dsts;
ctp.dust_policy = dust_policy;
ctp.extra = extra;
ctp.fake_outputs_count = 0;
ctp.fee = fee;
ctp.flags = flags;
ctp.mark_tx_as_complete = false;
ctp.multisig_id = multisig_id;
ctp.shuffle = shuffle;
ctp.split_strategy_id = split_strategy_id;
ctp.tx_outs_attr = tx_outs_attr;
ctp.unlock_time = unlock_time;
w.prepare_transaction(ctp, ftp, tx);
w.finalize_transaction(ftp, tx, crypto::secret_key(), false);
// sign ms input with all other non-wallet keys
auto it = w.get_multisig_transfers().find(multisig_id);
@ -158,7 +154,7 @@ bool multisig_wallet_test::c1(currency::core& c, size_t ev_index, const std::vec
dst.back().amount = AMOUNT_TO_TRANSFER_MULTISIG + TESTS_DEFAULT_FEE;
dst.back().minimum_sigs = dst.back().addr.size();
transaction result_tx = AUTO_VAL_INIT(result_tx);
miner_wlt->transfer(dst, 0, 0, TESTS_DEFAULT_FEE, extra, attachments, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx);
miner_wlt->transfer(dst, 0, 0, TESTS_DEFAULT_FEE, extra, attachments, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx);
bool r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
@ -204,7 +200,7 @@ bool multisig_wallet_test::c1(currency::core& c, size_t ev_index, const std::vec
TESTS_DEFAULT_FEE,
extra,
attachments,
tools::detail::digit_split_strategy,
tools::detail::ssi_digit,
tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD),
result_tx);
@ -293,7 +289,7 @@ bool multisig_wallet_test_many_dst::c1(currency::core& c, size_t ev_index, const
transaction result_tx = AUTO_VAL_INIT(result_tx);
TMP_LOG_SILENT;
miner_wlt->transfer(std::vector<tx_destination_entry>({ de }), 0, 0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx);
miner_wlt->transfer(std::vector<tx_destination_entry>({ de }), 0, 0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx);
TMP_LOG_RESTORE;
auto it = std::find_if(result_tx.vout.begin(), result_tx.vout.end(), [](tx_out& o) { return o.target.type() == typeid(txout_multisig); });
@ -314,7 +310,7 @@ bool multisig_wallet_test_many_dst::c1(currency::core& c, size_t ev_index, const
tx_destination_entry de2(amount - TESTS_DEFAULT_FEE, m_accounts[ALICE_ACC_IDX].get_public_address());
transaction tx = AUTO_VAL_INIT(tx);
TMP_LOG_SILENT;
transfer_multisig(*w.get(), owner_keys, get_multisig_out_id(result_tx, multisig_index), std::vector<tx_destination_entry>({ de2 }), 0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
transfer_multisig(*w.get(), owner_keys, get_multisig_out_id(result_tx, multisig_index), std::vector<tx_destination_entry>({ de2 }), 0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
TMP_LOG_RESTORE;
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
@ -416,7 +412,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
// Send multisig tx
transaction ms_tx = AUTO_VAL_INIT(ms_tx);
miner_wlt->transfer(std::vector<tx_destination_entry>({ de1, de2, de3, de4, de5, de6 }),
0, 0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), ms_tx);
0, 0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), ms_tx);
// calculate multisig hashes for further usage
crypto::hash ms1_hash = currency::get_multisig_out_id(ms_tx, get_tx_out_index_by_amount(ms_tx, de1.amount));
@ -484,7 +480,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
currency::transaction tx = AUTO_VAL_INIT(tx);
transfer_multisig(*alice_wlt.get(), std::list<account_keys>({ m_accounts[BOB_ACC_IDX].get_keys() }), ms1_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount1, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool");
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
@ -499,7 +495,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
{
// as 'false' means don't send to network. This should fail during preparation, not during sending/processing
transfer_multisig(*bob_wlt.get(), std::list<account_keys>({ m_accounts[ALICE_ACC_IDX].get_keys() }), ms1_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount1, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
}
catch (tools::error::wallet_internal_error&)
{
@ -518,7 +514,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
tx = AUTO_VAL_INIT(tx);
transfer_multisig(*carol_wlt.get(), std::list<account_keys>({ m_accounts[DAN_ACC_IDX].get_keys() }), ms2_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount2, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool");
@ -530,7 +526,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
{
// as 'false' means don't send to network. This should fail during preparation, not during sending/processing
transfer_multisig(*dan_wlt.get(), std::list<account_keys>({ m_accounts[CAROL_ACC_IDX].get_keys() }), ms2_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount2, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
}
catch (tools::error::wallet_internal_error&)
{
@ -546,7 +542,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
// Re-try spending Carol-Dan multisig out on behalf of Dan. It should be OK now
transfer_multisig(*dan_wlt.get(), std::list<account_keys>({ m_accounts[CAROL_ACC_IDX].get_keys() }), ms2_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount2, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool");
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
@ -564,7 +560,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
tx = AUTO_VAL_INIT(tx);
transfer_multisig(*alice_wlt.get(), std::list<account_keys>({ m_accounts[DAN_ACC_IDX].get_keys() }), ms3_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount3, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool");
@ -575,7 +571,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
{
// last 'false' means don't send to network. This should fail during preparation, not during sending/processing
transfer_multisig(*dan_wlt.get(), std::list<account_keys>({ m_accounts[ALICE_ACC_IDX].get_keys() }), ms3_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount3, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
}
catch (tools::error::wallet_internal_error&)
{
@ -605,7 +601,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co
try
{
transfer_multisig(*dan_wlt.get(), std::list<account_keys>({ m_accounts[ALICE_ACC_IDX].get_keys() }), ms3_hash, std::vector<tx_destination_entry>({ tx_destination_entry(amount3, receiver_acc.get_public_address()) }),
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
0, TESTS_DEFAULT_FEE, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, 0, true, false);
}
catch (tools::error::wallet_internal_error&)
{
@ -704,7 +700,7 @@ bool multisig_wallet_same_dst_addr::c1(currency::core& c, size_t ev_index, const
transaction tx = AUTO_VAL_INIT(tx);
transfer_multisig(*alice_wlt.get(), std::list<account_keys>({ m_accounts[ALICE_ACC_IDX].get_keys() }), ms_hash,
std::vector<tx_destination_entry>({ tx_destination_entry(amount, m_accounts[BOB_ACC_IDX].get_public_address()) }),
0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool");
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
@ -798,7 +794,7 @@ bool multisig_wallet_ms_to_ms::c1(currency::core& c, size_t ev_index, const std:
transaction ms_tx2 = AUTO_VAL_INIT(ms_tx2);
transfer_multisig(*alice_wlt.get(), std::list<account_keys>({ m_accounts[BOB_ACC_IDX].get_keys() }), ms_hash,
std::vector<tx_destination_entry>({ de }),
0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), ms_tx2);
0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), ms_tx2);
// check the pool and mine a block
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool");
@ -815,7 +811,7 @@ bool multisig_wallet_ms_to_ms::c1(currency::core& c, size_t ev_index, const std:
transaction tx = AUTO_VAL_INIT(tx);
transfer_multisig(*miner_wlt.get(), std::list<account_keys>({ m_accounts[BOB_ACC_IDX].get_keys() }), ms_hash2,
std::vector<tx_destination_entry>({ tx_destination_entry(amount - TESTS_DEFAULT_FEE, m_accounts[BOB_ACC_IDX].get_public_address()) }),
0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool");
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
@ -2488,7 +2484,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co
dst.back().amount = ms_amount + TESTS_DEFAULT_FEE;
dst.back().minimum_sigs = dst.back().addr.size();
transaction key_to_ms_tx = AUTO_VAL_INIT(key_to_ms_tx);
miner_wlt->transfer(dst, 0, 0, TESTS_DEFAULT_FEE, extra, attachments, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), key_to_ms_tx);
miner_wlt->transfer(dst, 0, 0, TESTS_DEFAULT_FEE, extra, attachments, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), key_to_ms_tx);
bool r = mine_next_pow_blocks_in_playtime(miner_acc.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
@ -2528,7 +2524,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co
TESTS_DEFAULT_FEE,
extra,
attachments,
tools::detail::digit_split_strategy,
tools::detail::ssi_digit,
tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD),
tx);

View file

@ -925,7 +925,7 @@ bool offers_updating_hack::update_foreign_offer(currency::core& c, size_t ev_ind
// make a tx with this attachment (note: tsa.security is signed using Bob's keys, can be resign later using Alice's public address)
transaction tx = AUTO_VAL_INIT(tx);
bob_wlt->transfer(std::vector<tx_destination_entry>({ tx_destination_entry(TESTS_DEFAULT_FEE * 3, m_accounts[BOB_ACC_IDX].get_public_address()) }), 0, 0, TESTS_DEFAULT_FEE * 81, empty_extra, attachments,
tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, true, 0, false);
tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, true, 0, false);
// don't resign yet
@ -999,7 +999,7 @@ bool offers_updating_hack::delete_foreign_offer(currency::core& c, size_t ev_ind
// make a tx with this attachment (note: tsa.security is signed using Bob's keys, can be resign later using Alice's public address)
transaction tx_c = AUTO_VAL_INIT(tx_c);
bob_wlt->transfer(std::vector<tx_destination_entry>({ tx_destination_entry(TESTS_DEFAULT_FEE * 3, m_accounts[BOB_ACC_IDX].get_public_address()) }), 0, 0, TESTS_DEFAULT_FEE * 19, empty_extra, attachments,
tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx_c, 0, true, 0, true);
tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx_c, 0, true, 0, true);
LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true));

View file

@ -3082,7 +3082,7 @@ bool wallet_unconfirmed_tx_expiration::c1(currency::core& c, size_t ev_index, co
transaction tx = AUTO_VAL_INIT(tx);
try
{
alice_wlt->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, extra, empty_attachment, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
alice_wlt->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, extra, empty_attachment, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
}
catch (std::exception &e)
{

View file

@ -71,7 +71,7 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
try
{
uint64_t ticks = epee::misc_utils::get_tick_count();
w1.transfer(dsts, mix_in_factor, 0, w1.get_core_runtime_config().tx_default_fee, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::null_split_strategy, tools::tx_dust_policy(w1.get_core_runtime_config().tx_default_fee), tx);
w1.transfer(dsts, mix_in_factor, 0, w1.get_core_runtime_config().tx_default_fee, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(w1.get_core_runtime_config().tx_default_fee), tx);
uint64_t ticks_for_tx = epee::misc_utils::get_tick_count() - ticks;
LOG_PRINT_GREEN("Send tx took " << ticks_for_tx << "ms", LOG_LEVEL_0);
return true;
@ -179,7 +179,7 @@ bool do_send_money_by_fractions(tools::wallet2& w1, tools::wallet2& w2, size_t m
try
{
w1.transfer(dsts, mix_in_factor, 0, w1.get_core_runtime_config().tx_default_fee, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::null_split_strategy, tools::tx_dust_policy(w1.get_core_runtime_config().tx_default_fee), tx);
w1.transfer(dsts, mix_in_factor, 0, w1.get_core_runtime_config().tx_default_fee, std::vector<currency::extra_v>(), std::vector<currency::attachment_v>(), tools::detail::ssi_digit, tools::tx_dust_policy(w1.get_core_runtime_config().tx_default_fee), tx);
LOG_PRINT_GREEN("Split transaction sent " << get_transaction_hash(tx) << ", destinations: " << dsts.size() << ", blob size: " << get_object_blobsize(tx), LOG_LEVEL_0);
return true;
}

View file

@ -2,11 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "gtest/gtest.h"
#include "crypto/crypto.h"
#include "currency_core/currency_basic.h"
#include "profile_tools.h"
@ -48,4 +44,3 @@ using namespace currency;
// bool res = test_scratchpad_against_light_scratchpad();
// ASSERT_TRUE(res);
// }