@@ -304,6 +304,21 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
304304 const auto checked = is_under_checkpoint (height) ||
305305 query.is_milestone (link);
306306
307+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308+ // Failed on block [363353] with block_internal_double_spend (!checked).
309+ // The block object remains in scope during the call, but the pointer owns
310+ // the memory. There is a local pointer object copied above, but it may be
311+ // deleted once it is no longer referenced. This makes the block reference
312+ // below weak. The message pointer object is also held by the calling
313+ // closure, however it can be deleted by the compiler due to subsequent
314+ // non-use. The copied block pointer holds the block object, but it may be
315+ // also deleted if not referenced. Passing a block pointer into check,
316+ // allowing block->check() to be called would resolve that issue, but not
317+ // the issue of calling set_code (see below). But it's not clear how ~block
318+ // could have occured here with query.set_code(*block) pending below.
319+ // It hasn't failed when using a prevout table, which seems unrelated.
320+ // But if it's a race to overwrite freed block memory, it's very possible.
321+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
307322 // Tx commitments and malleation are checked under bypass. Invalidity is
308323 // only stored when a strong header has been stored, later to be found out
309324 // as invalid and not malleable. Stored invalidity prevents repeat
@@ -315,6 +330,11 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
315330 code == system::error::invalid_witness_commitment ||
316331 code == system::error::block_malleated)
317332 {
333+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
334+ // These references to block didn't keep it in scope.
335+ // But because block is const they could precede the check. Could
336+ // be a compiler optimization as these are called by check(true).
337+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
318338 LOGR (" Uncommitted block [" << encode_hash (hash) << " :" << height
319339 << " ] from [" << authority () << " ] " << code.message ()
320340 << " txs(" << block->transactions () << " )"
@@ -323,22 +343,12 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
323343 return false ;
324344 }
325345
326- // TODO: why were we not setting this block as unconfirmable?
327- // //if (code == system::error::forward_reference)
328- // //{
329- // // LOGR("Disordered block [" << encode_hash(hash) << ":" << height
330- // // << " txs(" << block->transactions() << ")"
331- // // << " segregated(" << block->is_segregated() << ").");
332- // // stop(code);
333- // // return false;
334- // //}
335-
336346 // Actual block represented by the hash is unconfirmable.
337347 if (!query.set_block_unconfirmable (link))
338348 {
339349 LOGF (" Failure setting block unconfirmable [" << encode_hash (hash)
340350 << " :" << height << " ] from [" << authority () << " ]." );
341- fault (error::protocol1);
351+ stop ( fault (error::protocol1) );
342352 return false ;
343353 }
344354
@@ -353,6 +363,18 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
353363 // Commit block.txs.
354364 // ........................................................................
355365
366+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
367+ // For early segwit blocks this often fails to set the witness.
368+ // There is no failure code, the witness is just empty and stored empty.
369+ // That causes a validation failure with invalid_witness (!checked).
370+ // It may have also failed in a way that invalidates confirmation queries.
371+ // Passing a block pointer here would only hold the block in scope until
372+ // it iterates transactions, with no subsequent reference. Then transaction
373+ // pointers could hold themselves in scope, however block owns their memory
374+ // and ~block() frees that memory even if the transaction pointer is alive.
375+ // It hasn't failed when using a prevout table, which seems unrelated.
376+ // But if it's a race to overwrite freed block memory, it's very possible.
377+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
356378 // This invokes set_strong when checked.
357379 if (const auto code = query.set_code (*block, link, checked))
358380 {
@@ -363,6 +385,23 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
363385 return false ;
364386 }
365387
388+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
389+ // TODO: verify that ~block() free during contained object access is the
390+ // problem by switching to the default memory allocator w/non-prevout run
391+ // and the code below disabled.
392+ // TODO: pass shared_ptr in to check(block) and set_code(block) from here.
393+ // This may guarantee the pointer (vs. block&) lifetime until return.
394+ // This is an attempt to keep the shared pointer in scope.
395+ // Given that block is const this could also be reordered prior to check().
396+ // But this is not called in this scope, only by message deserialization.
397+ // Passing the block pointer through the store
398+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
399+ if (!block->is_valid ())
400+ {
401+ stop (fault (error::protocol2));
402+ return false ;
403+ }
404+
366405 // Advance.
367406 // ........................................................................
368407
@@ -372,8 +411,10 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
372411 notify (ec, chase::checked, height);
373412 fire (events::block_archived, height);
374413
414+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
375415 // block->serialized_size may keep block in scope during set_code above.
376416 // However the compiler may reorder this calculation since block is const.
417+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
377418 count (block->serialized_size (true ));
378419 map_->erase (it);
379420 if (is_idle ())
0 commit comments