Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change block.populate() to allow forward refs and own coinbase ref. #1408

Merged
merged 3 commits into from
Feb 24, 2024
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: 1 addition & 2 deletions include/bitcoin/system/chain/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ class BC_API block
code connect(const context& ctx) const NOEXCEPT;
code confirm(const context& ctx) const NOEXCEPT;

/// Populate previous output metadata internal to the block.
/// Does not populate forward references (consensus limited).
/// Populate previous outputs (only, no metadata) internal to the block.
void populate() const NOEXCEPT;

protected:
Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/system/chain/prevout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class BC_API prevout final
/// For a non-coinbase input this indicates spent at height.
bool spent{ true };

// The output is of a coinbase transaction.
/// The output is of a coinbase transaction.
bool coinbase{ false };
};

Expand Down
51 changes: 18 additions & 33 deletions src/chain/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,48 +564,32 @@ bool block::is_unspent_coinbase_collision() const NOEXCEPT
if (txs_->empty() || txs_->front()->inputs_ptr()->empty())
return false;

// May only commit duplicate coinbase that is already confirmed spent.
// May only commit duplicate coinbase that is already confirmed spent.
// Metadata population defaults coinbase to spent (not a collision).
return !txs_->front()->inputs_ptr()->front()->metadata.spent;
}

// Search is not ordered, forward references are caught by block.check.
void block::populate() const NOEXCEPT
{
// Coinbase, outputs only, inputs only.
if (txs_->size() < 3u)
return;

BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
std::unordered_map<point, output::cptr> map{};

// Skip coinbase tx.
auto tx = std::next(txs_->begin());
std::unordered_map<point, output::cptr> points{};
uint32_t index{};

// Outputs only (first tx).
for (const auto& out: *(*tx)->outputs_ptr())
map.emplace(point{ (*tx)->hash(false), index++ }, out);
// Populate outputs hash table.
for (auto tx = txs_->begin(); tx != txs_->end(); ++tx, index = 0)
for (const auto& out: *(*tx)->outputs_ptr())
points.emplace(point{ (*tx)->hash(false), index++ }, out);

// Search is ordered, no forward references or coinbase spend (consensus).
for (++tx; tx != std::prev(txs_->end()); ++tx)
// Populate input prevouts from hash table.
for (auto tx = txs_->begin(); tx != txs_->end(); ++tx)
{
for (const auto& in: *(*tx)->inputs_ptr())
{
const auto element = map.find(in->point());
if (element != map.end())
in->prevout = element->second;
const auto point = points.find(in->point());
if (point != points.end())
in->prevout = point->second;
}

index = 0;
for (const auto& out: *(*tx)->outputs_ptr())
map.emplace(point{ (*tx)->hash(false), index++ }, out);
}

// Inputs only (last tx).
for (const auto& in: *(*tx)->inputs_ptr())
{
const auto element = map.find(in->point());
if (element != map.end())
in->prevout = element->second;
}

BC_POP_WARNING()
Expand Down Expand Up @@ -668,10 +652,11 @@ code block::connect_transactions(const context& ctx) const NOEXCEPT
code block::confirm_transactions(const context& ctx) const NOEXCEPT
{
code ec;

for (auto tx = std::next(txs_->begin()); tx != txs_->end(); ++tx)
if ((ec = (*tx)->confirm(ctx)))
return ec;

if (!is_empty())
for (auto tx = std::next(txs_->begin()); tx != txs_->end(); ++tx)
if ((ec = (*tx)->confirm(ctx)))
return ec;

return error::block_success;
}
Expand Down
6 changes: 3 additions & 3 deletions src/chain/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1284,7 +1284,7 @@ code transaction::accept(const context&) const NOEXCEPT

// Do NOT invoke on coinbase.
// Node performs these checks through database query.
// This assume that prevout and metadata caching are completed on all inputs.
// This assumes that prevout and metadata caching are completed on all inputs.
code transaction::confirm(const context& ctx) const NOEXCEPT
{
BC_ASSERT(!is_coinbase());
Expand Down Expand Up @@ -1312,8 +1312,8 @@ code transaction::connect(const context& ctx) const NOEXCEPT
{
BC_ASSERT(!is_coinbase());

////if (is_coinbase())
//// return error::transaction_success;
if (is_coinbase())
return error::transaction_success;

code ec;
using namespace machine;
Expand Down
Loading