forked from lthn/blockchain
Merge branch 'offsig'
This commit is contained in:
commit
2d3ef5e41f
37 changed files with 1813 additions and 1065 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) << "}";
|
||||
|
|
|
|||
|
|
@ -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 = '?')
|
||||
|
|
|
|||
|
|
@ -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()) */
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#include "zlib.h"
|
||||
#include "../zlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef STDC
|
||||
|
|
|
|||
|
|
@ -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" };
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
127
src/common/pod_array_file_container.h
Normal file
127
src/common/pod_array_file_container.h
Normal 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
|
||||
|
|
@ -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 "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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*/)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()); \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
// }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue