forked from lthn/blockchain
wallet: watch-only & cold-signing
This commit is contained in:
parent
b08905c1cc
commit
25e9cfc537
10 changed files with 152 additions and 401 deletions
|
|
@ -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*/)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ simple_wallet::simple_wallet()
|
|||
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 a watch-only keys file <filename> <password>.");
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -1280,6 +1281,31 @@ void simple_wallet::set_offline_mode(bool 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(epee::string_encoding::convert_to_unicode(args[0]), args[1], true);
|
||||
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;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#ifdef WIN32
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ namespace currency
|
|||
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 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);
|
||||
|
|
|
|||
|
|
@ -272,29 +272,52 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
for (size_t i_in_outs = 0; i_in_outs != outs.size(); i_in_outs++)
|
||||
{
|
||||
size_t o = outs[i_in_outs];
|
||||
THROW_IF_TRUE_WALLET_EX(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" +
|
||||
std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size()));
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(o < tx.vout.size(), "wrong out in transaction: internal index=" << o << ", total_outs=" << tx.vout.size());
|
||||
if (tx.vout[o].target.type() == typeid(txout_to_key))
|
||||
{
|
||||
currency::keypair in_ephemeral;
|
||||
const currency::txout_to_key& otk = boost::get<currency::txout_to_key>(tx.vout[o].target);
|
||||
|
||||
// obtain key image for this output
|
||||
crypto::key_image ki = currency::null_ki;
|
||||
currency::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, ki);
|
||||
THROW_IF_TRUE_WALLET_EX(in_ephemeral.pub != boost::get<currency::txout_to_key>(tx.vout[o].target).key,
|
||||
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
|
||||
|
||||
auto it = m_key_images.find(ki);
|
||||
if (it != m_key_images.end())
|
||||
if (m_watch_only)
|
||||
{
|
||||
THROW_IF_TRUE_WALLET_EX(it->second >= m_transfers.size(), error::wallet_internal_error, "m_key_images entry has wrong m_transfers index, it->second: " + epee::string_tools::num_to_string_fast(it->second) + ", m_transfers.size(): " + epee::string_tools::num_to_string_fast(m_transfers.size()));
|
||||
const transfer_details& local_td = m_transfers[it->second];
|
||||
WLT_LOG_YELLOW("tx " << get_transaction_hash(tx) << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" <<
|
||||
local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height <<
|
||||
". This output can't ever be spent and will be skipped.", LOG_LEVEL_0);
|
||||
THROW_IF_TRUE_WALLET_EX(tx_money_got_in_outs < tx.vout[o].amount, error::wallet_internal_error, "tx_money_got_in_outs: " + epee::string_tools::num_to_string_fast(tx_money_got_in_outs) + ", tx.vout[o].amount:" + print_money(tx.vout[o].amount));
|
||||
tx_money_got_in_outs -= tx.vout[o].amount;
|
||||
continue; // skip the output
|
||||
// don't have spend secret key, so we unable to calculate key image for an output
|
||||
// look it up in special container instead
|
||||
auto it = m_pending_key_images.find(otk.key);
|
||||
if (it != m_pending_key_images.end())
|
||||
{
|
||||
ki = it->second;
|
||||
WLT_LOG_L1("pending key image " << ki << " was found by out pub key " << otk.key);
|
||||
}
|
||||
else
|
||||
{
|
||||
ki = currency::null_ki;
|
||||
WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal wallet, calculate and store key images for own outs
|
||||
currency::keypair in_ephemeral;
|
||||
currency::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, ki);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(in_ephemeral.pub == otk.key, "key_image generated ephemeral public key that does not match with output_key");
|
||||
}
|
||||
|
||||
if (ki != currency::null_ki)
|
||||
{
|
||||
auto it = m_key_images.find(ki);
|
||||
if (it != m_key_images.end())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "m_key_images entry has wrong m_transfers index, it->second: " << it->second << ", m_transfers.size(): " << m_transfers.size());
|
||||
const transfer_details& local_td = m_transfers[it->second];
|
||||
WLT_LOG_YELLOW("tx " << get_transaction_hash(tx) << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" <<
|
||||
local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height <<
|
||||
". This output can't ever be spent and will be skipped.", LOG_LEVEL_0);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tx_money_got_in_outs >= tx.vout[o].amount, "tx_money_got_in_outs: " << tx_money_got_in_outs << ", tx.vout[o].amount:" << tx.vout[o].amount);
|
||||
tx_money_got_in_outs -= tx.vout[o].amount;
|
||||
continue; // skip the output
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mtd.receive_indices.push_back(o);
|
||||
|
||||
|
|
@ -314,7 +337,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
}
|
||||
}
|
||||
size_t transfer_index = m_transfers.size()-1;
|
||||
m_key_images[td.m_key_image] = transfer_index;
|
||||
if (td.m_key_image != currency::null_ki)
|
||||
m_key_images[td.m_key_image] = transfer_index;
|
||||
add_transfer_to_transfers_cache(tx.vout[o].amount, transfer_index);
|
||||
WLT_LOG_L0("Received money, transfer #" << transfer_index << ", amount: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height);
|
||||
}
|
||||
|
|
@ -1686,6 +1710,7 @@ bool wallet2::reset_all()
|
|||
m_blockchain.clear();
|
||||
m_transfers.clear();
|
||||
m_key_images.clear();
|
||||
// m_pending_key_images is not cleared intentionally
|
||||
m_unconfirmed_in_transfers.clear();
|
||||
m_unconfirmed_txs.clear();
|
||||
m_unconfirmed_multisig_transfers.clear();
|
||||
|
|
@ -1702,11 +1727,16 @@ bool wallet2::reset_all()
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::store_keys(std::string& buff, const std::string& password)
|
||||
bool wallet2::store_keys(std::string& buff, const std::string& password, bool store_as_watch_only /* = false */)
|
||||
{
|
||||
currency::account_base acc = m_account;
|
||||
if (store_as_watch_only)
|
||||
acc.make_account_watch_only();
|
||||
|
||||
std::string account_data;
|
||||
bool r = epee::serialization::store_t_to_binary(m_account, account_data);
|
||||
bool r = epee::serialization::store_t_to_binary(acc, account_data);
|
||||
WLT_CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet keys");
|
||||
|
||||
wallet2::keys_file_data keys_file_data = boost::value_initialized<wallet2::keys_file_data>();
|
||||
|
||||
crypto::chacha8_key key;
|
||||
|
|
@ -1857,8 +1887,11 @@ void wallet2::generate(const std::wstring& path, const std::string& pass)
|
|||
init_log_prefix();
|
||||
boost::system::error_code ignored_ec;
|
||||
THROW_IF_TRUE_WALLET_EX(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
bool stub;
|
||||
load_keys2ki(true, stub);
|
||||
if (m_watch_only)
|
||||
{
|
||||
bool stub;
|
||||
load_keys2ki(true, stub);
|
||||
}
|
||||
store();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -1930,25 +1963,22 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password)
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::store()
|
||||
{
|
||||
store(m_wallet_file);
|
||||
store(m_wallet_file, m_password, false);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::store(const std::wstring& path_to_save)
|
||||
void wallet2::store(const std::wstring& path_to_save, const std::string& password, bool store_as_watch_only)
|
||||
{
|
||||
LOG_PRINT_L0("(before storing: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")");
|
||||
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!(store_as_watch_only && path_to_save == m_wallet_file), "ttrying to save watch-only wallet to the same wallet file!");
|
||||
|
||||
//prepare data
|
||||
std::string keys_buff;
|
||||
bool r = store_keys(keys_buff, m_password);
|
||||
bool r = store_keys(keys_buff, password);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "failed to store_keys for wallet " << epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh);
|
||||
|
||||
// std::stringstream ss;
|
||||
// r = tools::portble_serialize_obj_to_stream(*this, ss);
|
||||
// CHECK_AND_ASSERT_THROW_MES(r, "failed to portble_serialize_obj_to_stream for wallet " << epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
// std::string body_buff = ss.str();
|
||||
|
||||
//store data
|
||||
|
||||
wbh.m_signature = WALLET_FILE_SIGNATURE;
|
||||
|
|
@ -1965,8 +1995,18 @@ void wallet2::store(const std::wstring& path_to_save)
|
|||
CHECK_AND_ASSERT_THROW_MES(!data_file.fail(), "failed to open binary wallet file for saving: " << epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
data_file << header_buff << keys_buff;
|
||||
WLT_LOG_L0("Storing to file...");
|
||||
r = tools::portble_serialize_obj_to_stream(*this, data_file);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "failed to portble_serialize_obj_to_stream for wallet " << epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
if (store_as_watch_only)
|
||||
{
|
||||
// TODO
|
||||
r = tools::portble_serialize_obj_to_stream(*this, data_file);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "failed to portble_serialize_obj_to_stream for wallet " << epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
}
|
||||
else
|
||||
{
|
||||
r = tools::portble_serialize_obj_to_stream(*this, data_file);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "failed to portble_serialize_obj_to_stream for wallet " << epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
}
|
||||
|
||||
data_file.flush();
|
||||
data_file.close();
|
||||
|
|
@ -2173,8 +2213,6 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
|
|||
|
||||
crypto::hash tx_hash = get_transaction_hash(ft.tx);
|
||||
|
||||
// foolproof check to make sure create_tx_param and create_tx_result DO match each other
|
||||
|
||||
try
|
||||
{
|
||||
send_transaction_to_network(ft.tx);
|
||||
|
|
@ -2182,12 +2220,12 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
|
|||
catch (...)
|
||||
{
|
||||
// clear spent transfers if smth went wrong
|
||||
clear_transfers_from_flag(ft.ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, "broadcasting tx " + epee::string_tools::pod_to_hex(get_transaction_hash(ft.tx)) + " was unsuccessful");
|
||||
clear_transfers_from_flag(ft.ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, "broadcasting tx " + epee::string_tools::pod_to_hex(tx_hash) + " was unsuccessful");
|
||||
throw;
|
||||
}
|
||||
|
||||
add_sent_tx_detailed_info(ft.tx, ft.ftp.prepared_destinations, ft.ftp.selected_transfers);
|
||||
m_tx_keys.insert(std::make_pair(get_transaction_hash(ft.tx), ft.one_time_key));
|
||||
m_tx_keys.insert(std::make_pair(tx_hash, ft.one_time_key));
|
||||
|
||||
if (m_watch_only)
|
||||
{
|
||||
|
|
@ -2237,9 +2275,9 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
|
|||
{
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(p.first < m_transfers.size(), "incorrect transfer index: " << p.first);
|
||||
auto& tr = m_transfers[p.first];
|
||||
if (tr.m_key_image != currency::null_ki)
|
||||
if (tr.m_key_image != currency::null_ki && tr.m_key_image != p.second)
|
||||
{
|
||||
LOG_PRINT_YELLOW("transfer #" << p.first << " has not null key image: " << tr.m_key_image << " will be replaced with ki " << p.second, LOG_LEVEL_0);
|
||||
LOG_PRINT_YELLOW("transfer #" << p.first << " already has not null key image " << tr.m_key_image << " and it will be replaced with ki " << p.second, LOG_LEVEL_0);
|
||||
}
|
||||
tr.m_key_image = p.second;
|
||||
m_key_images[p.second] = p.first;
|
||||
|
|
@ -2247,8 +2285,8 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
|
|||
}
|
||||
}
|
||||
|
||||
// print inputs' key images
|
||||
// print tx was sent
|
||||
// TODO: print inputs' key images
|
||||
print_tx_sent_message(ft.tx, "(from submit_transfer)");
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::submit_transfer_files(const std::string& signed_tx_file, currency::transaction& tx)
|
||||
|
|
@ -3332,6 +3370,7 @@ void wallet2::exception_handler()
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::mark_transfers_as_spent(const std::vector<uint64_t>& selected_transfers, const std::string& reason /* = empty_string */)
|
||||
{
|
||||
// TODO: design a safe undo for this operation
|
||||
mark_transfers_with_flag(selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, reason);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -3667,13 +3706,17 @@ void wallet2::set_genesis(const crypto::hash& genesis_hash)
|
|||
m_blockchain[0] = genesis_hash;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::print_tx_sent_message(const currency::transaction& tx, const std::string& description, uint64_t fee)
|
||||
void wallet2::print_tx_sent_message(const currency::transaction& tx, const std::string& description, uint64_t fee /* = UINT64_MAX */)
|
||||
{
|
||||
//uint64_t balance_unlocked = 0;
|
||||
//uint64_t balance_total = balance(balance_unlocked);
|
||||
|
||||
std::stringstream ss;
|
||||
if (fee != UINT64_MAX)
|
||||
ss << "Commission: " << std::setw(21) << std::right << print_money(fee) << ENDL;
|
||||
|
||||
WLT_LOG_CYAN("Transaction " << get_transaction_hash(tx) << " was successfully sent " << description << ENDL
|
||||
<< "Commission: " << std::setw(21) << std::right << print_money(fee) << ENDL
|
||||
<< ss.str()
|
||||
// << "Balance: " << std::setw(21) << print_money(balance_total) << ENDL
|
||||
// << "Unlocked: " << std::setw(21) << print_money(balance_unlocked) << ENDL
|
||||
<< "Please, wait for confirmation for your balance to be unlocked.",
|
||||
|
|
@ -3746,28 +3789,6 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money,
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
/*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,
|
||||
tools::detail::split_strategy_id_t destination_split_strategy_id,
|
||||
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)
|
||||
{
|
||||
// TODO
|
||||
}*/
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::prepare_transaction(const construct_tx_param& ctp, finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate /* = currency::transaction() */)
|
||||
{
|
||||
TIME_MEASURE_START_MS(get_needed_money_time);
|
||||
|
|
@ -3905,12 +3926,10 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
|
|||
uint8_t tx_outs_attr,
|
||||
bool shuffle,
|
||||
uint8_t flags,
|
||||
bool send_to_network)
|
||||
bool send_to_network,
|
||||
std::string* p_signed_tx_blob_str)
|
||||
{
|
||||
TIME_MEASURE_START(precalculation_time);
|
||||
//using namespace currency;
|
||||
currency::keypair onetime_keys = AUTO_VAL_INIT(onetime_keys);
|
||||
|
||||
construct_tx_param tx_param = AUTO_VAL_INIT(tx_param);
|
||||
tx_param.attachments = attachments;
|
||||
tx_param.crypt_address = currency::get_crypt_address_from_destinations(m_account.get_keys(), dsts);
|
||||
|
|
@ -3933,7 +3952,6 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
|
|||
prepare_transaction(tx_param, ftp);
|
||||
TIME_MEASURE_FINISH(prepare_transaction_time);
|
||||
|
||||
|
||||
if (m_watch_only)
|
||||
{
|
||||
tx_param.spend_pub_key = m_account.get_public_address().m_spend_public_key;
|
||||
|
|
@ -3941,7 +3959,9 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
|
|||
crypto::chacha_crypt(bl, m_account.get_keys().m_view_secret_key);
|
||||
epee::file_io_utils::save_string_to_file("unsigned_zano_tx", bl);
|
||||
LOG_PRINT_L0("Transaction stored to unsigned_zano_tx. You need to sign this tx using a full-access wallet.");
|
||||
//relay_blob = bl; // TODO: save encrypted tx param blob to relay_blob
|
||||
|
||||
if (p_signed_tx_blob_str != nullptr)
|
||||
*p_signed_tx_blob_str = bl;
|
||||
|
||||
// unlock transfers at the very end
|
||||
TIME_MEASURE_START(mark_transfers_as_spent_time);
|
||||
|
|
|
|||
|
|
@ -297,6 +297,8 @@ namespace tools
|
|||
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)
|
||||
|
|
@ -309,6 +311,7 @@ namespace tools
|
|||
FIELD(sources)
|
||||
FIELD(selected_transfers)
|
||||
FIELD(prepared_destinations)
|
||||
FIELD(spend_pub_key)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
|
@ -468,7 +471,8 @@ namespace tools
|
|||
void restore(const std::wstring& path, const std::string& pass, const std::string& restore_key);
|
||||
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, bool store_as_watch_only = false);
|
||||
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; }
|
||||
|
|
@ -534,7 +538,8 @@ namespace tools
|
|||
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,
|
||||
|
|
@ -698,25 +703,6 @@ namespace tools
|
|||
const std::list<expiration_entry_info>& get_expiration_entries() const { return m_money_expirations; };
|
||||
bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const;
|
||||
|
||||
/*void prepare_transaction(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,
|
||||
detail::split_strategy_id_t destination_split_strategy_id,
|
||||
const tx_dust_policy& dust_policy,
|
||||
const currency::account_public_address& crypt_address,
|
||||
OUT currency::transaction &tx,
|
||||
uint8_t tx_outs_attr,
|
||||
bool shuffle,
|
||||
bool mark_tx_as_complete,
|
||||
uint8_t flags,
|
||||
OUT std::vector<uint64_t>& selected_transfers,
|
||||
OUT currency::keypair& one_time_key,
|
||||
OUT 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);
|
||||
|
||||
|
|
@ -725,7 +711,6 @@ namespace tools
|
|||
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);
|
||||
|
|
@ -797,7 +782,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,
|
||||
|
|
|
|||
|
|
@ -676,6 +676,7 @@ 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)
|
||||
|
||||
|
|
|
|||
|
|
@ -158,8 +158,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)
|
||||
|
|
@ -337,14 +346,6 @@ namespace tools
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
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_unsigned_blob;
|
||||
//if (!string_tools::parse_hexstr_to_binbuff(req.tx_unsigned_hex, tx_unsigned_blob))
|
||||
//{
|
||||
// er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
|
||||
// er.message = "tx_unsigned_hex is invalid";
|
||||
// return false;
|
||||
//}
|
||||
|
||||
std::string tx_signed_blob;
|
||||
if (!string_tools::parse_hexstr_to_binbuff(req.tx_signed_hex, tx_signed_blob))
|
||||
{
|
||||
|
|
@ -356,7 +357,7 @@ namespace tools
|
|||
try
|
||||
{
|
||||
currency::transaction tx = AUTO_VAL_INIT(tx);
|
||||
// TODO m_wallet.submit_transfer(tx_unsigned_blob, tx_signed_blob, 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)
|
||||
|
|
@ -371,290 +372,9 @@ namespace tools
|
|||
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
{
|
||||
//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))
|
||||
{
|
||||
//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;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
|
||||
//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)
|
||||
{
|
||||
LOG_ERROR("Problem with construct_tx(....) ");
|
||||
status = "INTERNAL_ERROR";
|
||||
return false;
|
||||
}
|
||||
if (CURRENCY_MAX_TRANSACTION_BLOB_SIZE <= get_object_blobsize(tx2))
|
||||
{
|
||||
LOG_ERROR("Problem with construct_tx(....), blobl size os too big: " << get_object_blobsize(tx2));
|
||||
status = "INTERNAL_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
|
||||
|
|
|
|||
|
|
@ -48,12 +48,6 @@ namespace tools
|
|||
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)
|
||||
|
||||
// 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)
|
||||
END_JSON_RPC_MAP()
|
||||
END_URI_MAP2()
|
||||
|
||||
|
|
@ -69,13 +63,7 @@ namespace tools
|
|||
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 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 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;
|
||||
|
|
@ -83,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()
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue