@@ -698,25 +698,24 @@ bool block::is_unspent_coinbase_collision() const NOEXCEPT
698698 return !txs_->front ()->inputs_ptr ()->front ()->metadata .spent ;
699699}
700700
701- // Search is not ordered , forward references are caught by block.check.
701+ // Search is unordered , forward refs (and duplicates) caught by block.check.
702702bool block::populate (const chain::context& ctx) const NOEXCEPT
703703{
704704 if (txs_->empty ())
705705 return true ;
706706
707- const auto start = std::next (txs_->begin ());
708707 const auto bip68 = ctx.is_enabled (chain::flags::bip68_rule);
709708 unordered_map_of_cref_point_to_output_cptr_cref points{ outputs () };
710709 uint32_t index{};
711710
712- // Populate outputs hash table.
713- for (auto tx = start ; tx != txs_->end (); ++tx, index = 0 )
711+ // Populate outputs hash table (coinbase included) .
712+ for (auto tx = txs_-> begin () ; tx != txs_->end (); ++tx, index = 0 )
714713 for (const auto & out: *(*tx)->outputs_ptr ())
715714 points.emplace (cref_point{ (*tx)->get_hash (false ), index++ }, out);
716715
717716 // Populate input prevouts from hash table and obtain locked state.
718717 auto locked = false ;
719- for (auto tx = start ; tx != txs_->end (); ++tx)
718+ for (auto tx = std::next (txs_-> begin ()) ; tx != txs_->end (); ++tx)
720719 {
721720 for (const auto & in: *(*tx)->inputs_ptr ())
722721 {
@@ -726,8 +725,13 @@ bool block::populate(const chain::context& ctx) const NOEXCEPT
726725
727726 if (point != points.end ())
728727 {
728+ // Zero maturity coinbase spend is treated as locked.
729+ const auto lock = (bip68 && (*tx)->is_internal_lock (*in));
730+ const auto immature = !is_zero (coinbase_maturity) &&
731+ (in->point ().hash () == txs_->front ()->get_hash (false ));
732+
729733 in->prevout = point->second ;
730- in->metadata .locked = bip68 && (*tx)-> is_internal_lock (*in) ;
734+ in->metadata .locked = immature || lock ;
731735 locked |= in->metadata .locked ;
732736 }
733737 }
0 commit comments