Files
wownero-lws/src/db/account.cpp
2024-04-03 21:46:44 -04:00

188 lines
5.8 KiB
C++

// Copyright (c) 2018, The Monero Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "account.h"
#include <algorithm>
#include <cstring>
#include "common/error.h"
#include "common/expect.h"
#include "db/data.h"
#include "db/string.h"
namespace lws
{
namespace
{
// update if `crypto::public_key` gets `operator<`
struct sort_pubs
{
bool operator()(crypto::public_key const& lhs, crypto::public_key const& rhs) const noexcept
{
return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(lhs)) < 0;
}
};
}
struct account::internal
{
explicit internal(db::account const& source)
: address(db::address_string(source.address)), id(source.id), pubs(source.address), view_key()
{
using inner_type =
std::remove_reference<decltype(tools::unwrap(view_key))>::type;
static_assert(std::is_standard_layout<db::view_key>(), "need standard layout source");
static_assert(std::is_pod<inner_type>(), "need pod target");
static_assert(sizeof(view_key) == sizeof(source.key), "different size keys");
std::memcpy(
std::addressof(tools::unwrap(view_key)),
std::addressof(source.key),
sizeof(source.key)
);
}
std::string address;
db::account_id id;
db::account_address pubs;
crypto::secret_key view_key;
};
account::account(std::shared_ptr<const internal> immutable, db::block_id height, std::vector<std::pair<db::output_id, db::address_index>> spendable, std::vector<crypto::public_key> pubs) noexcept
: immutable_(std::move(immutable))
, spendable_(std::move(spendable))
, pubs_(std::move(pubs))
, spends_()
, outputs_()
, height_(height)
{}
void account::null_check() const
{
if (!immutable_)
MONERO_THROW(::common_error::kInvalidArgument, "using moved from account");
}
account::account(db::account const& source, std::vector<std::pair<db::output_id, db::address_index>> spendable, std::vector<crypto::public_key> pubs)
: account(std::make_shared<internal>(source), source.scan_height, std::move(spendable), std::move(pubs))
{
std::sort(spendable_.begin(), spendable_.end());
std::sort(pubs_.begin(), pubs_.end(), sort_pubs{});
}
account::~account() noexcept
{}
account account::clone() const
{
account result{immutable_, height_, spendable_, pubs_};
result.outputs_ = outputs_;
result.spends_ = spends_;
return result;
}
void account::updated(db::block_id new_height) noexcept
{
height_ = new_height;
spends_.clear();
spends_.shrink_to_fit();
outputs_.clear();
outputs_.shrink_to_fit();
}
db::account_id account::id() const noexcept
{
if (immutable_)
return immutable_->id;
return db::account_id::invalid;
}
std::string const& account::address() const
{
null_check();
return immutable_->address;
}
db::account_address const& account::db_address() const
{
null_check();
return immutable_->pubs;
}
crypto::public_key const& account::view_public() const
{
null_check();
return immutable_->pubs.view_public;
}
crypto::public_key const& account::spend_public() const
{
null_check();
return immutable_->pubs.spend_public;
}
crypto::secret_key const& account::view_key() const
{
null_check();
return immutable_->view_key;
}
boost::optional<db::address_index> account::get_spendable(db::output_id const& id) const noexcept
{
const auto searchable =
std::make_pair(id, db::address_index{db::major_index::primary, db::minor_index::primary});
const auto account =
std::lower_bound(spendable_.begin(), spendable_.end(), searchable);
if (account == spendable_.end() || account->first != id)
return boost::none;
return account->second;
}
bool account::add_out(db::output const& out)
{
auto existing_pub = std::lower_bound(pubs_.begin(), pubs_.end(), out.pub, sort_pubs{});
if (existing_pub != pubs_.end() && *existing_pub == out.pub)
return false;
pubs_.insert(existing_pub, out.pub);
auto spendable_value = std::make_pair(out.spend_meta.id, out.recipient);
spendable_.insert(
std::lower_bound(spendable_.begin(), spendable_.end(), spendable_value),
spendable_value
);
outputs_.push_back(out);
return true;
}
void account::add_spend(db::spend const& spend)
{
spends_.push_back(spend);
}
} // lws