diff --git a/include/bitcoin/database/impl/query/confirm.ipp b/include/bitcoin/database/impl/query/confirm.ipp index fee07e7ea..63142950b 100644 --- a/include/bitcoin/database/impl/query/confirm.ipp +++ b/include/bitcoin/database/impl/query/confirm.ipp @@ -710,6 +710,10 @@ bool CLASS::set_unstrong(const header_link& link) NOEXCEPT TEMPLATE bool CLASS::set_prevouts(size_t height, const block& block) NOEXCEPT { + // Empty or coinbase only implies no spends. + if (block.transactions() <= one) + return true; + // ======================================================================== const auto scope = store_.get_transactor(); diff --git a/include/bitcoin/database/tables/caches/prevout.hpp b/include/bitcoin/database/tables/caches/prevout.hpp index bf3da50af..d2757177a 100644 --- a/include/bitcoin/database/tables/caches/prevout.hpp +++ b/include/bitcoin/database/tables/caches/prevout.hpp @@ -103,31 +103,24 @@ struct prevout inline bool to_data(finalizer& sink) const NOEXCEPT { const auto txs = *block.transactions_ptr(); - if (txs.size() <= one) - { - // Empty or coinbase only implies no spends. - sink.invalidate(); - } - else - { - const auto write_spend = [&](const auto& in) NOEXCEPT - { - // Sets terminal sentinel for block-internal spends. - const auto value = in->metadata.inside ? tx::terminal : - merge(in->metadata.coinbase, in->metadata.parent); + BC_ASSERT_MSG(txs.size() > one, "empty block"); - sink.write_little_endian(value); - }; + const auto write_spend = [&](const auto& in) NOEXCEPT + { + // Sets terminal sentinel for block-internal spends. + const auto value = in->metadata.inside ? tx::terminal : + merge(in->metadata.coinbase, in->metadata.parent); - const auto write_tx = [&](const auto& tx) NOEXCEPT - { - const auto& ins = tx->inputs_ptr(); - return std::for_each(ins->begin(), ins->end(), write_spend); - }; + sink.write_little_endian(value); + }; - std::for_each(std::next(txs.begin()), txs.end(), write_tx); - } + const auto write_tx = [&](const auto& tx) NOEXCEPT + { + const auto& ins = tx->inputs_ptr(); + return std::for_each(ins->begin(), ins->end(), write_spend); + }; + std::for_each(std::next(txs.begin()), txs.end(), write_tx); BC_ASSERT(!sink || (sink.get_write_position() == count() * minrow)); return sink; } diff --git a/test/tables/caches/prevout.cpp b/test/tables/caches/prevout.cpp index e80582c7c..1ad2c1cfd 100644 --- a/test/tables/caches/prevout.cpp +++ b/test/tables/caches/prevout.cpp @@ -264,17 +264,18 @@ BOOST_AUTO_TEST_CASE(prevout__put__merged_values__expected) // record_put_ref -BOOST_AUTO_TEST_CASE(prevout__record_put_ref__empty_block__false) -{ - test::chunk_storage head_store{}; - test::chunk_storage body_store{}; - table::prevout instance{ head_store, body_store, 5 }; - BOOST_REQUIRE(instance.create()); - - const auto genesis = system::settings(selection::mainnet).genesis_block; - const auto record = table::prevout::record_put_ref{ {}, genesis }; - BOOST_REQUIRE(!instance.put(4, record)); -} +// Empty block is now guarded at the query level (set_prevouts(...)). +////BOOST_AUTO_TEST_CASE(prevout__record_put_ref__empty_block__false) +////{ +//// test::chunk_storage head_store{}; +//// test::chunk_storage body_store{}; +//// table::prevout instance{ head_store, body_store, 5 }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const auto genesis = system::settings(selection::mainnet).genesis_block; +//// const auto record = table::prevout::record_put_ref{ {}, genesis }; +//// BOOST_REQUIRE(!instance.put(4, record)); +////} BOOST_AUTO_TEST_CASE(prevout__put_ref__get_non_empty_block_with_default_metadata__inside_spend_terminals) {