Skip to content

Commit fb94c79

Browse files
committed
Revert to full parallel confirm.
1 parent 5e9d38e commit fb94c79

3 files changed

Lines changed: 79 additions & 119 deletions

File tree

include/bitcoin/database/error.hpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,6 @@ enum error_t : uint8_t
4747
integrity8,
4848
integrity9,
4949
integrity10,
50-
integrity11,
51-
integrity12,
52-
integrity13,
53-
integrity14,
54-
integrity15,
55-
integrity16,
56-
integrity17,
5750

5851
/// memory map
5952
open_open,

include/bitcoin/database/impl/query/consensus.ipp

Lines changed: 79 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -148,35 +148,29 @@ code CLASS::unspent_duplicates(const header_link& link,
148148
if (!ctx.is_enabled(system::chain::flags::bip30_rule))
149149
return error::success;
150150

151-
// Get the block's first tx link.
151+
// Get coinbase (block's first tx link).
152152
const auto cb = to_coinbase(link);
153153
if (cb.is_terminal())
154154
return error::integrity1;
155155

156-
// TODO: deadlock risk.
157-
// Iterate all strong records for each tx link of the same hash.
158-
// The same link may be the coinbase for more than one block.
159-
// Distinct links may be the coinbase for independent blocks.
160-
// Duplicate instances of a tx (including cb) may exist because of a race.
161-
// Strong records for a link may be reorganized and again organized.
156+
// Get all coinbases (must be at least one, because self).
162157
auto it = store_.tx.it(get_tx_key(cb));
163158
if (!it)
164159
return error::integrity2;
165160

166-
// TODO: avoid nested iterators. accumulate set of tx_links and iterate set
167-
// TODO: after releasing the initial iterator.
168161
tx_links coinbases{};
169-
do
170-
{
171-
for (const auto& tx: get_strong_txs(it.self()))
172-
coinbases.push_back(tx);
173-
}
174-
while (it.advance());
162+
coinbases.reserve(one);
163+
do { coinbases.push_back(it.self()); } while (it.advance());
175164
it.reset();
176-
177-
// Current block is set strong, so self is expected.
178-
if (is_one(coinbases.size()))
179-
return error::success;
165+
166+
// Get all strong coinbases.
167+
tx_links strong_coinbases{};
168+
strong_coinbases.reserve(one);
169+
for (const auto& tx: coinbases)
170+
if (is_strong_tx(tx))
171+
strong_coinbases.push_back(tx);
172+
173+
// Strong must be other blocks, dis/re-orged blocks are not strong.
180174

181175
// Remove self (will be not found if current block is not set_strong).
182176
const auto self = std::find(coinbases.begin(), coinbases.end(), link);
@@ -193,83 +187,6 @@ code CLASS::unspent_duplicates(const header_link& link,
193187
return error::success;
194188
}
195189

196-
// get_double_spenders
197-
// ----------------------------------------------------------------------------
198-
// called from validation to set prevout state
199-
200-
// protected
201-
TEMPLATE
202-
code CLASS::push_spenders(tx_links& out, const point& point,
203-
const point_link& self) const NOEXCEPT
204-
{
205-
auto it = store_.point.it(table::point::compose(point));
206-
if (!it)
207-
{
208-
// This verified that there was a race condition in the intial hashmap
209-
// memory fence implementation, manifesting above as not found, where
210-
// immediately after (below) the same object was found. Now fixed.
211-
////const auto key1 = it.key();
212-
////const auto link1 = it.self();
213-
////const auto get1 = it.get();
214-
////it.reset();
215-
////
216-
////if (key1 != table::point::compose(point))
217-
//// return error::integrity12;
218-
////if (!link1.is_terminal())
219-
//// return error::integrity13;
220-
////if (is_null(get1))
221-
//// return error::integrity14;
222-
////
223-
////table::point::record get{};
224-
////if (!store_.point.get(self, get))
225-
//// return error::integrity15;
226-
////if (get.hash != point.hash())
227-
//// return error::integrity16;
228-
////if (get.index != point.index())
229-
//// return error::integrity17;
230-
231-
return error::integrity4;
232-
}
233-
234-
point_links points{};
235-
do
236-
{
237-
if (it.self() != self)
238-
points.push_back(it.self());
239-
}
240-
while (it.advance());
241-
it.reset();
242-
243-
for (auto link: points)
244-
{
245-
table::ins::get_parent get{};
246-
if (!store_.ins.get(link, get))
247-
return error::integrity5;
248-
249-
out.push_back(get.parent_fk);
250-
}
251-
252-
return error::success;
253-
}
254-
255-
TEMPLATE
256-
code CLASS::get_double_spenders(tx_links& out,
257-
const block& block) const NOEXCEPT
258-
{
259-
// Empty or coinbase only implies no spends.
260-
const auto& txs = *block.transactions_ptr();
261-
if (txs.size() <= one)
262-
return error::success;
263-
264-
code ec{};
265-
for (auto tx = std::next(txs.begin()); tx != txs.end(); ++tx)
266-
for (const auto& in: *(*tx)->inputs_ptr())
267-
if ((ec = push_spenders(out, in->point(), in->metadata.link)))
268-
return ec;
269-
270-
return error::success;
271-
}
272-
273190
// unspendable
274191
// ----------------------------------------------------------------------------
275192

@@ -297,7 +214,7 @@ error::error_t CLASS::unspendable(uint32_t sequence, bool coinbase,
297214
{
298215
context out{};
299216
if (!get_context(out, strong))
300-
return error::integrity7;
217+
return error::integrity4;
301218

302219
if (relative &&
303220
input::is_locked(sequence, ctx.height, ctx.mtp, out.height, out.mtp))
@@ -325,12 +242,14 @@ code CLASS::populate_prevouts(point_sets& sets, size_t points,
325242
table::prevout::slab_get cache{};
326243
cache.spends.resize(points);
327244
if (!store_.prevout.at(link, cache))
328-
return error::integrity8;
245+
return error::integrity5;
329246

247+
// The conflicts list is generally empty.
330248
for (const auto& spender: cache.conflicts)
331249
if (is_strong_tx(spender))
332250
return error::confirmed_double_spend;
333251

252+
// Augments spend.points with metadata.
334253
auto it = cache.spends.begin();
335254
for (auto& set: sets)
336255
for (auto& point: set.points)
@@ -354,12 +273,12 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
354273

355274
context ctx{};
356275
if (!get_context(ctx, link))
357-
return error::integrity9;
276+
return error::integrity6;
358277

359278
// bip30 coinbase check.
360279
code ec{};
361-
////if ((ec = unspent_duplicates(link, ctx)))
362-
//// return ec;
280+
if ((ec = unspent_duplicates(link, ctx)))
281+
return ec;
363282

364283
// Empty block is success.
365284
const auto txs = to_spending_txs(link);
@@ -376,17 +295,18 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
376295
point_set set{};
377296
table::transaction::get_set_ref get{ {}, set };
378297
if (!store_.tx.get(tx, get))
379-
failure.store(error::integrity10);
298+
failure.store(error::integrity7);
380299

381300
points.fetch_add(set.points.size(), std::memory_order_relaxed);
382301
return set;
383302
};
384303

304+
// Get points for each tx, and sum the total number.
385305
std::transform(parallel, txs.begin(), txs.end(), sets.begin(), to_set);
386306
if (failure)
387307
return { failure.load() };
388308

389-
// Checks for double spends and populates prevout parent tx/cb links.
309+
// Check double spends strength, populates prevout parent tx/cb/sq links.
390310
if ((ec = populate_prevouts(sets, points, link)))
391311
return ec;
392312

@@ -401,13 +321,14 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
401321
return failure != error::success;
402322
};
403323

324+
// Check all spends for spendability (strong, unlocked and mature).
404325
if (std::any_of(parallel, sets.begin(), sets.end(), is_unspendable))
405326
return { failure.load() };
406327

407328
return error::success;
408329
}
409330

410-
// setters
331+
// set_strong
411332
// ----------------------------------------------------------------------------
412333

413334
// protected
@@ -493,6 +414,59 @@ bool CLASS::set_unstrong(const header_link& link) NOEXCEPT
493414
// ========================================================================
494415
}
495416

417+
// set_prevouts
418+
// ----------------------------------------------------------------------------
419+
// called from validation to set prevout state
420+
421+
// protected
422+
TEMPLATE
423+
code CLASS::push_spenders(tx_links& out, const point& point,
424+
const point_link& self) const NOEXCEPT
425+
{
426+
// This is most of the expense of confirmation.
427+
auto it = store_.point.it(table::point::compose(point));
428+
if (!it)
429+
return error::integrity8;
430+
431+
point_links points{};
432+
do
433+
{
434+
if (it.self() != self)
435+
points.push_back(it.self());
436+
}
437+
while (it.advance());
438+
it.reset();
439+
440+
for (auto link: points)
441+
{
442+
table::ins::get_parent get{};
443+
if (!store_.ins.get(link, get))
444+
return error::integrity9;
445+
446+
out.push_back(get.parent_fk);
447+
}
448+
449+
return error::success;
450+
}
451+
452+
TEMPLATE
453+
code CLASS::get_double_spenders(tx_links& out,
454+
const block& block) const NOEXCEPT
455+
{
456+
// Empty or coinbase only implies no spends.
457+
const auto& txs = *block.transactions_ptr();
458+
if (txs.size() <= one)
459+
return error::success;
460+
461+
code ec{};
462+
for (auto tx = std::next(txs.begin()); tx != txs.end(); ++tx)
463+
for (const auto& in: *(*tx)->inputs_ptr())
464+
if ((ec = push_spenders(out, in->point(), in->metadata.link)))
465+
return ec;
466+
467+
return error::success;
468+
}
469+
496470
TEMPLATE
497471
code CLASS::set_prevouts(const header_link& link, const block& block) NOEXCEPT
498472
{
@@ -507,7 +481,7 @@ code CLASS::set_prevouts(const header_link& link, const block& block) NOEXCEPT
507481
// Clean single allocation failure (e.g. disk full).
508482
const table::prevout::slab_put_ref prevouts{ {}, spenders, block };
509483
return store_.prevout.put(link, prevouts) ? error::success :
510-
error::integrity11;
484+
error::integrity10;
511485
// ========================================================================
512486
}
513487

src/error.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
4040
{ integrity8, "store corrupted8" },
4141
{ integrity9, "store corrupted9" },
4242
{ integrity10, "store corrupted10" },
43-
{ integrity11, "store corrupted11" },
44-
{ integrity12, "store corrupted12" },
45-
{ integrity13, "store corrupted13" },
46-
{ integrity14, "store corrupted14" },
47-
{ integrity15, "store corrupted15" },
48-
{ integrity16, "store corrupted16" },
49-
{ integrity17, "store corrupted17" },
5043

5144
// memory map
5245
{ open_open, "opening open file" },

0 commit comments

Comments
 (0)