Skip to content

Commit

Permalink
Merge pull request #458 from evoskuil/master
Browse files Browse the repository at this point in the history
Fix error suppression in spend key generation.
  • Loading branch information
evoskuil authored May 3, 2024
2 parents cdd4a55 + 5526a87 commit 03ff133
Show file tree
Hide file tree
Showing 26 changed files with 547 additions and 76 deletions.
9 changes: 9 additions & 0 deletions include/bitcoin/database/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ enum error_t : uint8_t
unload_locked,
unload_failure,

// mmap
disk_full,
mmap_failure,
mremap_failure,
munmap_failure,
madvise_failure,
ftruncate_failure,
fsync_failure,

/// locks
transactor_lock,
process_lock,
Expand Down
15 changes: 15 additions & 0 deletions include/bitcoin/database/impl/primitives/arraymap.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,21 @@ bool CLASS::truncate(const Link& count) NOEXCEPT
return manager_.truncate(count);
}

// error condition
// ----------------------------------------------------------------------------

TEMPLATE
code CLASS::get_error() const NOEXCEPT
{
return manager_.get_error();
}

TEMPLATE
void CLASS::clear_error() NOEXCEPT
{
manager_.clear_error();
}

// query interface
// ----------------------------------------------------------------------------

Expand Down
15 changes: 15 additions & 0 deletions include/bitcoin/database/impl/primitives/hashmap.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,21 @@ Link CLASS::count() const NOEXCEPT
// query interface
// ----------------------------------------------------------------------------

TEMPLATE
code CLASS::get_error() const NOEXCEPT
{
return manager_.get_error();
}

TEMPLATE
void CLASS::clear_error() NOEXCEPT
{
manager_.clear_error();
}

// query interface
// ----------------------------------------------------------------------------

TEMPLATE
Link CLASS::top(const Link& link) const NOEXCEPT
{
Expand Down
15 changes: 15 additions & 0 deletions include/bitcoin/database/impl/primitives/manager.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,21 @@ memory_ptr CLASS::get(const Link& value) const NOEXCEPT
return file_.get(link_to_position(value));
}

// Errors.
// ----------------------------------------------------------------------------

TEMPLATE
code CLASS::get_error() const NOEXCEPT
{
return file_.get_error();
}

TEMPLATE
void CLASS::clear_error() NOEXCEPT
{
file_.clear_error();
}

// private
// ----------------------------------------------------------------------------

Expand Down
87 changes: 53 additions & 34 deletions include/bitcoin/database/impl/query/archive.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -656,25 +656,6 @@ typename CLASS::inputs_ptr CLASS::get_spenders(const tx_link& link,
return get_spenders(to_output(link, output_index));
}

TEMPLATE
inline point_link CLASS::set_link_(const hash_digest& point_hash) NOEXCEPT
{
if (point_hash == system::null_hash)
return {};

// Reuse if archived (always - this is a compression, not a guard).
auto point_fk = to_point(point_hash);
if (!point_fk.is_terminal())
return point_fk;

// This write is NOT transacted as it is only called from set_link(tx)
const table::point::record empty{};
if (!store_.point.put_link(point_fk, point_hash, empty))
return {};

return point_fk;
}

// TODO: rename/change spend to archive table.
// The only multitable write, all archive except header, also address.
TEMPLATE
Expand Down Expand Up @@ -725,14 +706,38 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
// Commit input record.
// Safe allocation failure, blob linked by unindexed spend.
input_link input_fk{};
if (!store_.input.put_link(input_fk, table::input::put_ref{ {}, *in }))
if (!store_.input.put_link(input_fk, table::input::put_ref
{
{},
*in
}))
{
return {};
}

// Create point and accumulate spend keys.
// Safe allocation failure, duplicates are guarded and expected.
// Input point aliases.
const auto& prevout = in->point();
spends.push_back(table::spend::compose(set_link_(prevout.hash()),
prevout.index()));
const auto& hash = prevout.hash();

// Get or create prevout hash in point table (reduces duplicates).
point_link hash_fk{};
if (hash != null_hash)
{
hash_fk = to_point(hash);
if (hash_fk.is_terminal())
{
// Safe allocation failure, duplicates limited but expected.
if (!store_.point.put_link(hash_fk, hash, table::point::record
{
}))
{
return {};
}
}
}

// Accumulate spend keys in order (terminal for any null point).
spends.push_back(table::spend::compose(hash_fk, prevout.index()));

// Write spend record.
// Safe allocation failure, index is deferred because invalid tx_fk.
Expand All @@ -747,7 +752,7 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
return {};
}

// Acumulate input (spend) in order.
// Acumulate spends (input references) in order.
puts.spend_fks.push_back(spend_fk.value++);
}

Expand All @@ -766,7 +771,7 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
return {};
}

// Acumulate output in order.
// Acumulate outputs in order.
puts.out_fks.push_back(output_fk);
}

Expand All @@ -792,10 +797,10 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
}

// Commit spends to search.
// Safe allocation failure, unindexed txs linked by spend, others
// unlinked. A replay of committed spends without indexed tx will appear as
// double spends, but the spend cannot be confirmed without the indexed tx.
// Spends without indexed txs should be suppressed by c/s interface query.
// Safe allocation failure, unindexed txs linked by spend, others unlinked.
// A replay of committed spends without indexed tx will appear as double
// spends, but the spend cannot be confirmed without the indexed tx. Spends
// without indexed txs should be suppressed by c/s interface query.
for (const auto& spend: views_reverse(spends))
{
--spend_fk.value;
Expand Down Expand Up @@ -826,7 +831,7 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
}

// Commit tx to search.
// Clean single allocation failure, see also above. (e.g. disk full).
// Clean single allocation failure (e.g. disk full).
return store_.tx.commit_link(tx_fk, key);
// ========================================================================
}
Expand Down Expand Up @@ -945,13 +950,20 @@ txs_link CLASS::set_link(const transactions& txs,
// ========================================================================
const auto scope = store_.get_transactor();

// Header link is the key for the txs table.
// Clean single allocation failure (e.g. disk full).
return store_.txs.put_link(link, table::txs::slab{ {}, malleable, wire, links });
return store_.txs.put_link(link, table::txs::slab
{
{},
malleable,
wire,
links
});
// ========================================================================
}

TEMPLATE
bool CLASS::dissasociate(const header_link& link) NOEXCEPT
bool CLASS::set_dissasociated(const header_link& link) NOEXCEPT
{
if (link.is_terminal())
return false;
Expand All @@ -961,8 +973,15 @@ bool CLASS::dissasociate(const header_link& link) NOEXCEPT
// ========================================================================
const auto scope = store_.get_transactor();

// Header link is the key for the txs table.
// Clean single allocation failure (e.g. disk full).
return store_.txs.put_link(link, table::txs::slab{ {}, malleable, {}, {} });
return store_.txs.put(link, table::txs::slab
{
{},
malleable,
{},
{}
});
// ========================================================================
}

Expand Down
6 changes: 6 additions & 0 deletions include/bitcoin/database/impl/query/query.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ CLASS::query(Store& value) NOEXCEPT
{
}

TEMPLATE
bool CLASS::is_full() const NOEXCEPT
{
return store_.get_error(error::disk_full);
}

} // namespace database
} // namespace libbitcoin

Expand Down
62 changes: 62 additions & 0 deletions include/bitcoin/database/impl/store.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
// so establish 1 as the minimum value (which also implies disabled).
constexpr auto nonzero = 1_u32;

// public
// ----------------------------------------------------------------------------

TEMPLATE
CLASS::store(const settings& config) NOEXCEPT
: configuration_(config),
Expand Down Expand Up @@ -396,6 +399,65 @@ const typename CLASS::transactor CLASS::get_transactor() NOEXCEPT
return transactor{ transactor_mutex_ };
}

TEMPLATE
bool CLASS::get_error(const code& ec) const NOEXCEPT
{
// A disk full error will not leave a flush lock, but others will.
// There may be other error codes as well so check all.

bool found{};
const auto match = [&ec, &found](const auto& storage) NOEXCEPT
{
const auto error = storage.get_error();
if (error == ec) found = true;
return !error || found;
};

return match(header_body_)
&& match(point_body_)
&& match(input_body_)
&& match(output_body_)
&& match(puts_body_)
&& match(tx_body_)
&& match(txs_body_)
&& match(address_body_)
&& match(candidate_body_)
&& match(confirmed_body_)
&& match(spend_body_)
&& match(strong_tx_body_)
&& match(validated_bk_body_)
&& match(validated_tx_body_)
&& match(neutrino_body_)
////&& match(bootstrap_body_)
////&& match(buffer_body_)
&& found;
}

TEMPLATE
void CLASS::clear_error() NOEXCEPT
{
header_body_.clear_error();
point_body_.clear_error();
input_body_.clear_error();
output_body_.clear_error();
puts_body_.clear_error();
tx_body_.clear_error();
txs_body_.clear_error();
address_body_.clear_error();
candidate_body_.clear_error();
confirmed_body_.clear_error();
spend_body_.clear_error();
strong_tx_body_.clear_error();
validated_bk_body_.clear_error();
validated_tx_body_.clear_error();
neutrino_body_.clear_error();
////bootstrap_body_.clear_error();
////buffer_body_.clear_error();
}

// protected
// ----------------------------------------------------------------------------

TEMPLATE
code CLASS::open_load(const event_handler& handler) NOEXCEPT
{
Expand Down
8 changes: 7 additions & 1 deletion include/bitcoin/database/memory/interfaces/storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class storage
virtual code load() NOEXCEPT = 0;

/// Flush memory map to disk, suspend writes for call, must be loaded.
virtual code flush() const NOEXCEPT = 0;
virtual code flush() NOEXCEPT = 0;

/// Flush, unmap and truncate to logical, restartable, idempotent.
virtual code unload() NOEXCEPT = 0;
Expand All @@ -66,6 +66,12 @@ class storage

/// Get r/w access to start/offset of memory map (or null).
virtual memory_ptr get(size_t offset=zero) const NOEXCEPT = 0;

/// Get the current error condition.
virtual code get_error() const NOEXCEPT = 0;

/// Clear the error condition.
virtual void clear_error() NOEXCEPT = 0;
};

} // namespace database
Expand Down
Loading

0 comments on commit 03ff133

Please sign in to comment.