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
21 changes: 14 additions & 7 deletions include/bitcoin/database/impl/query/address/address_balance.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ namespace database {

// unused
TEMPLATE
code CLASS::get_unconfirmed_balance(stopper& , uint64_t& ,
const hash_digest& , bool ) const NOEXCEPT
code CLASS::get_unconfirmed_balance(stopper& cancel, uint64_t& out,
const hash_digest& key, bool turbo) const NOEXCEPT
{
return {};
// While duplicates are easily filtered out, conflict resolution is murky.
// An output may have multiple directly or indirectly conflicting spends,
// and other spends and receives may not be visible. An unconfirmed balance
// is therefore inherehtly ambiguous. Given the lack of tx pooling,
// presently we just return combined = confirmed (net zero unconfirmed).
return get_confirmed_balance(cancel, out, key, turbo);
}

// server/native
Expand All @@ -63,11 +68,13 @@ code CLASS::get_confirmed_balance(stopper& cancel, uint64_t& out,

// server/electrum
TEMPLATE
code CLASS::get_balance(stopper& , uint64_t& ,
uint64_t& , const hash_digest& ,
bool ) const NOEXCEPT
code CLASS::get_balance(stopper& cancel, uint64_t& confirmed,
uint64_t& combined, const hash_digest& key, bool turbo) const NOEXCEPT
{
return {};
// See notes on get_unconfirmed_balance().
const auto ec = get_confirmed_balance(cancel, confirmed, key, turbo);
combined = confirmed;
return ec;
}

} // namespace database
Expand Down
10 changes: 7 additions & 3 deletions include/bitcoin/database/impl/query/address/address_history.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,30 @@ namespace database {
// tied-height transactions sorted by base16 txid (not converted).

TEMPLATE
code CLASS::get_unconfirmed_address(stopper& , histories& ,
code CLASS::get_unconfirmed_history(stopper& , histories& ,
const hash_digest& , bool ) const NOEXCEPT
{
return {};
}

TEMPLATE
code CLASS::get_confirmed_address(stopper& , histories& ,
code CLASS::get_confirmed_history(stopper& , histories& ,
const hash_digest& , bool ) const NOEXCEPT
{
return {};
}

TEMPLATE
code CLASS::get_address(stopper& , histories& ,
code CLASS::get_history(stopper& , histories& ,
const hash_digest& , bool ) const NOEXCEPT
{
return {};
}

// turbos
// ----------------------------------------------------------------------------
// protected

} // namespace database
} // namespace libbitcoin

Expand Down
158 changes: 46 additions & 112 deletions include/bitcoin/database/impl/query/address/address_outpoints.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -33,88 +33,44 @@ namespace database {

// server/native
TEMPLATE
code CLASS::get_address_outputs(stopper& cancel, outpoints& out,
const hash_digest& key, bool turbo) const NOEXCEPT
{
if (turbo && store_.turbo())
return get_address_outputs_turbo(cancel, out, key);

out.clear();
for (auto it = store_.address.it(key); it; ++it)
{
if (cancel)
return error::canceled;

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

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

return error::success;
}

// protected
TEMPLATE
code CLASS::get_confirmed_unspent_outputs_turbo(stopper& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT
code CLASS::get_confirmed_unspent_outputs(stopper& cancel,
outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

return parallel_address_transform(cancel, out, links,
return parallel_address_transform(cancel, turbo, out, links,
[this](const auto& link, auto& cancel, auto& fail) NOEXCEPT
{
// !is_confirmed_unspent must be filtered out.
if (cancel || fail || !is_confirmed_unspent(link))
return outpoint{};

auto outpoint = get_spent(link);
fail = (outpoint.point().index() == point::null_index);
auto outpoint = get_outpoint(link);
fail = outpoint.point().is_null();
return outpoint;
});
}

// server/native
TEMPLATE
code CLASS::get_confirmed_unspent_outputs(stopper& cancel,
outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
{
if (turbo && store_.turbo())
return get_confirmed_unspent_outputs_turbo(cancel, out, key);

out.clear();
for (auto it = store_.address.it(key); it; ++it)
{
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.insert(get_spent(address.output_fk));
}

return error::success;
}

// protected
// unused
TEMPLATE
code CLASS::get_minimum_unspent_outputs_turbo(stopper& cancel,
outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT
code CLASS::get_minimum_unspent_outputs(stopper& cancel,
outpoints& out, const hash_digest& key, uint64_t minimum,
bool turbo) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

return parallel_address_transform(cancel, out, links,
return parallel_address_transform(cancel, turbo, out, links,
[this, minimum](const auto& link, auto& cancel, auto& fail) NOEXCEPT
{
// !is_confirmed_unspent must be filtered out.
if (cancel || fail || !is_confirmed_unspent(link))
return outpoint{};

Expand All @@ -125,100 +81,78 @@ code CLASS::get_minimum_unspent_outputs_turbo(stopper& cancel,
return outpoint{};
}

// Must be filtered out.
if (value < minimum)
return outpoint{};

auto outpoint = get_spent(link);
fail = (outpoint.point().index() == point::null_index);
auto outpoint = get_outpoint(link);
fail = outpoint.point().is_null();
return outpoint;
});

return error::success;
}

// unused
// server/native
TEMPLATE
code CLASS::get_minimum_unspent_outputs(stopper& cancel,
outpoints& out, const hash_digest& key, uint64_t minimum,
bool turbo) const NOEXCEPT
code CLASS::get_address_outputs(stopper& cancel, outpoints& out,
const hash_digest& key, bool turbo) const NOEXCEPT
{
if (turbo && store_.turbo())
return get_minimum_unspent_outputs_turbo(cancel, out, key, minimum);

out.clear();
for (auto it = store_.address.it(key); it; ++it)
{
if (cancel)
return error::canceled;

table::address::record address{};
if (!store_.address.get(it, address))
return error::integrity;
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

if (is_confirmed_unspent(address.output_fk))
return parallel_address_transform(cancel, turbo, out, links,
[this](const auto& link, auto& cancel, auto& fail) NOEXCEPT
{
uint64_t value{};
if (!get_value(value, address.output_fk))
return error::integrity;

if (value >= minimum)
out.insert(get_spent(address.output_fk));
}
}
if (cancel || fail) return outpoint{};
auto outpoint = get_outpoint(link);
fail = outpoint.point().is_null();
return outpoint;
});

return error::success;
}

// utilities
// ----------------------------------------------------------------------------

// private/static

TEMPLATE
template <typename Functor>
inline code CLASS::parallel_address_transform(stopper& cancel,
inline code CLASS::parallel_address_transform(stopper& cancel, bool turbo,
outpoints& out, const output_links& links, Functor&& functor) NOEXCEPT
{
constexpr auto parallel = poolstl::execution::par;

out.clear();
stopper fail{};
std::vector<outpoint> outpoints(links.size());
std::transform(parallel, links.begin(), links.end(), outpoints.begin(),
const auto policy = poolstl::execution::par_if(turbo);
std::transform(policy, links.begin(), links.end(), outpoints.begin(),
[&functor, &cancel, &fail](const auto& link) NOEXCEPT
{
return functor(link, cancel, fail);
});

out.clear();
if (fail) return error::integrity;
if (cancel) return error::canceled;
if (fail)
return error::integrity;

if (cancel)
return error::canceled;

for (auto& outpoint: outpoints)
{
if (cancel) return error::canceled;
if (outpoint.point().index() != point::null_index)
if (cancel)
return error::canceled;

// Filter out non-failures.
if (!outpoint.point().is_null())
out.insert(std::move(outpoint));
}

return error::success;
}

// protected
TEMPLATE
code CLASS::get_address_outputs_turbo(stopper& cancel, outpoints& out,
const hash_digest& key) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

return parallel_address_transform(cancel, out, links,
[this](const auto& link, auto& cancel, auto& fail) NOEXCEPT
{
if (cancel || fail) return outpoint{};
auto outpoint = get_spent(link);
fail = (outpoint.point().index() == point::null_index);
return outpoint;
});
}

} // namespace database
} // namespace libbitcoin

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ namespace database {
// Unconfirmed unspent are included at end of list in consistent order.

TEMPLATE
code CLASS::get_unconfirmed_unspent(stopper& , histories& ,
code CLASS::get_unconfirmed_unspent(stopper& , unspents& ,
const hash_digest& , bool ) const NOEXCEPT
{
return {};
}

TEMPLATE
code CLASS::get_confirmed_unspent(stopper& , histories& ,
code CLASS::get_confirmed_unspent(stopper& , unspents& ,
const hash_digest& , bool ) const NOEXCEPT
{
return {};
Expand All @@ -53,6 +53,10 @@ code CLASS::get_unspent(stopper& , unspents& ,
return {};
}

// turbos
// ----------------------------------------------------------------------------
// protected

} // namespace database
} // namespace libbitcoin

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ typename CLASS::inputs_ptr CLASS::get_spenders(
// ----------------------------------------------------------------------------

TEMPLATE
outpoint CLASS::get_spent(const output_link& link) const NOEXCEPT
outpoint CLASS::get_outpoint(const output_link& link) const NOEXCEPT
{
table::output::get_parent_value out{};
if (!store_.output.get(link, out))
Expand Down
4 changes: 2 additions & 2 deletions include/bitcoin/database/impl/query/confirmed.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ point_link CLASS::find_confirmed_spender(const point& prevout) const NOEXCEPT
TEMPLATE
bool CLASS::is_confirmed_unspent(const output_link& link) const NOEXCEPT
{
return is_confirmed_output(link) && !is_spent_output(link);
return is_confirmed_output(link) && !is_confirmed_spent_output(link);
}

TEMPLATE
Expand Down Expand Up @@ -111,7 +111,7 @@ bool CLASS::is_confirmed_output(const output_link& link) const NOEXCEPT
}

TEMPLATE
bool CLASS::is_spent_output(const output_link& link) const NOEXCEPT
bool CLASS::is_confirmed_spent_output(const output_link& link) const NOEXCEPT
{
// The spender is strong *and* its block is confirmed (by height).
const auto ins = to_spenders(link);
Expand Down
Loading
Loading