mirror of https://github.com/monero-project/monero
Light wallet subaddress support
This commit is contained in:
parent
efb20d1b1e
commit
f2a51ebc43
|
@ -1597,6 +1597,8 @@ bool wallet2::should_expand(const cryptonote::subaddress_index &index) const
|
|||
void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
|
||||
{
|
||||
hw::device &hwdev = m_account.get_device();
|
||||
std::vector<cryptonote::subaddress_index> subaddrs;
|
||||
|
||||
if (m_subaddress_labels.size() <= index.major)
|
||||
{
|
||||
// add new accounts
|
||||
|
@ -1614,6 +1616,7 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
|
|||
}
|
||||
m_subaddress_labels.resize(index.major + 1, {"Untitled account"});
|
||||
m_subaddress_labels[index.major].resize(index.minor + 1);
|
||||
subaddrs.push_back(index2);
|
||||
get_account_tags();
|
||||
}
|
||||
else if (m_subaddress_labels[index.major].size() <= index.minor)
|
||||
|
@ -1629,6 +1632,13 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
|
|||
m_subaddresses[D] = index2;
|
||||
}
|
||||
m_subaddress_labels[index.major].resize(index.minor + 1);
|
||||
subaddrs.push_back(index2);
|
||||
}
|
||||
|
||||
if (m_light_wallet && !subaddrs.empty()) {
|
||||
if(light_wallet_upsert_subaddrs(subaddrs)) {
|
||||
MINFO("Successfully upsert light wallet subaddresses");
|
||||
} else throw std::runtime_error("Error while upserting light wallet subaddresses");
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -6533,9 +6543,6 @@ boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data()
|
|||
uint64_t wallet2::balance(uint32_t index_major, bool strict) const
|
||||
{
|
||||
uint64_t amount = 0;
|
||||
if(m_light_wallet)
|
||||
if(index_major == 0) return m_light_wallet_balance;
|
||||
else return 0;
|
||||
for (const auto& i : balance_per_subaddress(index_major, strict))
|
||||
amount += i.second;
|
||||
return amount;
|
||||
|
@ -10214,7 +10221,9 @@ void wallet2::light_wallet_get_unspent_outs()
|
|||
string_tools::hex_to_pod(o.tx_pub_key, tx_pub_key);
|
||||
|
||||
for(auto &t: m_transfers){
|
||||
// everoddandeven: m_transfers should e empty, before of previous call of m_transfer.clear()
|
||||
if(t.get_public_key() == public_key) {
|
||||
// update spent status
|
||||
t.m_spent = spent;
|
||||
add_transfer = false;
|
||||
break;
|
||||
|
@ -10243,6 +10252,8 @@ void wallet2::light_wallet_get_unspent_outs()
|
|||
td.m_internal_output_index = o.index;
|
||||
td.m_spent = spent;
|
||||
td.m_frozen = false;
|
||||
td.m_subaddr_index.major = o.recipient.maj_i;
|
||||
td.m_subaddr_index.minor = o.recipient.min_i;
|
||||
|
||||
tx_out txout;
|
||||
txout.target = txout_to_key(public_key);
|
||||
|
@ -10388,6 +10399,7 @@ void wallet2::light_wallet_get_address_txs()
|
|||
address_tx.m_timestamp = t.timestamp;
|
||||
address_tx.m_coinbase = t.coinbase;
|
||||
address_tx.m_mempool = t.mempool;
|
||||
|
||||
m_light_wallet_address_txs.emplace(tx_hash,address_tx);
|
||||
|
||||
// populate data needed for history (m_payments, m_unconfirmed_payments, m_confirmed_txs)
|
||||
|
@ -10571,9 +10583,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image,
|
|||
return key_image == calculated_key_image;
|
||||
}
|
||||
|
||||
std::vector<bool> wallet2::light_wallet_is_key_image_spent(const std::vector<crypto::key_image>& key_images) {
|
||||
MDEBUG("Getting unspent outs");
|
||||
|
||||
std::vector<bool> wallet2::light_wallet_is_key_image_spent(const std::vector<crypto::key_image>& key_images) {
|
||||
tools::COMMAND_RPC_GET_UNSPENT_OUTS::request oreq;
|
||||
tools::COMMAND_RPC_GET_UNSPENT_OUTS::response ores;
|
||||
oreq.amount = "0";
|
||||
|
@ -10592,7 +10602,7 @@ std::vector<bool> wallet2::light_wallet_is_key_image_spent(const std::vector<cry
|
|||
THROW_WALLET_EXCEPTION_IF(ores.status == "error", error::wallet_internal_error, ores.reason);
|
||||
|
||||
m_light_wallet_per_kb_fee = ores.per_kb_fee;
|
||||
MDEBUG("FOUND " << ores.outputs.size() <<" outputs");
|
||||
|
||||
std:vector<bool> spent_list;
|
||||
|
||||
for(crypto::key_image key_image : key_images) {
|
||||
|
@ -10612,6 +10622,119 @@ std::vector<bool> wallet2::light_wallet_is_key_image_spent(const std::vector<cry
|
|||
return spent_list;
|
||||
}
|
||||
|
||||
void wallet2::light_wallet_get_subaddrs() {
|
||||
MINFO("Getting light wallet subaddresses");
|
||||
|
||||
tools::COMMAND_RPC_GET_SUBADDRS::request oreq;
|
||||
tools::COMMAND_RPC_GET_SUBADDRS::response ores;
|
||||
|
||||
oreq.address = get_account().get_public_address_str(m_nettype);
|
||||
oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
|
||||
|
||||
m_daemon_rpc_mutex.lock();
|
||||
bool r = invoke_http_json("/get_subaddrs", oreq, ores, rpc_timeout, "POST");
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_subaddrs");
|
||||
|
||||
m_light_wallet_subaddrs.clear();
|
||||
m_light_wallet_accounts.clear();
|
||||
|
||||
for(auto subaddr : ores.all_subaddrs) {
|
||||
for(auto index_range : subaddr.value) {
|
||||
THROW_WALLET_EXCEPTION_IF(index_range.size() != 2, error::wallet_internal_error, "Invalid index range size");
|
||||
|
||||
uint32_t minor = index_range[0];
|
||||
uint32_t major = index_range[1];
|
||||
|
||||
for(;minor <= major; minor++) {
|
||||
m_light_wallet_subaddrs.push_back({subaddr.key,minor});
|
||||
}
|
||||
}
|
||||
|
||||
m_light_wallet_accounts.push_back(subaddr.key);
|
||||
}
|
||||
|
||||
MINFO("GOT " << m_light_wallet_accounts.size() << " ACCOUNTS AND " << m_light_wallet_subaddrs.size() << " SUBADDRESSES");
|
||||
}
|
||||
|
||||
bool wallet2::light_wallet_upsert_subaddrs(std::vector<cryptonote::subaddress_index> subaddrs) {
|
||||
tools::COMMAND_RPC_UPSERT_SUBADDRS::request oreq;
|
||||
tools::COMMAND_RPC_UPSERT_SUBADDRS::response ores;
|
||||
std::vector<tools::COMMAND_RPC_UPSERT_SUBADDRS::subaddrs> all_subaddrs;
|
||||
oreq.address = get_account().get_public_address_str(m_nettype);
|
||||
oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
|
||||
oreq.get_all = true;
|
||||
|
||||
for (cryptonote::subaddress_index subaddr : subaddrs) {
|
||||
oreq.subaddrs.key = subaddr.major;
|
||||
std::vector<uint32_t> index_range;
|
||||
index_range.push_back(0);
|
||||
index_range.push_back(subaddr.minor);
|
||||
oreq.subaddrs.value.push_back(index_range);
|
||||
|
||||
m_daemon_rpc_mutex.lock();
|
||||
bool r = invoke_http_json("/upsert_subaddrs", oreq, ores, rpc_timeout, "POST");
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "upsert_subaddrs");
|
||||
|
||||
all_subaddrs = ores.all_subaddrs;
|
||||
}
|
||||
|
||||
m_light_wallet_subaddrs.clear();
|
||||
m_light_wallet_accounts.clear();
|
||||
|
||||
for(auto subaddr : ores.all_subaddrs) {
|
||||
for(auto index_range : subaddr.value) {
|
||||
THROW_WALLET_EXCEPTION_IF(index_range.size() != 2, error::wallet_internal_error, "Invalid index range size");
|
||||
|
||||
uint32_t minor = index_range[0];
|
||||
uint32_t major = index_range[1];
|
||||
|
||||
for(;minor <= major; minor++) {
|
||||
m_light_wallet_subaddrs.push_back({subaddr.key,minor});
|
||||
}
|
||||
}
|
||||
|
||||
m_light_wallet_accounts.push_back(subaddr.key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wallet2::light_wallet_provision_subaddrs(uint32_t maj_i, uint32_t min_i, uint32_t n_maj, uint32_t n_min) {
|
||||
tools::COMMAND_RPC_PROVISION_SUBADDRS::request oreq;
|
||||
tools::COMMAND_RPC_PROVISION_SUBADDRS::response ores;
|
||||
std::vector<tools::COMMAND_RPC_PROVISION_SUBADDRS::subaddrs> all_subaddrs;
|
||||
oreq.address = get_account().get_public_address_str(m_nettype);
|
||||
oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
|
||||
oreq.get_all = true;
|
||||
|
||||
m_daemon_rpc_mutex.lock();
|
||||
bool r = invoke_http_json("/provision_subaddrs", oreq, ores, rpc_timeout, "POST");
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "provision_subaddrs");
|
||||
|
||||
m_light_wallet_subaddrs.clear();
|
||||
m_light_wallet_accounts.clear();
|
||||
|
||||
for(auto subaddr : ores.all_subaddrs) {
|
||||
for(auto index_range : subaddr.value) {
|
||||
THROW_WALLET_EXCEPTION_IF(index_range.size() != 2, error::wallet_internal_error, "Invalid index range size");
|
||||
|
||||
uint32_t minor = index_range[0];
|
||||
uint32_t major = index_range[1];
|
||||
|
||||
for(;minor <= major; minor++) {
|
||||
m_light_wallet_subaddrs.push_back({subaddr.key,minor});
|
||||
}
|
||||
}
|
||||
|
||||
m_light_wallet_accounts.push_back(subaddr.key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Another implementation of transaction creation that is hopefully better
|
||||
// While there is anything left to pay, it goes through random outputs and tries
|
||||
// to fill the next destination/amount. If it fully fills it, it will use the
|
||||
|
|
|
@ -1634,7 +1634,12 @@ private:
|
|||
}
|
||||
|
||||
std::vector<bool> light_wallet_is_key_image_spent(const std::vector<crypto::key_image>& key_images);
|
||||
|
||||
std::vector<cryptonote::subaddress_index> m_light_wallet_subaddrs;
|
||||
std::vector<uint32_t> m_light_wallet_accounts;
|
||||
bool light_wallet_supports_subaddrs();
|
||||
void light_wallet_get_subaddrs();
|
||||
bool light_wallet_provision_subaddrs(uint32_t maj_i, uint32_t min_i, uint32_t n_maj, uint32_t n_min);
|
||||
bool light_wallet_upsert_subaddrs(std::vector<cryptonote::subaddress_index> subaddrs);
|
||||
/*
|
||||
* "attributes" are a mechanism to store an arbitrary number of string values
|
||||
* on the level of the wallet as a whole, identified by keys. Their introduction,
|
||||
|
|
|
@ -49,13 +49,28 @@ namespace tools
|
|||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
struct address_meta {
|
||||
uint32_t maj_i;
|
||||
uint32_t min_i;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(maj_i)
|
||||
FIELD(min_i)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(maj_i)
|
||||
KV_SERIALIZE(min_i)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct spent_output {
|
||||
uint64_t amount;
|
||||
std::string key_image;
|
||||
std::string tx_pub_key;
|
||||
uint64_t out_index;
|
||||
uint32_t mixin;
|
||||
|
||||
address_meta sender;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
|
@ -63,6 +78,7 @@ namespace tools
|
|||
KV_SERIALIZE(tx_pub_key)
|
||||
KV_SERIALIZE(out_index)
|
||||
KV_SERIALIZE(mixin)
|
||||
KV_SERIALIZE_OPT(sender, (address_meta)({0, 0}))
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
@ -136,6 +152,21 @@ namespace tools
|
|||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
struct address_meta {
|
||||
uint32_t maj_i;
|
||||
uint32_t min_i;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(maj_i)
|
||||
FIELD(min_i)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(maj_i)
|
||||
KV_SERIALIZE(min_i)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct spent_output
|
||||
{
|
||||
uint64_t amount;
|
||||
|
@ -143,13 +174,15 @@ namespace tools
|
|||
std::string tx_pub_key;
|
||||
uint64_t out_index;
|
||||
uint32_t mixin;
|
||||
|
||||
address_meta sender;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
KV_SERIALIZE(key_image)
|
||||
KV_SERIALIZE(tx_pub_key)
|
||||
KV_SERIALIZE(out_index)
|
||||
KV_SERIALIZE(mixin)
|
||||
KV_SERIALIZE_OPT(sender, (address_meta)({0, 0}))
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
@ -178,7 +211,6 @@ namespace tools
|
|||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_GET_UNSPENT_OUTS
|
||||
{
|
||||
|
@ -202,7 +234,21 @@ namespace tools
|
|||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
|
||||
struct address_meta {
|
||||
uint32_t maj_i;
|
||||
uint32_t min_i;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(maj_i)
|
||||
FIELD(min_i)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(maj_i)
|
||||
KV_SERIALIZE(min_i)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct output {
|
||||
uint64_t amount;
|
||||
|
@ -215,8 +261,8 @@ namespace tools
|
|||
std::string tx_prefix_hash;
|
||||
std::vector<std::string> spend_key_images;
|
||||
uint64_t timestamp;
|
||||
uint64_t height;
|
||||
|
||||
uint64_t height;
|
||||
address_meta recipient;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
|
@ -229,7 +275,8 @@ namespace tools
|
|||
KV_SERIALIZE(tx_prefix_hash)
|
||||
KV_SERIALIZE(spend_key_images)
|
||||
KV_SERIALIZE(timestamp)
|
||||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE_OPT(recipient, (address_meta)({0, 0}))
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
@ -364,4 +411,133 @@ namespace tools
|
|||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_PROVISION_SUBADDRS
|
||||
{
|
||||
typedef std::vector<uint32_t> index_range;
|
||||
|
||||
struct subaddrs {
|
||||
uint32_t key;
|
||||
std::vector<index_range> value;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(key)
|
||||
KV_SERIALIZE(value)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct request_t
|
||||
{
|
||||
std::string address;
|
||||
std::string view_key;
|
||||
uint32_t maj_i;
|
||||
uint32_t min_i;
|
||||
uint32_t n_maj;
|
||||
uint32_t n_min;
|
||||
bool get_all;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(view_key)
|
||||
KV_SERIALIZE(maj_i)
|
||||
KV_SERIALIZE(min_i)
|
||||
KV_SERIALIZE(n_maj)
|
||||
KV_SERIALIZE(n_min)
|
||||
KV_SERIALIZE(get_all)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
struct response_t
|
||||
{
|
||||
std::vector<subaddrs> new_subaddrs;
|
||||
std::vector<subaddrs> all_subaddrs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(new_subaddrs)
|
||||
KV_SERIALIZE(all_subaddrs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_UPSERT_SUBADDRS
|
||||
{
|
||||
typedef std::vector<uint32_t> index_range;
|
||||
|
||||
struct subaddrs {
|
||||
uint32_t key;
|
||||
std::vector<index_range> value;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(key)
|
||||
KV_SERIALIZE(value)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct request_t
|
||||
{
|
||||
std::string address;
|
||||
std::string view_key;
|
||||
subaddrs subaddrs;
|
||||
bool get_all;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(view_key)
|
||||
KV_SERIALIZE(subaddrs)
|
||||
KV_SERIALIZE(get_all)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
struct response_t
|
||||
{
|
||||
std::vector<subaddrs> new_subaddrs;
|
||||
std::vector<subaddrs> all_subaddrs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(new_subaddrs)
|
||||
KV_SERIALIZE(all_subaddrs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_GET_SUBADDRS
|
||||
{
|
||||
struct request_t
|
||||
{
|
||||
std::string address;
|
||||
std::string view_key;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(view_key)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
typedef std::vector<uint32_t> index_range;
|
||||
|
||||
struct subaddrs {
|
||||
uint32_t key;
|
||||
std::vector<index_range> value;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(key)
|
||||
KV_SERIALIZE(value)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response_t
|
||||
{
|
||||
std::vector<subaddrs> all_subaddrs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(all_subaddrs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
//-----------------------------------------------
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue