forked from such-gitea/wownero-lws
Initial working base separated from top-level monero project
This commit is contained in:
34
src/db/CMakeLists.txt
Normal file
34
src/db/CMakeLists.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2018-2020, 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.
|
||||
|
||||
set(monero-lws-db_sources account.cpp data.cpp storage.cpp string.cpp)
|
||||
set(monero-lws-db_headers account.h data.h fwd.h storage.h string.h)
|
||||
|
||||
add_library(monero-lws-db ${monero-lws-db_sources} ${monero-lws-db_headers})
|
||||
target_include_directories(monero-lws-db PUBLIC "${LMDB_INCLUDE}")
|
||||
target_link_libraries(monero-lws-db monero::libraries ${LMDB_LIB_PATH})
|
||||
179
src/db/account.cpp
Normal file
179
src/db/account.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
// 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<db::output_id> 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<db::output_id> 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;
|
||||
}
|
||||
|
||||
bool account::has_spendable(db::output_id const& id) const noexcept
|
||||
{
|
||||
return std::binary_search(spendable_.begin(), spendable_.end(), id);
|
||||
}
|
||||
|
||||
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);
|
||||
spendable_.insert(
|
||||
std::lower_bound(spendable_.begin(), spendable_.end(), out.spend_meta.id),
|
||||
out.spend_meta.id
|
||||
);
|
||||
outputs_.push_back(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
void account::add_spend(db::spend const& spend)
|
||||
{
|
||||
spends_.push_back(spend);
|
||||
}
|
||||
} // lws
|
||||
|
||||
114
src/db/account.h
Normal file
114
src/db/account.h
Normal file
@@ -0,0 +1,114 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "fwd.h"
|
||||
#include "db/fwd.h"
|
||||
|
||||
namespace lws
|
||||
{
|
||||
//! Tracks a subset of DB account info for scanning/updating.
|
||||
class account
|
||||
{
|
||||
struct internal;
|
||||
|
||||
std::shared_ptr<const internal> immutable_;
|
||||
std::vector<db::output_id> spendable_;
|
||||
std::vector<crypto::public_key> pubs_;
|
||||
std::vector<db::spend> spends_;
|
||||
std::vector<db::output> outputs_;
|
||||
db::block_id height_;
|
||||
|
||||
explicit account(std::shared_ptr<const internal> immutable, db::block_id height, std::vector<db::output_id> spendable, std::vector<crypto::public_key> pubs) noexcept;
|
||||
void null_check() const;
|
||||
|
||||
public:
|
||||
|
||||
//! Construct an account from `source` and current `spendable` outputs.
|
||||
explicit account(db::account const& source, std::vector<db::output_id> spendable, std::vector<crypto::public_key> pubs);
|
||||
|
||||
/*!
|
||||
\return False if this is a "moved-from" account (i.e. the internal memory
|
||||
has been moved to another object).
|
||||
*/
|
||||
explicit operator bool() const noexcept { return immutable_ != nullptr; }
|
||||
|
||||
account(const account&) = delete;
|
||||
account(account&&) = default;
|
||||
~account() noexcept;
|
||||
account& operator=(const account&) = delete;
|
||||
account& operator=(account&&) = default;
|
||||
|
||||
//! \return A copy of `this`.
|
||||
account clone() const;
|
||||
|
||||
//! \return A copy of `this` with a new height and `outputs().empty()`.
|
||||
void updated(db::block_id new_height) noexcept;
|
||||
|
||||
//! \return Unique ID from the account database, possibly `db::account_id::kInvalid`.
|
||||
db::account_id id() const noexcept;
|
||||
|
||||
//! \return Monero base58 string for account.
|
||||
std::string const& address() const;
|
||||
|
||||
//! \return Object used for lookup in LMDB.
|
||||
db::account_address const& db_address() const;
|
||||
|
||||
//! \return Extracted view public key from `address()`
|
||||
crypto::public_key const& view_public() const;
|
||||
|
||||
//! \return Extracted spend public key from `address()`.
|
||||
crypto::public_key const& spend_public() const;
|
||||
|
||||
//! \return Secret view key for the account.
|
||||
crypto::secret_key const& view_key() const;
|
||||
|
||||
//! \return Current scan height of `this`.
|
||||
db::block_id scan_height() const noexcept { return height_; }
|
||||
|
||||
//! \return True iff `id` is spendable by `this`.
|
||||
bool has_spendable(db::output_id const& id) const noexcept;
|
||||
|
||||
//! \return Outputs matched during the latest scan.
|
||||
std::vector<db::output> const& outputs() const noexcept { return outputs_; }
|
||||
|
||||
//! \return Spends matched during the latest scan.
|
||||
std::vector<db::spend> const& spends() const noexcept { return spends_; }
|
||||
|
||||
//! Track a newly received `out`, \return `false` if `out.pub` is duplicated.
|
||||
bool add_out(db::output const& out);
|
||||
|
||||
//! Track a possible `spend`.
|
||||
void add_spend(db::spend const& spend);
|
||||
};
|
||||
} // lws
|
||||
225
src/db/data.cpp
Normal file
225
src/db/data.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
// 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 "data.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "wire/crypto.h"
|
||||
#include "wire.h"
|
||||
|
||||
namespace lws
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template<typename F, typename T>
|
||||
void map_output_id(F& format, T& self)
|
||||
{
|
||||
wire::object(format, WIRE_FIELD(high), WIRE_FIELD(low));
|
||||
}
|
||||
}
|
||||
WIRE_DEFINE_OBJECT(output_id, map_output_id);
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr const char* map_account_status[] = {"active", "inactive", "hidden"};
|
||||
constexpr const char* map_request[] = {"create", "import"};
|
||||
}
|
||||
WIRE_DEFINE_ENUM(account_status, map_account_status);
|
||||
WIRE_DEFINE_ENUM(request, map_request);
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename F, typename T>
|
||||
void map_account_address(F& format, T& self)
|
||||
{
|
||||
wire::object(format, WIRE_FIELD(spend_public), WIRE_FIELD(view_public));
|
||||
}
|
||||
}
|
||||
WIRE_DEFINE_OBJECT(account_address, map_account_address);
|
||||
|
||||
void write_bytes(wire::writer& dest, const account& self, const bool show_key)
|
||||
{
|
||||
view_key const* const key =
|
||||
show_key ? std::addressof(self.key) : nullptr;
|
||||
const bool admin = (self.flags & admin_account);
|
||||
const bool generated_locally = (self.flags & account_generated_locally);
|
||||
|
||||
wire::object(dest,
|
||||
WIRE_FIELD(id),
|
||||
wire::field("access_time", self.access),
|
||||
WIRE_FIELD(address),
|
||||
wire::optional_field("view_key", key),
|
||||
WIRE_FIELD(scan_height),
|
||||
WIRE_FIELD(start_height),
|
||||
wire::field("creation_time", self.creation),
|
||||
wire::field("admin", admin),
|
||||
wire::field("generated_locally", generated_locally)
|
||||
);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename F, typename T>
|
||||
void map_block_info(F& format, T& self)
|
||||
{
|
||||
wire::object(format, WIRE_FIELD(id), WIRE_FIELD(hash));
|
||||
}
|
||||
}
|
||||
WIRE_DEFINE_OBJECT(block_info, map_block_info);
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename F, typename T>
|
||||
void map_transaction_link(F& format, T& self)
|
||||
{
|
||||
wire::object(format, WIRE_FIELD(height), WIRE_FIELD(tx_hash));
|
||||
}
|
||||
}
|
||||
WIRE_DEFINE_OBJECT(transaction_link, map_transaction_link);
|
||||
|
||||
void write_bytes(wire::writer& dest, const output& self)
|
||||
{
|
||||
const std::pair<db::extra, std::uint8_t> unpacked =
|
||||
db::unpack(self.extra);
|
||||
|
||||
const bool coinbase = (unpacked.first & lws::db::coinbase_output);
|
||||
const bool rct = (unpacked.first & lws::db::ringct_output);
|
||||
|
||||
const auto rct_mask = rct ? std::addressof(self.ringct_mask) : nullptr;
|
||||
|
||||
epee::span<const std::uint8_t> payment_bytes{};
|
||||
if (unpacked.second == 32)
|
||||
payment_bytes = epee::as_byte_span(self.payment_id.long_);
|
||||
else if (unpacked.second == 8)
|
||||
payment_bytes = epee::as_byte_span(self.payment_id.short_);
|
||||
|
||||
const auto payment_id = payment_bytes.empty() ?
|
||||
nullptr : std::addressof(payment_bytes);
|
||||
|
||||
wire::object(dest,
|
||||
wire::field("id", std::cref(self.spend_meta.id)),
|
||||
wire::field("block", self.link.height),
|
||||
wire::field("index", self.spend_meta.index),
|
||||
wire::field("amount", self.spend_meta.amount),
|
||||
wire::field("timestamp", self.timestamp),
|
||||
wire::field("tx_hash", std::cref(self.link.tx_hash)),
|
||||
wire::field("tx_prefix_hash", std::cref(self.tx_prefix_hash)),
|
||||
wire::field("tx_public", std::cref(self.spend_meta.tx_public)),
|
||||
wire::optional_field("rct_mask", rct_mask),
|
||||
wire::optional_field("payment_id", payment_id),
|
||||
wire::field("unlock_time", self.unlock_time),
|
||||
wire::field("mixin_count", self.spend_meta.mixin_count),
|
||||
wire::field("coinbase", coinbase)
|
||||
);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename F, typename T1, typename T2>
|
||||
void map_spend(F& format, T1& self, T2& payment_id)
|
||||
{
|
||||
wire::object(format,
|
||||
wire::field("height", self.link.height),
|
||||
wire::field("tx_hash", std::ref(self.link.tx_hash)),
|
||||
WIRE_FIELD(image),
|
||||
WIRE_FIELD(source),
|
||||
WIRE_FIELD(timestamp),
|
||||
WIRE_FIELD(unlock_time),
|
||||
WIRE_FIELD(mixin_count),
|
||||
wire::optional_field("payment_id", payment_id)
|
||||
);
|
||||
}
|
||||
}
|
||||
void read_bytes(wire::reader& source, spend& dest)
|
||||
{
|
||||
boost::optional<crypto::hash> payment_id;
|
||||
map_spend(source, dest, payment_id);
|
||||
|
||||
if (payment_id)
|
||||
{
|
||||
dest.length = sizeof(dest.payment_id);
|
||||
dest.payment_id = std::move(*payment_id);
|
||||
}
|
||||
else
|
||||
dest.length = 0;
|
||||
}
|
||||
void write_bytes(wire::writer& dest, const spend& source)
|
||||
{
|
||||
crypto::hash const* const payment_id =
|
||||
(source.length == sizeof(source.payment_id) ?
|
||||
std::addressof(source.payment_id) : nullptr);
|
||||
return map_spend(dest, source, payment_id);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename F, typename T>
|
||||
void map_key_image(F& format, T& self)
|
||||
{
|
||||
wire::object(format,
|
||||
wire::field("key_image", std::ref(self.value)),
|
||||
wire::field("tx_hash", std::ref(self.link.tx_hash)),
|
||||
wire::field("height", self.link.height)
|
||||
);
|
||||
}
|
||||
}
|
||||
WIRE_DEFINE_OBJECT(key_image, map_key_image);
|
||||
|
||||
void write_bytes(wire::writer& dest, const request_info& self, const bool show_key)
|
||||
{
|
||||
db::view_key const* const key =
|
||||
show_key ? std::addressof(self.key) : nullptr;
|
||||
const bool generated = (self.creation_flags & lws::db::account_generated_locally);
|
||||
|
||||
wire::object(dest,
|
||||
WIRE_FIELD(address),
|
||||
wire::optional_field("view_key", key),
|
||||
WIRE_FIELD(start_height),
|
||||
wire::field("generated_locally", generated)
|
||||
);
|
||||
}
|
||||
|
||||
/*! TODO consider making an `operator<` for `crypto::tx_hash`. Not known to be
|
||||
needed elsewhere yet. */
|
||||
|
||||
bool operator<(transaction_link const& left, transaction_link const& right) noexcept
|
||||
{
|
||||
return left.height == right.height ?
|
||||
std::memcmp(std::addressof(left.tx_hash), std::addressof(right.tx_hash), sizeof(left.tx_hash)) < 0 :
|
||||
left.height < right.height;
|
||||
}
|
||||
bool operator<=(transaction_link const& left, transaction_link const& right) noexcept
|
||||
{
|
||||
return right.height == left.height ?
|
||||
std::memcmp(std::addressof(left.tx_hash), std::addressof(right.tx_hash), sizeof(left.tx_hash)) <= 0 :
|
||||
left.height < right.height;
|
||||
}
|
||||
} // db
|
||||
} // lws
|
||||
275
src/db/data.h
Normal file
275
src/db/data.h
Normal file
@@ -0,0 +1,275 @@
|
||||
// Copyright (c) 2018-2020, 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.
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <utility>
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "lmdb/util.h"
|
||||
#include "ringct/rctTypes.h" //! \TODO brings in lots of includes, try to remove
|
||||
#include "wire/fwd.h"
|
||||
#include "wire/traits.h"
|
||||
|
||||
namespace lws
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
/*
|
||||
Enum classes are used because they generate identical code to native integer
|
||||
types, but are not implicitly convertible to each other or any integer types.
|
||||
They also have comparison but not arithmetic operators defined.
|
||||
*/
|
||||
|
||||
//! References an account stored in the database, faster than by address
|
||||
enum class account_id : std::uint32_t
|
||||
{
|
||||
invalid = std::uint32_t(-1) //!< Always represents _not an_ account id.
|
||||
};
|
||||
WIRE_AS_INTEGER(account_id);
|
||||
|
||||
//! Number of seconds since UNIX epoch.
|
||||
enum class account_time : std::uint32_t {};
|
||||
WIRE_AS_INTEGER(account_time);
|
||||
|
||||
//! References a block height
|
||||
enum class block_id : std::uint64_t {};
|
||||
WIRE_AS_INTEGER(block_id);
|
||||
|
||||
//! References a global output number, as determined by the public chain
|
||||
struct output_id
|
||||
{
|
||||
std::uint64_t high; //!< Amount on public chain; rct outputs are `0`
|
||||
std::uint64_t low; //!< Offset within `amount` on the public chain
|
||||
};
|
||||
WIRE_DECLARE_OBJECT(output_id);
|
||||
|
||||
enum class account_status : std::uint8_t
|
||||
{
|
||||
active = 0, //!< Actively being scanned and reported by API
|
||||
inactive, //!< Not being scanned, but still reported by API
|
||||
hidden //!< Not being scanned or reported by API
|
||||
};
|
||||
WIRE_DECLARE_ENUM(account_status);
|
||||
|
||||
enum account_flags : std::uint8_t
|
||||
{
|
||||
default_account = 0,
|
||||
admin_account = 1, //!< Not currently used, for future extensions
|
||||
account_generated_locally = 2 //!< Flag sent by client on initial login request
|
||||
};
|
||||
|
||||
enum class request : std::uint8_t
|
||||
{
|
||||
create = 0, //!< Add a new account
|
||||
import_scan //!< Set account start and scan height to zero.
|
||||
};
|
||||
WIRE_DECLARE_ENUM(request);
|
||||
|
||||
/*!
|
||||
DB does not use `crypto::secret_key` because it is not POD (UB to copy over
|
||||
entire struct). LMDB is keeping a copy in process memory anyway (row
|
||||
encryption not currently used). The roadmap recommends process isolation
|
||||
per-connection by default as a defense against viewkey leaks due to bug. */
|
||||
|
||||
struct view_key : crypto::ec_scalar {};
|
||||
// wire::is_blob trait below
|
||||
|
||||
//! The public keys of a monero address
|
||||
struct account_address
|
||||
{
|
||||
crypto::public_key spend_public; //!< Must be first for LMDB optimizations.
|
||||
crypto::public_key view_public;
|
||||
};
|
||||
static_assert(sizeof(account_address) == 64, "padding in account_address");
|
||||
WIRE_DECLARE_OBJECT(account_address);
|
||||
|
||||
struct account
|
||||
{
|
||||
account_id id; //!< Must be first for LMDB optimizations
|
||||
account_time access; //!< Last time `get_address_info` was called.
|
||||
account_address address;
|
||||
view_key key; //!< Doubles as authorization handle for REST API.
|
||||
block_id scan_height; //!< Last block scanned; check-ins are always by block
|
||||
block_id start_height; //!< Account started scanning at this block height
|
||||
account_time creation; //!< Time account first appeared in database.
|
||||
account_flags flags; //!< Additional account info bitmask.
|
||||
char reserved[3];
|
||||
};
|
||||
static_assert(sizeof(account) == (4 * 2) + 64 + 32 + (8 * 2) + (4 * 2), "padding in account");
|
||||
void write_bytes(wire::writer&, const account&, bool show_key = false);
|
||||
|
||||
struct block_info
|
||||
{
|
||||
block_id id; //!< Must be first for LMDB optimizations
|
||||
crypto::hash hash;
|
||||
};
|
||||
static_assert(sizeof(block_info) == 8 + 32, "padding in block_info");
|
||||
WIRE_DECLARE_OBJECT(block_info);
|
||||
|
||||
//! `output`s and `spend`s are sorted by these fields to make merging easier.
|
||||
struct transaction_link
|
||||
{
|
||||
block_id height; //!< Block height containing transaction
|
||||
crypto::hash tx_hash; //!< Hash of the transaction
|
||||
};
|
||||
|
||||
//! Additional flags stored in `output`s.
|
||||
enum extra : std::uint8_t
|
||||
{
|
||||
coinbase_output = 1,
|
||||
ringct_output = 2
|
||||
};
|
||||
|
||||
//! Packed information stored in `output`s.
|
||||
enum class extra_and_length : std::uint8_t {};
|
||||
|
||||
//! \return `val` and `length` packed into a single byte.
|
||||
inline extra_and_length pack(extra val, std::uint8_t length) noexcept
|
||||
{
|
||||
assert(length <= 32);
|
||||
return extra_and_length((std::uint8_t(val) << 6) | (length & 0x3f));
|
||||
}
|
||||
|
||||
//! \return `extra` and length unpacked from a single byte.
|
||||
inline std::pair<extra, std::uint8_t> unpack(extra_and_length val) noexcept
|
||||
{
|
||||
const std::uint8_t real_val = std::uint8_t(val);
|
||||
return {extra(real_val >> 6), std::uint8_t(real_val & 0x3f)};
|
||||
}
|
||||
|
||||
//! Information for an output that has been received by an `account`.
|
||||
struct output
|
||||
{
|
||||
transaction_link link; //! Orders and links `output` to `spend`s.
|
||||
|
||||
//! Data that a linked `spend` needs in some REST endpoints.
|
||||
struct spend_meta_
|
||||
{
|
||||
output_id id; //!< Unique id for output within monero
|
||||
// `link` and `id` must be in this order for LMDB optimizations
|
||||
std::uint64_t amount;
|
||||
std::uint32_t mixin_count;//!< Ring-size of TX
|
||||
std::uint32_t index; //!< Offset within a tx
|
||||
crypto::public_key tx_public;
|
||||
} spend_meta;
|
||||
|
||||
std::uint64_t timestamp;
|
||||
std::uint64_t unlock_time; //!< Not always a timestamp; mirrors chain value.
|
||||
crypto::hash tx_prefix_hash;
|
||||
crypto::public_key pub; //!< One-time spendable public key.
|
||||
rct::key ringct_mask; //!< Unencrypted CT mask
|
||||
char reserved[7];
|
||||
extra_and_length extra; //!< Extra info + length of payment id
|
||||
union payment_id_
|
||||
{
|
||||
crypto::hash8 short_; //!< Decrypted short payment id
|
||||
crypto::hash long_; //!< Long version of payment id (always decrypted)
|
||||
} payment_id;
|
||||
};
|
||||
static_assert(
|
||||
sizeof(output) == 8 + 32 + (8 * 3) + (4 * 2) + 32 + (8 * 2) + (32 * 3) + 7 + 1 + 32,
|
||||
"padding in output"
|
||||
);
|
||||
void write_bytes(wire::writer&, const output&);
|
||||
|
||||
//! Information about a possible spend of a received `output`.
|
||||
struct spend
|
||||
{
|
||||
transaction_link link; //!< Orders and links `spend` to `output`.
|
||||
crypto::key_image image; //!< Unique ID for the spend
|
||||
// `link` and `image` must in this order for LMDB optimizations
|
||||
output_id source; //!< The output being spent
|
||||
std::uint64_t timestamp; //!< Timestamp of spend
|
||||
std::uint64_t unlock_time;//!< Unlock time of spend
|
||||
std::uint32_t mixin_count;//!< Ring-size of TX output
|
||||
char reserved[3];
|
||||
std::uint8_t length; //!< Length of `payment_id` field (0..32).
|
||||
crypto::hash payment_id; //!< Unencrypted only, can't decrypt spend
|
||||
};
|
||||
static_assert(sizeof(spend) == 8 + 32 * 2 + 8 * 4 + 4 + 3 + 1 + 32, "padding in spend");
|
||||
WIRE_DECLARE_OBJECT(spend);
|
||||
|
||||
//! Key image and info needed to retrieve primary `spend` data.
|
||||
struct key_image
|
||||
{
|
||||
crypto::key_image value; //!< Actual key image value
|
||||
// The above field needs to be first for LMDB optimizations
|
||||
transaction_link link; //!< Link to `spend` and `output`.
|
||||
};
|
||||
WIRE_DECLARE_OBJECT(key_image);
|
||||
|
||||
struct request_info
|
||||
{
|
||||
account_address address;//!< Must be first for LMDB optimizations
|
||||
view_key key;
|
||||
block_id start_height;
|
||||
account_time creation; //!< Time the request was created.
|
||||
account_flags creation_flags; //!< Generated locally?
|
||||
char reserved[3];
|
||||
};
|
||||
static_assert(sizeof(request_info) == 64 + 32 + 8 + (4 * 2), "padding in request_info");
|
||||
void write_bytes(wire::writer& dest, const request_info& self, bool show_key = false);
|
||||
|
||||
inline constexpr bool operator==(output_id left, output_id right) noexcept
|
||||
{
|
||||
return left.high == right.high && left.low == right.low;
|
||||
}
|
||||
inline constexpr bool operator!=(output_id left, output_id right) noexcept
|
||||
{
|
||||
return left.high != right.high || left.low != right.low;
|
||||
}
|
||||
inline constexpr bool operator<(output_id left, output_id right) noexcept
|
||||
{
|
||||
return left.high == right.high ?
|
||||
left.low < right.low : left.high < right.high;
|
||||
}
|
||||
inline constexpr bool operator<=(output_id left, output_id right) noexcept
|
||||
{
|
||||
return left.high == right.high ?
|
||||
left.low <= right.low : left.high < right.high;
|
||||
}
|
||||
|
||||
bool operator<(transaction_link const& left, transaction_link const& right) noexcept;
|
||||
bool operator<=(transaction_link const& left, transaction_link const& right) noexcept;
|
||||
|
||||
/*!
|
||||
Write `address` to `out` in base58 format using `lws::config::network` to
|
||||
determine tag. */
|
||||
std::ostream& operator<<(std::ostream& out, account_address const& address);
|
||||
} // db
|
||||
} // lws
|
||||
|
||||
namespace wire
|
||||
{
|
||||
template<>
|
||||
struct is_blob<lws::db::view_key>
|
||||
: std::true_type
|
||||
{};
|
||||
}
|
||||
56
src/db/fwd.h
Normal file
56
src/db/fwd.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2018-2020, 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lws
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
enum account_flags : std::uint8_t;
|
||||
enum class account_id : std::uint32_t;
|
||||
enum class account_status : std::uint8_t;
|
||||
enum class block_id : std::uint64_t;
|
||||
enum extra : std::uint8_t;
|
||||
enum class extra_and_length : std::uint8_t;
|
||||
enum class request : std::uint8_t;
|
||||
|
||||
struct account;
|
||||
struct account_address;
|
||||
struct block_info;
|
||||
struct key_image;
|
||||
struct output;
|
||||
struct output_id;
|
||||
struct request_info;
|
||||
struct spend;
|
||||
class storage;
|
||||
struct transaction_link;
|
||||
struct view_key;
|
||||
} // db
|
||||
} // lws
|
||||
1797
src/db/storage.cpp
Normal file
1797
src/db/storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
239
src/db/storage.h
Normal file
239
src/db/storage.h
Normal file
@@ -0,0 +1,239 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include <iosfwd>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/expect.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "db/account.h"
|
||||
#include "db/data.h"
|
||||
#include "fwd.h"
|
||||
#include "lmdb/transaction.h"
|
||||
#include "lmdb/key_stream.h"
|
||||
#include "lmdb/value_stream.h"
|
||||
|
||||
namespace lws
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
namespace cursor
|
||||
{
|
||||
MONERO_CURSOR(accounts);
|
||||
MONERO_CURSOR(outputs);
|
||||
MONERO_CURSOR(spends);
|
||||
MONERO_CURSOR(images);
|
||||
MONERO_CURSOR(requests);
|
||||
|
||||
MONERO_CURSOR(blocks);
|
||||
MONERO_CURSOR(accounts_by_address);
|
||||
MONERO_CURSOR(accounts_by_height);
|
||||
}
|
||||
|
||||
struct storage_internal;
|
||||
struct reader_internal
|
||||
{
|
||||
cursor::blocks blocks_cur;
|
||||
cursor::accounts_by_address accounts_ba_cur;
|
||||
cursor::accounts_by_height accounts_bh_cur;
|
||||
};
|
||||
|
||||
//! Wrapper for LMDB read access to on-disk storage of light-weight server data.
|
||||
class storage_reader
|
||||
{
|
||||
std::shared_ptr<storage_internal> db;
|
||||
lmdb::read_txn txn;
|
||||
reader_internal curs;
|
||||
|
||||
public:
|
||||
storage_reader(std::shared_ptr<storage_internal> db, lmdb::read_txn txn) noexcept
|
||||
: db(std::move(db)), txn(std::move(txn)), curs{}
|
||||
{}
|
||||
|
||||
storage_reader(storage_reader&&) = default;
|
||||
storage_reader(storage_reader const&) = delete;
|
||||
|
||||
~storage_reader() noexcept;
|
||||
|
||||
storage_reader& operator=(storage_reader&&) = default;
|
||||
storage_reader& operator=(storage_reader const&) = delete;
|
||||
|
||||
//! \return Last known block.
|
||||
expect<block_info> get_last_block() noexcept;
|
||||
|
||||
//! \return List for `GetHashesFast` to sync blockchain with daemon.
|
||||
expect<std::list<crypto::hash>> get_chain_sync();
|
||||
|
||||
//! \return All registered `account`s.
|
||||
expect<lmdb::key_stream<account_status, account, cursor::close_accounts>>
|
||||
get_accounts(cursor::accounts cur = nullptr) noexcept;
|
||||
|
||||
//! \return All `account`s currently in `status` or `lmdb::error(MDB_NOT_FOUND)`.
|
||||
expect<lmdb::value_stream<account, cursor::close_accounts>>
|
||||
get_accounts(account_status status, cursor::accounts cur = nullptr) noexcept;
|
||||
|
||||
//! \return Info related to `address` or `lmdb::error(MDB_NOT_FOUND)`.
|
||||
expect<std::pair<account_status, account>>
|
||||
get_account(account_address const& address, cursor::accounts& cur) noexcept;
|
||||
|
||||
expect<std::pair<account_status, account>>
|
||||
get_account(account_address const& address) noexcept
|
||||
{
|
||||
cursor::accounts cur;
|
||||
return get_account(address, cur);
|
||||
}
|
||||
|
||||
//! \return All outputs received by `id`.
|
||||
expect<lmdb::value_stream<output, cursor::close_outputs>>
|
||||
get_outputs(account_id id, cursor::outputs cur = nullptr) noexcept;
|
||||
|
||||
//! \return All potential spends by `id`.
|
||||
expect<lmdb::value_stream<spend, cursor::close_spends>>
|
||||
get_spends(account_id id, cursor::spends cur = nullptr) noexcept;
|
||||
|
||||
//! \return All key images associated with `id`.
|
||||
expect<lmdb::value_stream<db::key_image, cursor::close_images>>
|
||||
get_images(output_id id, cursor::images cur = nullptr) noexcept;
|
||||
|
||||
//! \return All `request_info`s.
|
||||
expect<lmdb::key_stream<request, request_info, cursor::close_requests>>
|
||||
get_requests(cursor::requests cur = nullptr) noexcept;
|
||||
|
||||
//! \return A specific request from `address` of `type`.
|
||||
expect<request_info>
|
||||
get_request(request type, account_address const& address, cursor::requests cur = nullptr) noexcept;
|
||||
|
||||
//! Dump the contents of the database in JSON format to `out`.
|
||||
expect<void> json_debug(std::ostream& out, bool show_keys);
|
||||
|
||||
//! \return Read txn that can be re-used via `storage::start_read`.
|
||||
lmdb::suspended_txn finish_read() noexcept;
|
||||
};
|
||||
|
||||
//! Wrapper for LMDB on-disk storage of light-weight server data.
|
||||
class storage
|
||||
{
|
||||
std::shared_ptr<storage_internal> db;
|
||||
|
||||
storage(std::shared_ptr<storage_internal> db) noexcept
|
||||
: db(std::move(db))
|
||||
{}
|
||||
|
||||
public:
|
||||
/*!
|
||||
Open a light_wallet_server LDMB database.
|
||||
|
||||
\param path Directory for LMDB storage
|
||||
\param create_queue_max Maximum number of create account requests allowed.
|
||||
|
||||
\throw std::system_error on any LMDB error (all treated as fatal).
|
||||
\throw std::bad_alloc If `std::shared_ptr` fails to allocate.
|
||||
|
||||
\return A ready light-wallet server database.
|
||||
*/
|
||||
static storage open(const char* path, unsigned create_queue_max);
|
||||
|
||||
storage(storage&&) = default;
|
||||
storage(storage const&) = delete;
|
||||
|
||||
~storage() noexcept;
|
||||
|
||||
storage& operator=(storage&&) = default;
|
||||
storage& operator=(storage const&) = delete;
|
||||
|
||||
//! \return A copy of the LMDB environment, but not reusable txn/cursors.
|
||||
storage clone() const noexcept;
|
||||
|
||||
//! Rollback chain and accounts to `height`.
|
||||
expect<void> rollback(block_id height);
|
||||
|
||||
/*!
|
||||
Sync the local blockchain with a remote version. Pops user txes if reorg
|
||||
detected.
|
||||
|
||||
\param height The height of the element in `hashes`
|
||||
\param hashes List of blockchain hashes starting at `height`.
|
||||
|
||||
\return True if the local blockchain is correctly synced.
|
||||
*/
|
||||
expect<void> sync_chain(block_id height, epee::span<const crypto::hash> hashes);
|
||||
|
||||
//! Bump the last access time of `address` to the current time.
|
||||
expect<void> update_access_time(account_address const& address) noexcept;
|
||||
|
||||
//! Change state of `address` to `status`. \return Updated `addresses`.
|
||||
expect<std::vector<account_address>>
|
||||
change_status(account_status status, epee::span<const account_address> addresses);
|
||||
|
||||
|
||||
//! Add an account, for immediate inclusion in the active list.
|
||||
expect<void> add_account(account_address const& address, crypto::secret_key const& key) noexcept;
|
||||
|
||||
//! Reset `addresses` to `height` for scanning.
|
||||
expect<std::vector<account_address>>
|
||||
rescan(block_id height, epee::span<const account_address> addresses);
|
||||
|
||||
//! Add an account for later approval. For use with the login endpoint.
|
||||
expect<void> creation_request(account_address const& address, crypto::secret_key const& key, account_flags flags) noexcept;
|
||||
|
||||
/*!
|
||||
Request lock height of an existing account. No effect if the `start_height`
|
||||
is already older.
|
||||
*/
|
||||
expect<void> import_request(account_address const& address, block_id height) noexcept;
|
||||
|
||||
//! Accept requests by `addresses` of type `req`. \return Accepted addresses.
|
||||
expect<std::vector<account_address>>
|
||||
accept_requests(request req, epee::span<const account_address> addresses);
|
||||
|
||||
//! Reject requests by `addresses` of type `req`. \return Rejected addresses.
|
||||
expect<std::vector<account_address>>
|
||||
reject_requests(request req, epee::span<const account_address> addresses);
|
||||
|
||||
/*!
|
||||
Updates the status of user accounts, even if inactive or hidden. Duplicate
|
||||
receives or spends provided in `accts` are silently ignored. If a gap in
|
||||
`height` vs the stored account record is detected, the entire update will
|
||||
fail.
|
||||
|
||||
\param height The first hash in `chain` is at this height.
|
||||
\param chain List of block hashes that `accts` were scanned against.
|
||||
\param accts Updated to `height + chain.size()` scan height.
|
||||
|
||||
\return True iff LMDB successfully committed the update.
|
||||
*/
|
||||
expect<std::size_t> update(block_id height, epee::span<const crypto::hash> chain, epee::span<const lws::account> accts);
|
||||
|
||||
//! `txn` must have come from a previous call on the same thread.
|
||||
expect<storage_reader> start_read(lmdb::suspended_txn txn = nullptr) const;
|
||||
};
|
||||
} // db
|
||||
} // lws
|
||||
62
src/db/string.cpp
Normal file
62
src/db/string.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// 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 "string.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "db/data.h"
|
||||
#include "error.h"
|
||||
|
||||
namespace lws
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
std::string address_string_::operator()(account_address const& address) const
|
||||
{
|
||||
const cryptonote::account_public_address address_{
|
||||
address.spend_public, address.view_public
|
||||
};
|
||||
return cryptonote::get_account_address_as_str(
|
||||
lws::config::network, false, address_
|
||||
);
|
||||
}
|
||||
expect<account_address>
|
||||
address_string_::operator()(boost::string_ref address) const noexcept
|
||||
{
|
||||
cryptonote::address_parse_info info{};
|
||||
|
||||
if (!cryptonote::get_account_address_from_str(info, lws::config::network, std::string{address}))
|
||||
return {lws::error::bad_address};
|
||||
if (info.is_subaddress || info.has_payment_id)
|
||||
return {lws::error::bad_address};
|
||||
|
||||
return account_address{
|
||||
info.address.m_spend_public_key, info.address.m_view_public_key
|
||||
};
|
||||
}
|
||||
} // db
|
||||
} // lws
|
||||
55
src/db/string.h
Normal file
55
src/db/string.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "common/expect.h"
|
||||
#include "db/fwd.h"
|
||||
|
||||
namespace lws
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
//! Callable for converting `account_address` to/from monero base58 public address.
|
||||
struct address_string_
|
||||
{
|
||||
/*!
|
||||
\return `address` as a monero base58 public address, using
|
||||
`lws::config::network` for the tag.
|
||||
*/
|
||||
std::string operator()(account_address const& address) const;
|
||||
/*!
|
||||
\return `address`, as base58 public address, using `lws::config::network`
|
||||
for the tag.
|
||||
*/
|
||||
expect<account_address> operator()(boost::string_ref address) const noexcept;
|
||||
};
|
||||
constexpr const address_string_ address_string{};
|
||||
} // db
|
||||
} // lws
|
||||
Reference in New Issue
Block a user