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

Rem set_txs_connected/set_tx_preconnected, differentiate integrity errors. #542

Merged
merged 3 commits into from
Jan 22, 2025
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/database/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,9 @@ enum error_t : uint8_t

/// validation/confirmation
tx_connected,
tx_preconnected,
tx_disconnected,
block_confirmable,
block_valid,
block_confirmable,
block_unconfirmable,
unassociated,
unvalidated,
Expand Down
13 changes: 11 additions & 2 deletions include/bitcoin/database/impl/query/confirm.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -283,14 +283,18 @@ error::error_t CLASS::spent_prevout(const point_link& link, index index,
// The upside is half the prevout size (read/write/page) and store increase.

// Iterate points by point hash (of output tx) because may be conflicts.
auto point = store_.point.it(get_point_key(link));
// Search key must be passed as an l-value as it is held by reference.
const auto point_sk = get_point_key(link);
auto point = store_.point.it(point_sk);
if (!point)
return error::integrity;

do
{
// Iterate all spends of the point to find double spends.
auto it = store_.spend.it(table::spend::compose(point.self(), index));
// Search key must be passed as an l-value as it is held by reference.
const auto spend_sk = table::spend::compose(point.self(), index);
auto it = store_.spend.it(spend_sk);
if (!it)
return error::success;

Expand Down Expand Up @@ -494,12 +498,14 @@ spend_sets CLASS::to_spend_sets(const header_link& link) const NOEXCEPT
// Coinbase tx does not spend so is not retrieved.
const auto txs = to_spending_transactions(link);

// Empty here is normal.
if (txs.empty())
return {};

spend_sets sets{ txs.size() };
const auto to_set = [this](const auto& tx) NOEXCEPT
{
// Empty here implies integrity fault.
return to_spend_set(tx);
};

Expand Down Expand Up @@ -540,6 +546,7 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
if ((ec = unspent_duplicates(link, ctx)))
return ec;

// Empty here could imply integrity fault.
const auto sets = to_spend_sets(link);
if (sets.empty())
return ec;
Expand Down Expand Up @@ -753,6 +760,8 @@ bool CLASS::initialize(const block& genesis) NOEXCEPT
BC_ASSERT(!is_initialized());
BC_ASSERT(is_one(genesis.transactions_ptr()->size()));

// TODO: add genesis block neutrino head and body when neutrino is enabled.

// ========================================================================
const auto scope = store_.get_transactor();

Expand Down
104 changes: 41 additions & 63 deletions include/bitcoin/database/impl/query/validate.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ inline code CLASS::to_block_code(
{
switch (value)
{
// Block satisfies validation rules (prevouts unverified).
// Transitional: Satisfies validation rules (prevouts unverified).
case schema::block_state::valid:
return error::block_valid;
// Final: Block satisfies confirmation rules (prevouts).
// Final: Satisfies confirmation rules (prevouts confirmable).
case schema::block_state::confirmable:
return error::block_confirmable;
// Final: Block does not satisfy validation/confirmation rules.
// Final: Does not satisfy either validation or confirmation rules.
case schema::block_state::unconfirmable:
return error::block_unconfirmable;
// Block has no recorded state, may be under checkpoint or milestone.
// Fault: Has no state, should not happen when read from store.
default:
return error::unknown_state;
}
Expand All @@ -61,16 +61,13 @@ inline code CLASS::to_tx_code(
// All states below are relevant only to the associated validation context.
switch (value)
{
// Tx is valid in the case where standard prevouts are matched.
case schema::tx_state::preconnected:
return error::tx_preconnected;
// Final: Tx is valid (passed check, accept, and connect).
// Final: Is valid (passed check, accept, and connect).
case schema::tx_state::connected:
return error::tx_connected;
// Final: Tx is not valid (failed check, accept, or connect).
// Final: Is not valid (failed check, accept, or connect).
case schema::tx_state::disconnected:
return error::tx_disconnected;
// Tx has no recorded state, may be under checkpoint or milestone.
// Fault: Has no state, should not happen when read from store.
default:
return error::unknown_state;
}
Expand Down Expand Up @@ -307,25 +304,6 @@ bool CLASS::set_block_unconfirmable(const header_link& link) NOEXCEPT
// ========================================================================
}

TEMPLATE
bool CLASS::set_tx_preconnected(const tx_link& link,
const context& ctx) NOEXCEPT
{
// ========================================================================
const auto scope = store_.get_transactor();

// Clean single allocation failure (e.g. disk full).
return store_.validated_tx.put(link, table::validated_tx::slab
{
{},
ctx,
schema::tx_state::preconnected,
0, // fee
0 // sigops
});
// ========================================================================
}

TEMPLATE
bool CLASS::set_tx_disconnected(const tx_link& link,
const context& ctx) NOEXCEPT
Expand Down Expand Up @@ -367,40 +345,40 @@ bool CLASS::set_tx_connected(const tx_link& link, const context& ctx,
// ========================================================================
}

TEMPLATE
bool CLASS::set_txs_connected(const header_link& link) NOEXCEPT
{
context ctx{};
if (!get_context(ctx, link))
return false;

const auto txs = to_transactions(link);
if (txs.empty())
return false;

// FOR PERFORMANCE EVALUATION ONLY.
constexpr uint64_t fee = 99;
constexpr size_t sigops = 42;
using sigs = linkage<schema::sigops>;

// ========================================================================
const auto scope = store_.get_transactor();

// Clean single allocation failure (e.g. disk full).
return std_all_of(bc::seq, txs.begin(), txs.end(),
[&](const tx_link& fk) NOEXCEPT
{
return store_.validated_tx.put(fk, table::validated_tx::slab
{
{},
ctx,
schema::tx_state::connected,
fee,
system::possible_narrow_cast<sigs::integer>(sigops)
});
});
// ========================================================================
}
////TEMPLATE
////bool CLASS::set_txs_connected(const header_link& link) NOEXCEPT
////{
//// context ctx{};
//// if (!get_context(ctx, link))
//// return false;
////
//// const auto txs = to_transactions(link);
//// if (txs.empty())
//// return false;
////
//// // FOR PERFORMANCE EVALUATION ONLY.
//// constexpr uint64_t fee = 99;
//// constexpr size_t sigops = 42;
//// using sigs = linkage<schema::sigops>;
////
//// // ========================================================================
//// const auto scope = store_.get_transactor();
////
//// // Clean single allocation failure (e.g. disk full).
//// return std_all_of(bc::seq, txs.begin(), txs.end(),
//// [&](const tx_link& fk) NOEXCEPT
//// {
//// return store_.validated_tx.put(fk, table::validated_tx::slab
//// {
//// {},
//// ctx,
//// schema::tx_state::connected,
//// fee,
//// system::possible_narrow_cast<sigs::integer>(sigops)
//// });
//// });
//// // ========================================================================
////}

} // namespace database
} // namespace libbitcoin
Expand Down
11 changes: 4 additions & 7 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,10 +478,6 @@ class query
bool set_block_valid(const header_link& link, uint64_t fees) NOEXCEPT;
bool set_block_unconfirmable(const header_link& link) NOEXCEPT;
bool set_block_confirmable(const header_link& link) NOEXCEPT;

// set_txs_connected is FOR PERFORMANCE EVALUATION ONLY.
bool set_txs_connected(const header_link& link) NOEXCEPT;
bool set_tx_preconnected(const tx_link& link, const context& ctx) NOEXCEPT;
bool set_tx_disconnected(const tx_link& link, const context& ctx) NOEXCEPT;
bool set_tx_connected(const tx_link& link, const context& ctx,
uint64_t fee, size_t sigops) NOEXCEPT;
Expand Down Expand Up @@ -547,13 +543,14 @@ class query
bool set_filter_head(const header_link& link,
const hash_digest& head) NOEXCEPT;

// TODO: protected
spend_set to_spend_set(const tx_link& link) const NOEXCEPT;
spend_sets to_spend_sets(const header_link& link) const NOEXCEPT;

protected:
/// Translate.
/// -----------------------------------------------------------------------

spend_set to_spend_set(const tx_link& link) const NOEXCEPT;
spend_sets to_spend_sets(const header_link& link) const NOEXCEPT;

uint32_t to_spend_index(const tx_link& parent_fk,
const spend_link& input_fk) const NOEXCEPT;
uint32_t to_output_index(const tx_link& parent_fk,
Expand Down
12 changes: 5 additions & 7 deletions include/bitcoin/database/tables/schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ namespace schema
constexpr auto candidate = "candidate";
constexpr auto confirmed = "confirmed";
constexpr auto strong_tx = "strong_tx";
////constexpr auto spent_out = "spent_out";
}

namespace caches
Expand Down Expand Up @@ -89,16 +88,15 @@ namespace schema

enum block_state : uint8_t
{
confirmable = 0, // final
valid = 1, // transitional
unconfirmable = 2 // final
confirmable = 0, // final
valid = 1, // transitional
unconfirmable = 2 // final
};

enum tx_state : uint8_t
{
connected = 0, // final
preconnected = 1, // transitional
disconnected = 2 // final
connected = 0, // final
disconnected = 1 // final
};

/// Values.
Expand Down
3 changes: 1 addition & 2 deletions src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,9 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)

// states
{ tx_connected, "transaction connected" },
{ tx_preconnected, "transaction preconnected" },
{ tx_disconnected, "transaction disconnected" },
{ block_confirmable, "block confirmable" },
{ block_valid, "block valid" },
{ block_confirmable, "block confirmable" },
{ block_unconfirmable, "block unconfirmable" },
{ unassociated, "unassociated" },
{ unvalidated, "unvalidated" },
Expand Down
21 changes: 6 additions & 15 deletions test/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,15 +365,6 @@ BOOST_AUTO_TEST_CASE(error_t__code__tx_connected__true_exected_message)
BOOST_REQUIRE_EQUAL(ec.message(), "transaction connected");
}

BOOST_AUTO_TEST_CASE(error_t__code__tx_preconnected__true_exected_message)
{
constexpr auto value = error::tx_preconnected;
const auto ec = code(value);
BOOST_REQUIRE(ec);
BOOST_REQUIRE(ec == value);
BOOST_REQUIRE_EQUAL(ec.message(), "transaction preconnected");
}

BOOST_AUTO_TEST_CASE(error_t__code__tx_disconnected__true_exected_message)
{
constexpr auto value = error::tx_disconnected;
Expand All @@ -383,22 +374,22 @@ BOOST_AUTO_TEST_CASE(error_t__code__tx_disconnected__true_exected_message)
BOOST_REQUIRE_EQUAL(ec.message(), "transaction disconnected");
}

BOOST_AUTO_TEST_CASE(error_t__code__block_confirmable__true_exected_message)
BOOST_AUTO_TEST_CASE(error_t__code__block_valid__true_exected_message)
{
constexpr auto value = error::block_confirmable;
constexpr auto value = error::block_valid;
const auto ec = code(value);
BOOST_REQUIRE(ec);
BOOST_REQUIRE(ec == value);
BOOST_REQUIRE_EQUAL(ec.message(), "block confirmable");
BOOST_REQUIRE_EQUAL(ec.message(), "block valid");
}

BOOST_AUTO_TEST_CASE(error_t__code__block_valid__true_exected_message)
BOOST_AUTO_TEST_CASE(error_t__code__block_confirmable__true_exected_message)
{
constexpr auto value = error::block_valid;
constexpr auto value = error::block_confirmable;
const auto ec = code(value);
BOOST_REQUIRE(ec);
BOOST_REQUIRE(ec == value);
BOOST_REQUIRE_EQUAL(ec.message(), "block valid");
BOOST_REQUIRE_EQUAL(ec.message(), "block confirmable");
}

BOOST_AUTO_TEST_CASE(error_t__code__block_unconfirmable__true_exected_message)
Expand Down
22 changes: 0 additions & 22 deletions test/query/validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,28 +349,6 @@ BOOST_AUTO_TEST_CASE(query_validate__get_tx_state__connected_in_context__tx_conn
BOOST_REQUIRE_EQUAL(sigops, expected_sigops);
}

BOOST_AUTO_TEST_CASE(query_validate__get_tx_state__connected_in_context__tx_preconnected)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));
BOOST_REQUIRE(query.set(test::block1, context{}, false, false));
BOOST_REQUIRE(query.set(test::block2, context{}, false, false));
BOOST_REQUIRE(query.set(test::block3, context{}, false, false));

uint64_t fee{};
size_t sigops{};
constexpr context ctx{ 7, 8, 9 };
BOOST_REQUIRE(query.set_tx_preconnected(3, ctx));
BOOST_REQUIRE_EQUAL(query.get_tx_state(3, ctx), error::tx_preconnected);
BOOST_REQUIRE_EQUAL(query.get_tx_state(fee, sigops, 3, ctx), error::tx_preconnected);
BOOST_REQUIRE_EQUAL(fee, 0u);
BOOST_REQUIRE_EQUAL(sigops, 0u);
}

BOOST_AUTO_TEST_CASE(query_validate__get_tx_state__connected_in_context__tx_disconnected)
{
settings settings{};
Expand Down
Loading