diff --git a/nano/core_test/confirmation_height.cpp b/nano/core_test/confirmation_height.cpp index a8d758e04..644e1cf60 100644 --- a/nano/core_test/confirmation_height.cpp +++ b/nano/core_test/confirmation_height.cpp @@ -12,7 +12,7 @@ namespace { void add_callback_stats (nano::node & node, std::vector * observer_order = nullptr, nano::mutex * mutex = nullptr) { - node.observers.blocks.add ([&stats = node.stats, observer_order, mutex] (nano::election_status const & status_a, std::vector const &, nano::account const &, nano::amount const &, bool) { + node.observers.blocks.add ([&stats = node.stats, observer_order, mutex] (nano::election_status const & status_a, std::vector const &, nano::account const &, nano::amount const &, bool, bool) { stats.inc (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out); if (mutex) { diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index e1f553503..591c24416 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -1486,7 +1486,7 @@ TEST (node, coherent_observer) { nano::system system (1); auto & node1 (*system.nodes[0]); - node1.observers.blocks.add ([&node1] (nano::election_status const & status_a, std::vector const &, nano::account const &, nano::uint128_t const &, bool) { + node1.observers.blocks.add ([&node1] (nano::election_status const & status_a, std::vector const &, nano::account const &, nano::uint128_t const &, bool, bool) { auto transaction (node1.store.tx_begin_read ()); ASSERT_TRUE (node1.store.block.exists (transaction, status_a.winner->hash ())); }); diff --git a/nano/node/active_transactions.cpp b/nano/node/active_transactions.cpp index 10f9c16a9..2a8f8907b 100644 --- a/nano/node/active_transactions.cpp +++ b/nano/node/active_transactions.cpp @@ -183,9 +183,10 @@ void nano::active_transactions::block_cemented_callback (std::shared_ptrhash (), account, amount, is_state_send, pending_account); - node.observers.blocks.notify (nano::election_status{ block_a, 0, 0, std::chrono::duration_cast (std::chrono::system_clock::now ().time_since_epoch ()), std::chrono::duration_values::zero (), 0, 1, 0, nano::election_status_type::inactive_confirmation_height }, {}, account, amount, is_state_send); + node.process_confirmed_data (transaction, block_a, block_a->hash (), account, amount, is_state_send, is_state_epoch, pending_account); + node.observers.blocks.notify (nano::election_status{ block_a, 0, 0, std::chrono::duration_cast (std::chrono::system_clock::now ().time_since_epoch ()), std::chrono::duration_values::zero (), 0, 1, 0, nano::election_status_type::inactive_confirmation_height }, {}, account, amount, is_state_send, is_state_epoch); } else { @@ -208,15 +209,16 @@ void nano::active_transactions::block_cemented_callback (std::shared_ptrstatus.type = *election_status_type; election->status.confirmation_request_count = election->confirmation_request_count; status_l = election->status; election_lk.unlock (); auto votes (election->votes_with_weight ()); - node.observers.blocks.notify (status_l, votes, account, amount, is_state_send); + node.observers.blocks.notify (status_l, votes, account, amount, is_state_send, is_state_epoch); if (amount > 0) { node.observers.account_balance.notify (account, false); diff --git a/nano/node/ipc/flatbuffers_util.cpp b/nano/node/ipc/flatbuffers_util.cpp index 20813943d..8cf1fe5e4 100644 --- a/nano/node/ipc/flatbuffers_util.cpp +++ b/nano/node/ipc/flatbuffers_util.cpp @@ -3,9 +3,8 @@ #include #include -std::unique_ptr nano::ipc::flatbuffers_builder::from (nano::state_block const & block_a, nano::amount const & amount_a, bool is_state_send_a) +std::unique_ptr nano::ipc::flatbuffers_builder::from (nano::state_block const & block_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a) { - static nano::network_params params; auto block (std::make_unique ()); block->account = block_a.account ().to_account (); block->hash = block_a.hash ().to_string (); @@ -25,7 +24,7 @@ std::unique_ptr nano::ipc::flatbuffers_builder::from (nano { block->subtype = nanoapi::BlockSubType::BlockSubType_change; } - else if (amount_a == 0 && params.ledger.epochs.is_epoch_link (block_a.link ())) + else if (amount_a == 0 && is_state_epoch_a) { block->subtype = nanoapi::BlockSubType::BlockSubType_epoch; } @@ -82,14 +81,14 @@ std::unique_ptr nano::ipc::flatbuffers_builder::from (nan return block; } -nanoapi::BlockUnion nano::ipc::flatbuffers_builder::block_to_union (nano::block const & block_a, nano::amount const & amount_a, bool is_state_send_a) +nanoapi::BlockUnion nano::ipc::flatbuffers_builder::block_to_union (nano::block const & block_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a) { nanoapi::BlockUnion u; switch (block_a.type ()) { case nano::block_type::state: { - u.Set (*from (dynamic_cast (block_a), amount_a, is_state_send_a)); + u.Set (*from (dynamic_cast (block_a), amount_a, is_state_send_a, is_state_epoch_a)); break; } case nano::block_type::send: diff --git a/nano/node/ipc/flatbuffers_util.hpp b/nano/node/ipc/flatbuffers_util.hpp index c1236a941..2e7f8fcf1 100644 --- a/nano/node/ipc/flatbuffers_util.hpp +++ b/nano/node/ipc/flatbuffers_util.hpp @@ -21,8 +21,8 @@ namespace ipc class flatbuffers_builder { public: - static nanoapi::BlockUnion block_to_union (nano::block const & block_a, nano::amount const & amount_a, bool is_state_send_a = false); - static std::unique_ptr from (nano::state_block const & block_a, nano::amount const & amount_a, bool is_state_send_a); + static nanoapi::BlockUnion block_to_union (nano::block const & block_a, nano::amount const & amount_a, bool is_state_send_a = false, bool is_state_epoch_a = false); + static std::unique_ptr from (nano::state_block const & block_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a); static std::unique_ptr from (nano::send_block const & block_a); static std::unique_ptr from (nano::receive_block const & block_a); static std::unique_ptr from (nano::open_block const & block_a); diff --git a/nano/node/ipc/ipc_broker.cpp b/nano/node/ipc/ipc_broker.cpp index b3af919fd..77712bfc0 100644 --- a/nano/node/ipc/ipc_broker.cpp +++ b/nano/node/ipc/ipc_broker.cpp @@ -22,7 +22,7 @@ std::shared_ptr nano::ipc::subscriber::get_parser (nano::ip void nano::ipc::broker::start () { - node.observers.blocks.add ([this_l = shared_from_this ()] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a) { + node.observers.blocks.add ([this_l = shared_from_this ()] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a) { debug_assert (status_a.type != nano::election_status_type::ongoing); try @@ -51,7 +51,7 @@ void nano::ipc::broker::start () break; }; confirmation->confirmation_type = nanoapi::TopicConfirmationType::TopicConfirmationType_active_quorum; - confirmation->block = nano::ipc::flatbuffers_builder::block_to_union (*status_a.winner, amount_a, is_state_send_a); + confirmation->block = nano::ipc::flatbuffers_builder::block_to_union (*status_a.winner, amount_a, is_state_send_a, is_state_epoch_a); confirmation->election_info = std::make_unique (); confirmation->election_info->duration = status_a.election_duration.count (); confirmation->election_info->time = status_a.election_end.count (); diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 4e4887943..5951683d7 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -1138,14 +1138,16 @@ void nano::json_handler::block_confirm () bool error_or_pruned (false); auto amount (node.ledger.amount_safe (transaction, hash, error_or_pruned)); bool is_state_send (false); + bool is_state_epoch (false); if (!error_or_pruned) { if (auto state = dynamic_cast (block_l.get ())) { is_state_send = node.ledger.is_send (transaction, *state); + is_state_epoch = amount == 0 && node.ledger.is_epoch_link (state->link ()); } } - node.observers.blocks.notify (status, {}, account, amount, is_state_send); + node.observers.blocks.notify (status, {}, account, amount, is_state_send, is_state_epoch); } response_l.put ("started", "1"); } diff --git a/nano/node/node.cpp b/nano/node/node.cpp index d1791eab8..9d29cb0e7 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -149,12 +149,12 @@ nano::node::node (boost::asio::io_context & io_ctx_a, boost::filesystem::path co }; if (!config.callback_address.empty ()) { - observers.blocks.add ([this] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a) { + observers.blocks.add ([this] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a) { auto block_a (status_a.winner); if ((status_a.type == nano::election_status_type::active_confirmed_quorum || status_a.type == nano::election_status_type::active_confirmation_height) && this->block_arrival.recent (block_a->hash ())) { auto node_l (shared_from_this ()); - background ([node_l, block_a, account_a, amount_a, is_state_send_a] () { + background ([node_l, block_a, account_a, amount_a, is_state_send_a, is_state_epoch_a] () { boost::property_tree::ptree event; event.add ("account", account_a.to_account ()); event.add ("hash", block_a->hash ().to_string ()); @@ -174,8 +174,9 @@ nano::node::node (boost::asio::io_context & io_ctx_a, boost::filesystem::path co { event.add ("subtype", "change"); } - else if (amount_a == 0 && node_l->ledger.is_epoch_link (block_a->link ())) + else if (is_state_epoch_a) { + debug_assert (amount_a == 0 && node_l->ledger.is_epoch_link (block_a->link ())); event.add ("subtype", "epoch"); } else @@ -211,7 +212,7 @@ nano::node::node (boost::asio::io_context & io_ctx_a, boost::filesystem::path co } if (websocket_server) { - observers.blocks.add ([this] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a) { + observers.blocks.add ([this] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a) { debug_assert (status_a.type != nano::election_status_type::ongoing); if (this->websocket_server->any_subscriber (nano::websocket::topic::confirmation)) @@ -228,8 +229,9 @@ nano::node::node (boost::asio::io_context & io_ctx_a, boost::filesystem::path co { subtype = "change"; } - else if (amount_a == 0 && this->ledger.is_epoch_link (block_a->link ())) + else if (is_state_epoch_a) { + debug_assert (amount_a == 0 && this->ledger.is_epoch_link (block_a->link ())); subtype = "epoch"; } else @@ -259,7 +261,7 @@ nano::node::node (boost::asio::io_context & io_ctx_a, boost::filesystem::path co }); } // Add block confirmation type stats regardless of http-callback and websocket subscriptions - observers.blocks.add ([this] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a) { + observers.blocks.add ([this] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a) { debug_assert (status_a.type != nano::election_status_type::ongoing); switch (status_a.type) { @@ -1305,7 +1307,7 @@ void nano::node::receive_confirmed (nano::transaction const & block_transaction_ } } -void nano::node::process_confirmed_data (nano::transaction const & transaction_a, std::shared_ptr const & block_a, nano::block_hash const & hash_a, nano::account & account_a, nano::uint128_t & amount_a, bool & is_state_send_a, nano::account & pending_account_a) +void nano::node::process_confirmed_data (nano::transaction const & transaction_a, std::shared_ptr const & block_a, nano::block_hash const & hash_a, nano::account & account_a, nano::uint128_t & amount_a, bool & is_state_send_a, bool & is_state_epoch_a, nano::account & pending_account_a) { // Faster account calculation account_a = block_a->account (); @@ -1339,6 +1341,10 @@ void nano::node::process_confirmed_data (nano::transaction const & transaction_a { is_state_send_a = true; } + if (amount_a == 0 && network_params.ledger.epochs.is_epoch_link (state->link ())) + { + is_state_epoch_a = true; + } pending_account_a = state->hashables.link.as_account (); } if (auto send = dynamic_cast (block_a.get ())) diff --git a/nano/node/node.hpp b/nano/node/node.hpp index 1d9172983..3bd4edf83 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -100,7 +100,7 @@ public: std::shared_ptr shared (); int store_version (); void receive_confirmed (nano::transaction const & block_transaction_a, nano::block_hash const & hash_a, nano::account const & destination_a); - void process_confirmed_data (nano::transaction const &, std::shared_ptr const &, nano::block_hash const &, nano::account &, nano::uint128_t &, bool &, nano::account &); + void process_confirmed_data (nano::transaction const &, std::shared_ptr const &, nano::block_hash const &, nano::account &, nano::uint128_t &, bool &, bool &, nano::account &); void process_confirmed (nano::election_status const &, uint64_t = 0); void process_active (std::shared_ptr const &); nano::process_return process (nano::block &); diff --git a/nano/node/node_observers.hpp b/nano/node/node_observers.hpp index 78c0f0e03..cea357eb1 100644 --- a/nano/node/node_observers.hpp +++ b/nano/node/node_observers.hpp @@ -11,7 +11,7 @@ class telemetry; class node_observers final { public: - using blocks_t = nano::observer_set const &, nano::account const &, nano::uint128_t const &, bool>; + using blocks_t = nano::observer_set const &, nano::account const &, nano::uint128_t const &, bool, bool>; blocks_t blocks; nano::observer_set wallet; nano::observer_set, std::shared_ptr, nano::vote_code> vote; diff --git a/nano/qt/qt.cpp b/nano/qt/qt.cpp index 7fa6eac0e..3b43176f5 100644 --- a/nano/qt/qt.cpp +++ b/nano/qt/qt.cpp @@ -1289,7 +1289,7 @@ void nano_qt::wallet::start () this_l->push_main_stack (this_l->send_blocks_window); } }); - node.observers.blocks.add ([this_w] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::uint128_t const & amount_a, bool) { + node.observers.blocks.add ([this_w] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::uint128_t const & amount_a, bool, bool) { if (auto this_l = this_w.lock ()) { this_l->application.postEvent (&this_l->processor, new eventloop_event ([this_w, status_a, account_a] () {