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
1 change: 1 addition & 0 deletions builds/gnu/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ include_bitcoin_database_typesdir = \
include_bitcoin_database_types_HEADERS = \
${srcdir}/../../include/bitcoin/database/types/association.hpp \
${srcdir}/../../include/bitcoin/database/types/associations.hpp \
${srcdir}/../../include/bitcoin/database/types/block_amounts.hpp \
${srcdir}/../../include/bitcoin/database/types/block_state.hpp \
${srcdir}/../../include/bitcoin/database/types/difference_set.hpp \
${srcdir}/../../include/bitcoin/database/types/envelope.hpp \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
<ClInclude Include="..\..\..\..\include\bitcoin\database\tables\tables.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\association.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\associations.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_amounts.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_state.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\difference_set.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\envelope.hpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\associations.hpp">
<Filter>include\bitcoin\database\types</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_amounts.hpp">
<Filter>include\bitcoin\database\types</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_state.hpp">
<Filter>include\bitcoin\database\types</Filter>
</ClInclude>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
<ClInclude Include="..\..\..\..\include\bitcoin\database\tables\tables.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\association.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\associations.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_amounts.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_state.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\difference_set.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\envelope.hpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\associations.hpp">
<Filter>include\bitcoin\database\types</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_amounts.hpp">
<Filter>include\bitcoin\database\types</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\database\types\block_state.hpp">
<Filter>include\bitcoin\database\types</Filter>
</ClInclude>
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
#include <bitcoin/database/tables/optionals/filter_tx.hpp>
#include <bitcoin/database/types/association.hpp>
#include <bitcoin/database/types/associations.hpp>
#include <bitcoin/database/types/block_amounts.hpp>
#include <bitcoin/database/types/block_state.hpp>
#include <bitcoin/database/types/difference_set.hpp>
#include <bitcoin/database/types/envelope.hpp>
Expand Down
92 changes: 80 additions & 12 deletions include/bitcoin/database/impl/query/unspent.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,58 @@ bool CLASS::is_bip30_exception(bool& out,
}

TEMPLATE
code CLASS::scan_unspent(difference_set<>& set, const stopper& cancel,
const header_links& branch, bool turbo) const NOEXCEPT
code CLASS::get_block_amounts(block_amounts& out,
const header_link& link) const NOEXCEPT
{
out = {};
auto bip30_exception = false;
if (!is_bip30_exception(bip30_exception, link))
return error::integrity;

auto coinbase = true;
table::output::get_spendable value{};
for (const auto& tx: to_transactions(link))
{
for (const auto& put: to_outputs(tx))
{
if (!store_.output.get(put, value))
return error::integrity;

if (value.unspendable)
out.unspendable += value.value;

if (coinbase)
out.coinbase += value.value;
else
out.outputs += value.value;
}

coinbase = false;
}

// The duplicated coinbase overwrites (destroys) that of the original.
if (bip30_exception)
out.bip30 = out.coinbase;

for (const auto& put: to_block_prevouts(link))
{
if (!store_.output.get(put, value))
return error::integrity;

out.prevouts += value.value;
}

return error::success;
}

TEMPLATE
code CLASS::scan_unspent(difference_set<>& set, unspent_totals& out,
const stopper& cancel, const header_links& branch, bool turbo) const NOEXCEPT
{
using namespace system;
std::atomic_bool fail{};
std::atomic<uint64_t> unspendable{};
std::atomic<uint64_t> overwritten{};
const auto parallel = poolstl::execution::par_if(turbo);

// Reverse order in best effort attempt to minimize set size.
Expand All @@ -92,12 +139,27 @@ code CLASS::scan_unspent(difference_set<>& set, const stopper& cancel,
return;
}

// The bip30 exception blocks are coinbase only.
if (bip30_exception)
return;

auto coinbase = true;
table::output::get_spendable value{};

// The bip30 exception blocks are coinbase only, their duplicated
// outputs overwrite (destroy) those of the original blocks.
if (bip30_exception)
{
for (const auto& tx: to_transactions(link))
for (const auto& out_: to_outputs(tx))
{
if (!store_.output.get(out_, value))
{
fail = true;
return;
}

overwritten += value.value;
}

return;
}
for (const auto& tx: to_transactions(link))
{
if (cancel || fail)
Expand All @@ -112,7 +174,9 @@ code CLASS::scan_unspent(difference_set<>& set, const stopper& cancel,
return;
}

if (!value.unspendable)
if (value.unspendable)
unspendable += value.value;
else
set.toggle(tx, index);

++index;
Expand Down Expand Up @@ -165,6 +229,8 @@ code CLASS::scan_unspent(difference_set<>& set, const stopper& cancel,
if (cancel)
return error::query_canceled;

out.unspendable = unspendable;
out.bip30 = overwritten;
return error::success;
}

Expand All @@ -174,7 +240,6 @@ code CLASS::count_unspent(unspent_totals& out, const stopper& cancel,
{
using namespace system;

out = {};
output_links puts{};
auto previous = max_uint64;
table::output::get_spendable value{};
Expand Down Expand Up @@ -280,20 +345,23 @@ TEMPLATE
code CLASS::get_unspent_totals(const stopper& cancel, unspent_totals& out,
const header_links& branch, bool turbo) const NOEXCEPT
{
out = {};
difference_set<> set{};
const auto ec = scan_unspent(set, cancel, branch, turbo);
const auto ec = scan_unspent(set, out, cancel, branch, turbo);
return ec ? ec : count_unspent(out, cancel, set.drain());
}

TEMPLATE
template <typename Visitor>
code CLASS::get_unspent_coins(const stopper& cancel, const Visitor& visit,
const header_links& branch, bool ordered, bool turbo) const NOEXCEPT
code CLASS::get_unspent_coins(const stopper& cancel, unspent_totals& out,
const Visitor& visit, const header_links& branch, bool ordered,
bool turbo) const NOEXCEPT
{
using namespace system;

out = {};
difference_set<> set{};
if (const auto ec = scan_unspent(set, cancel, branch, turbo))
if (const auto ec = scan_unspent(set, out, cancel, branch, turbo))
return ec;

auto survivors = set.drain();
Expand Down
13 changes: 9 additions & 4 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,10 @@ class query
/// Unspent.
/// -----------------------------------------------------------------------

/// Coin amounts moved by the block.
code get_block_amounts(block_amounts& out,
const header_link& link) const NOEXCEPT;

/// Unspent output totals over the branch (administrative scan).
code get_unspent_totals(const stopper& cancel, unspent_totals& out,
const header_links& branch, bool turbo=false) const NOEXCEPT;
Expand All @@ -783,8 +787,8 @@ class query
/// canonical (txid, index) order as required for utxo set serialization,
/// otherwise unordered (ordering requires a full materialized sort).
template <typename Visitor>
code get_unspent_coins(const stopper& cancel, const Visitor& visit,
const header_links& branch, bool ordered,
code get_unspent_coins(const stopper& cancel, unspent_totals& out,
const Visitor& visit, const header_links& branch, bool ordered,
bool turbo=false) const NOEXCEPT;

protected:
Expand Down Expand Up @@ -989,8 +993,9 @@ class query

bool is_bip30_exception(bool& out,
const header_link& link) const NOEXCEPT;
code scan_unspent(difference_set<>& set, const stopper& cancel,
const header_links& branch, bool turbo) const NOEXCEPT;
code scan_unspent(difference_set<>& set, unspent_totals& out,
const stopper& cancel, const header_links& branch,
bool turbo) const NOEXCEPT;
code count_unspent(unspent_totals& out, const stopper& cancel,
const difference_set<>::entries& survivors) const NOEXCEPT;
template <typename Visitor>
Expand Down
49 changes: 49 additions & 0 deletions include/bitcoin/database/types/block_amounts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2011-2026 libbitcoin developers
*
* This file is part of libbitcoin.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBBITCOIN_DATABASE_TYPES_BLOCK_AMOUNTS_HPP
#define LIBBITCOIN_DATABASE_TYPES_BLOCK_AMOUNTS_HPP

#include <bitcoin/database/define.hpp>

namespace libbitcoin {
namespace database {

/// Coin amounts moved by a single block.
struct BCD_API block_amounts
{
/// Total value of the prevouts spent by the block.
uint64_t prevouts{};

/// Total value of the coinbase outputs.
uint64_t coinbase{};

/// Total value of the non-coinbase outputs.
uint64_t outputs{};

/// Total value of the provably unspendable outputs created.
uint64_t unspendable{};

/// Total value of the coinbase outputs overwritten by bip30 duplication.
uint64_t bip30{};
};

} // namespace database
} // namespace libbitcoin

#endif
1 change: 1 addition & 0 deletions include/bitcoin/database/types/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <bitcoin/database/types/span.hpp>
#include <bitcoin/database/types/tx_state.hpp>
#include <bitcoin/database/types/type.hpp>
#include <bitcoin/database/types/block_amounts.hpp>
#include <bitcoin/database/types/unspent.hpp>
#include <bitcoin/database/types/unspent_coin.hpp>
#include <bitcoin/database/types/unspent_totals.hpp>
Expand Down
6 changes: 6 additions & 0 deletions include/bitcoin/database/types/unspent_totals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ struct BCD_API unspent_totals

/// Total value of unspent outputs.
uint64_t value{};

/// Total value of provably unspendable outputs (excluded from the set).
uint64_t unspendable{};

/// Total value of coinbase outputs overwritten by bip30 duplication.
uint64_t bip30{};
};

} // namespace database
Expand Down
Loading