diff --git a/console/executor.cpp b/console/executor.cpp index 8a056d75..b1c1dfac 100644 --- a/console/executor.cpp +++ b/console/executor.cpp @@ -972,67 +972,69 @@ void executor::read_test() const outs.size() % keys.size() % span.count()); // Write it all... - ////logger( - //// "output_script_hash, " - //// "output_fk, " - //// "spend_fk, " - //// "input_fk, " - //// - //// "ouput_tx_fk, " - //// "ouput_tx_hash, " - //// "ouput_tx_pos, " - //// - //// "ouput_bk_fk, " - //// "ouput_bk_hash, " - //// "ouput_bk_height, " - //// - //// "input_tx_fk, " - //// "input_tx_hash, " - //// "input_tx_pos, " - //// - //// "input_bk_fk, " - //// "input_bk_hash, " - //// "sinput_bk_height, " - //// - //// "output_script " - //// "input_script, " - ////); - //// - ////for (const auto& row: outs) - ////{ - //// if (cancel_) break; - //// - //// const auto input = !row.input ? "{unspent}" : - //// row.input->script().to_string(chain::flags::all_rules); - //// - //// const auto output = !row.output ? "{error}" : - //// row.output->script().to_string(chain::flags::all_rules); - //// - //// logger(format("%1%, %2%, %3%, %4%, %5%, %6%, %7%, %8%, %9%, %10%, %11%, %12%, %13%, %14%, %15%, %16%, %17%, %18%") % - //// encode_hash(row.address) % - //// row.output_fk % - //// row.spend_fk% - //// row.input_fk% - //// - //// row.tx_fk % - //// encode_hash(row.tx_hash) % - //// row.tx_position % - //// - //// row.bk_fk % - //// encode_hash(row.bk_hash) % - //// row.bk_height % - //// - //// row.in_tx_fk % - //// encode_hash(row.in_tx_hash) % - //// row.in_tx_position % - //// - //// row.in_bk_fk % - //// encode_hash(row.in_bk_hash) % - //// row.in_bk_height % - //// - //// output% - //// input); - ////} +#if defined(UNDEFINED) + logger( + "output_script_hash, " + "output_fk, " + "spend_fk, " + "input_fk, " + + "ouput_tx_fk, " + "ouput_tx_hash, " + "ouput_tx_pos, " + + "ouput_bk_fk, " + "ouput_bk_hash, " + "ouput_bk_height, " + + "input_tx_fk, " + "input_tx_hash, " + "input_tx_pos, " + + "input_bk_fk, " + "input_bk_hash, " + "sinput_bk_height, " + + "output_script " + "input_script, " + ); + + for (const auto& row: outs) + { + if (cancel_) break; + + const auto input = !row.input ? "{unspent}" : + row.input->script().to_string(chain::flags::all_rules); + + const auto output = !row.output ? "{error}" : + row.output->script().to_string(chain::flags::all_rules); + + logger(format("%1%, %2%, %3%, %4%, %5%, %6%, %7%, %8%, %9%, %10%, %11%, %12%, %13%, %14%, %15%, %16%, %17%, %18%") % + encode_hash(row.address) % + row.output_fk % + row.spend_fk% + row.input_fk% + + row.tx_fk % + encode_hash(row.tx_hash) % + row.tx_position % + + row.bk_fk % + encode_hash(row.bk_hash) % + row.bk_height % + + row.in_tx_fk % + encode_hash(row.in_tx_hash) % + row.in_tx_position % + + row.in_bk_fk % + encode_hash(row.in_bk_hash) % + row.in_bk_height % + + output% + input); + } +#endif // UNDEFINED } #if defined(UNDEFINED) diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp index 89c636b3..1ae6db77 100644 --- a/include/bitcoin/node/chasers/chaser_confirm.hpp +++ b/include/bitcoin/node/chasers/chaser_confirm.hpp @@ -47,6 +47,7 @@ class BCN_API chaser_confirm event_value value) NOEXCEPT; virtual void do_validated(height_t height) NOEXCEPT; +#if defined(UNDEFINED) virtual void do_organize(size_t height) NOEXCEPT; virtual bool enqueue_block(const database::header_link& link) NOEXCEPT; virtual void confirm_tx(const database::context& ctx, @@ -57,6 +58,7 @@ class BCN_API chaser_confirm const database::header_link& link, size_t height)NOEXCEPT; virtual void confirm_block(const code& ec, const database::header_link& link, size_t height) NOEXCEPT; +#endif // UNDEFINED private: bool set_organized(const database::header_link& link, diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 4784cadb..e01d4936 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -91,6 +91,191 @@ bool chaser_confirm::handle_event(const code&, chase event_, // confirm // ---------------------------------------------------------------------------- +void chaser_confirm::do_validated(height_t height) NOEXCEPT +{ + BC_ASSERT(stranded()); + + if (closed()) + return; + + // TODO: update specialized fault codes. + + // Compute relative work. + // ........................................................................ + + bool strong{}; + uint256_t work{}; + header_links fork{}; + + if (!get_fork_work(work, fork, height)) + { + fault(error::get_fork_work); + return; + } + + if (!get_is_strong(strong, work, height)) + { + fault(error::get_is_strong); + return; + } + + if (!strong) + return; + + // Reorganize confirmed chain. + // ........................................................................ + + auto& query = archive(); + const auto top = query.get_top_confirmed(); + const auto fork_point = height - fork.size(); + if (top < fork_point) + { + fault(error::invalid_fork_point); + return; + } + + // Pop down to the fork point. + auto index = top; + header_links popped{}; + while (index > fork_point) + { + const auto link = query.to_confirmed(index); + if (link.is_terminal()) + { + fault(error::to_confirmed); + return; + } + + popped.push_back(link); + if (!query.set_unstrong(link)) + { + fault(error::node_confirm); + return; + } + + if (!query.pop_confirmed()) + { + fault(error::pop_confirmed); + return; + } + + notify(error::success, chase::reorganized, popped.back()); + fire(events::block_reorganized, index--); + } + + // Above may shrink indexes and below may cancel. + // This may result in an inability to restore. + // TODO: copy height indexes in backup. + + // fork_point + 1 + ++index; + + // Push candidate headers to confirmed chain. + for (const auto& link: views_reverse(fork)) + { + if (closed()) + return; + + auto ec = query.get_block_state(link); + if (ec == database::error::integrity) + { + fault(ec); + return; + } + + if (ec == database::error::block_unconfirmable) + { + notify(ec, chase::unconfirmable, link); + fire(events::block_unconfirmable, index); + + if (!roll_back(popped, link, fork_point, index)) + fault(error::node_roll_back); + + return; + } + + const auto checked = is_under_checkpoint(index) || + query.is_milestone(link); + + // Required for block_confirmable and all confirmed blocks. + if (!checked && !query.set_strong(link)) + { + fault(error::set_confirmed); + return; + } + + if (ec == database::error::block_confirmable || checked) + { + // TODO: compute fees from validation records. + if ((ec != database::error::block_confirmable) && + !query.set_block_confirmable(link, uint64_t{})) + { + fault(error::block_confirmable); + return; + } + + notify(ec, chase::confirmable, index); + ////fire(events::confirm_bypassed, index); + + if (!set_organized(link, index)) + { + fault(error::set_confirmed); + return; + } + + continue; + } + + ec = query.block_confirmable(link); + if (ec == database::error::integrity) + { + fault(error::node_confirm); + return; + } + + if (ec) + { + if (!query.set_block_unconfirmable(link)) + { + fault(error::set_block_unconfirmable); + return; + } + + LOGR("Unconfirmable block [" << index << "] " << ec.message()); + notify(ec, chase::unconfirmable, link); + fire(events::block_unconfirmable, index); + + if (!roll_back(popped, link, fork_point, index)) + { + fault(error::node_roll_back); + } + + return; + } + + // TODO: compute fees from validation records. + if (!query.set_block_confirmable(link, uint64_t{})) + { + fault(error::block_confirmable); + return; + } + + notify(error::success, chase::confirmable, index); + fire(events::block_confirmed, index); + + if (!set_organized(link, index)) + { + fault(error::set_confirmed); + return; + } + + LOGV("Block confirmed and organized: " << index); + ++index; + } +} + +#if defined(DISABLED) + // Blocks are either confirmed (blocks first) or validated/confirmed // (headers first) at this point. An unconfirmable block may not land here. // Candidate chain reorganizations will result in reported heights moving @@ -392,6 +577,8 @@ void chaser_confirm::confirm_block(const code& ec, const header_link& link, } } +#endif // DISABLED + // Private // ---------------------------------------------------------------------------- diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index a9ae8582..3990c9ec 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -196,7 +196,7 @@ void chaser_validate::do_bump(height_t) NOEXCEPT // Retain last height in validation sequence, update neutrino. update_position(height); - fire(events::block_validated, height); + ////fire(events::block_validated, height); // Don't confirm until validations are current. if (is_current(link))