diff --git a/nano/rpc/rpc_handler.cpp b/nano/rpc/rpc_handler.cpp index 76d99360..cd8b343e 100644 --- a/nano/rpc/rpc_handler.cpp +++ b/nano/rpc/rpc_handler.cpp @@ -836,7 +836,38 @@ void nano::rpc_handler::block_confirm () auto block_l (node.store.block_get (transaction, hash)); if (block_l != nullptr) { - node.block_confirm (std::move (block_l)); + if (!node.ledger.block_confirmed (transaction, hash)) + { + // Start new confirmation for unconfirmed block + node.block_confirm (std::move (block_l)); + } + else + { + // Add record in confirmation history for confirmed block + nano::election_status status; + status.winner = block_l; + status.tally = 0; + status.election_end = std::chrono::duration_cast (std::chrono::system_clock::now ().time_since_epoch ()); + status.election_duration = std::chrono::milliseconds::zero (); + { + std::lock_guard lock (node.active.mutex); + node.active.confirmed.push_back (status); + if (node.active.confirmed.size () > node.active.election_history_size) + { + node.active.confirmed.pop_front (); + } + } + // Trigger callback for confirmed block + node.block_arrival.add (hash); + auto account (node.ledger.account (transaction, hash)); + auto amount (node.ledger.amount (transaction, hash)); + bool is_state_send (false); + if (auto state = dynamic_cast (block_l.get ())) + { + is_state_send = node.ledger.is_send (transaction, *state); + } + node.observers.blocks.notify (block_l, account, amount, is_state_send); + } response_l.put ("started", "1"); } else diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index 238dff9c..e2182552 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -4637,7 +4637,6 @@ TEST (rpc, block_confirm) nano::system system (24000, 1); system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); nano::genesis genesis; - system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv); auto send1 (std::make_shared (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.nodes[0]->work_generate_blocking (genesis.hash ()))); { auto transaction (system.nodes[0]->store.tx_begin (true)); @@ -4677,6 +4676,54 @@ TEST (rpc, block_confirm_absent) ASSERT_EQ ("Block not found", response.json.get ("error")); } +TEST (rpc, block_confirm_confirmed) +{ + nano::system system (24000, 1); + nano::node_init init; + auto path (nano::unique_path ()); + nano::node_config config; + config.peering_port = 24001; + config.callback_address = "localhost"; + config.callback_port = 24002; + config.callback_target = "/"; + config.logging.init (path); + auto node (std::make_shared (init, system.io_ctx, path, system.alarm, config, system.work)); + node->start (); + system.nodes.push_back (node); + nano::genesis genesis; + { + auto transaction (node->store.tx_begin_read ()); + ASSERT_TRUE (node->ledger.block_confirmed (transaction, genesis.hash ())); + } + ASSERT_EQ (0, node->stats.count (nano::stat::type::error, nano::stat::detail::http_callback, nano::stat::dir::out)); + nano::rpc rpc (system.io_ctx, *node, nano::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "block_confirm"); + request.put ("hash", genesis.hash ().to_string ()); + test_response response (request, rpc, system.io_ctx); + system.deadline_set (5s); + while (response.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response.status); + ASSERT_EQ ("1", response.json.get ("started")); + // Check confirmation history + auto confirmed (node->active.list_confirmed ()); + ASSERT_EQ (1, confirmed.size ()); + ASSERT_EQ (genesis.hash (), confirmed.begin ()->winner->hash ()); + // Check callback + system.deadline_set (5s); + while (node->stats.count (nano::stat::type::error, nano::stat::detail::http_callback, nano::stat::dir::out) == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + // Callback result is error because callback target port isn't listening + ASSERT_EQ (1, node->stats.count (nano::stat::type::error, nano::stat::detail::http_callback, nano::stat::dir::out)); + node->stop (); +} + TEST (rpc, node_id) { nano::system system (24000, 1);