Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/bitcoin/database/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ enum error_t : uint8_t
{
/// general
success,
canceled,
unknown_state,

/// integrity (internal fault)
integrity,
integrity1,
integrity2,
Expand Down
118 changes: 62 additions & 56 deletions include/bitcoin/database/impl/query/optional.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -26,103 +26,109 @@
#include <bitcoin/system.hpp>
#include <bitcoin/database/define.hpp>

// TODO: address table could use point keys to compress the multimap.

namespace libbitcoin {
namespace database {

// Address (natural-keyed).
// ----------------------------------------------------------------------------
// TODO: could use point keys (for multimap compression).
// Pushing into vectors is more efficient than precomputation of size.

TEMPLATE
bool CLASS::to_address_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT
code CLASS::to_address_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT
{
out.clear();

// Pushing into the vector is more efficient than precomputation of size.
for (auto it = store_.address.it(key); it; ++it)
{
if (cancel)
return error::canceled;

table::address::record address{};
if (cancel || !store_.address.get(it, address))
{
out.clear();
return false;
}
if (!store_.address.get(it, address))
return error::integrity;

out.push_back(address.output_fk);
out.insert(get_spent(address.output_fk));
}

return true;
return error::success;
}

TEMPLATE
bool CLASS::to_confirmed_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT
code CLASS::to_confirmed_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT
{
output_links output_fks{};
if (!to_address_outputs(cancel, output_fks, key))
return false;

out.clear();
out.reserve(output_fks.size());
for (auto output_fk: output_fks)
if (is_confirmed_unspent(output_fk))
out.push_back(output_fk);
for (auto it = store_.address.it(key); it; ++it)
{
if (cancel)
return error::canceled;

out.shrink_to_fit();
return true;
table::address::record address{};
if (!store_.address.get(it, address))
return error::integrity;

if (is_confirmed_unspent(address.output_fk))
out.insert(get_spent(address.output_fk));
}

return error::success;
}

// TODO: test more.
TEMPLATE
bool CLASS::to_minimum_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT
code CLASS::to_minimum_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT
{
output_links unspent_fks{};
if (!to_confirmed_unspent_outputs(cancel, unspent_fks, key))
return false;

out.clear();
out.reserve(unspent_fks.size());
for (auto unspent_fk: unspent_fks)
for (auto it = store_.address.it(key); it; ++it)
{
uint64_t value{};
if (!get_value(value, unspent_fk))
if (cancel)
return error::canceled;

table::address::record address{};
if (!store_.address.get(it, address))
return error::integrity;

if (is_confirmed_unspent(address.output_fk))
{
out.clear();
out.shrink_to_fit();
return false;
}
uint64_t value{};
if (!get_value(value, address.output_fk))
return error::integrity;

if (value >= minimum)
out.push_back(unspent_fk);
if (value >= minimum)
out.insert(get_spent(address.output_fk));
}
}

out.shrink_to_fit();
return true;
return error::success;
}

// TODO: test more.
TEMPLATE
bool CLASS::get_confirmed_balance(const std::atomic_bool& cancel,
code CLASS::get_confirmed_balance(const std::atomic_bool& cancel,
uint64_t& out, const hash_digest& key) const NOEXCEPT
{
out = zero;
output_links unspent_fks{};
if (!to_confirmed_unspent_outputs(cancel, unspent_fks, key))
return false;

for (auto unspent_fk: unspent_fks)
for (auto it = store_.address.it(key); it; ++it)
{
uint64_t value{};
if (!get_value(value, unspent_fk))
return false;
if (cancel)
return error::canceled;

table::address::record address{};
if (!store_.address.get(it, address))
return error::integrity;

// max if overflowed.
out = system::ceilinged_add(value, out);
if (is_confirmed_unspent(address.output_fk))
{
uint64_t value{};
if (!get_value(value, address.output_fk))
return error::integrity;

out = system::ceilinged_add(value, out);
}
}

return true;
return error::success;
}

////TEMPLATE
Expand Down
14 changes: 7 additions & 7 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,13 +549,13 @@ class query
/// Optional Tables.
/// -----------------------------------------------------------------------

bool to_address_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT;
bool to_confirmed_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT;
bool to_minimum_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key, uint64_t value) const NOEXCEPT;
bool get_confirmed_balance(const std::atomic_bool& cancel,
code to_address_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT;
code to_confirmed_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT;
code to_minimum_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, uint64_t value) const NOEXCEPT;
code get_confirmed_balance(const std::atomic_bool& cancel,
uint64_t& out, const hash_digest& key) const NOEXCEPT;

bool is_filtered_body(const header_link& link) const NOEXCEPT;
Expand Down
3 changes: 3 additions & 0 deletions src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
{
// general
{ success, "success" },
{ canceled, "canceled" },
{ unknown_state, "unknown state" },

// integrity (internal fault)
{ integrity, "store corrupted" },
{ integrity1, "store corrupted1" },
{ integrity2, "store corrupted2" },
Expand Down
9 changes: 9 additions & 0 deletions test/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__success__false_exected_message)
BOOST_REQUIRE_EQUAL(ec.message(), "success");
}

BOOST_AUTO_TEST_CASE(error_t__code__canceled__true_exected_message)
{
constexpr auto value = error::canceled;
const auto ec = code(value);
BOOST_REQUIRE(ec);
BOOST_REQUIRE(ec == value);
BOOST_REQUIRE_EQUAL(ec.message(), "canceled");
}

BOOST_AUTO_TEST_CASE(error_t__code__unknown_state__true_exected_message)
{
constexpr auto value = error::unknown_state;
Expand Down
38 changes: 19 additions & 19 deletions test/query/optional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__genesis__expected)
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
outpoints out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_address_outputs(cancel, out, genesis_address));
BOOST_REQUIRE(!query.to_address_outputs(cancel, out, genesis_address));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), query.to_output(0, 0));
////BOOST_REQUIRE_EQUAL(out.front(), query.to_output(0, 0));
}

BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__cancel__canceled_false)
Expand All @@ -52,9 +52,9 @@ BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__cancel__canceled_false)
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
outpoints out{};
const std::atomic_bool cancel{ true };
BOOST_REQUIRE(!query.to_address_outputs(cancel, out, genesis_address));
BOOST_REQUIRE_EQUAL(query.to_address_outputs(cancel, out, genesis_address), error::canceled);
BOOST_REQUIRE(out.empty());
}

Expand All @@ -67,11 +67,11 @@ BOOST_AUTO_TEST_CASE(query_optional__to_confirmed_unspent_outputs__genesis__expe
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
outpoints out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_confirmed_unspent_outputs(cancel, out, genesis_address));
BOOST_REQUIRE(!query.to_confirmed_unspent_outputs(cancel, out, genesis_address));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
////BOOST_REQUIRE_EQUAL(out.front(), 0);
}

BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__above__excluded)
Expand All @@ -83,9 +83,9 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__above__excluded
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
outpoints out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000001));
BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000001));
BOOST_REQUIRE(out.empty());
}

Expand All @@ -98,11 +98,11 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__at__included)
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
outpoints out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000000));
BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000000));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
////BOOST_REQUIRE_EQUAL(out.front(), 0);
}

BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__below__included)
Expand All @@ -114,14 +114,14 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__below__included
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
outpoints out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 0));
BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 0));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 4999999999));
////BOOST_REQUIRE_EQUAL(out.front(), 0);
BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 4999999999));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
////BOOST_REQUIRE_EQUAL(out.front(), 0);
}

BOOST_AUTO_TEST_CASE(query_optional__get_confirmed_balance__genesis__expected)
Expand All @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(query_optional__get_confirmed_balance__genesis__expected)

uint64_t out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.get_confirmed_balance(cancel, out, genesis_address));
BOOST_REQUIRE(!query.get_confirmed_balance(cancel, out, genesis_address));
BOOST_REQUIRE_EQUAL(out, 5000000000u);
}

Expand Down
Loading