Allowing manual triggering of confirmation. HTTP callbacks happen later in the confirmation callback.

This commit is contained in:
clemahieu 2018-04-26 01:56:54 +02:00
commit d61b3ac855
7 changed files with 168 additions and 43 deletions

View file

@ -1012,7 +1012,7 @@ TEST (node, coherent_observer)
{
rai::system system (24000, 1);
auto & node1 (*system.nodes[0]);
node1.observers.blocks.add ([&node1](std::shared_ptr<rai::block> block_a, rai::process_return const &) {
node1.observers.blocks.add ([&node1](std::shared_ptr<rai::block> block_a, rai::account const &, rai::uint128_t const &, bool) {
rai::transaction transaction (node1.store.environment, nullptr, false);
ASSERT_TRUE (node1.store.block_exists (transaction, block_a->hash ()));
});
@ -1475,3 +1475,25 @@ TEST (node, online_reps)
ASSERT_LT (iterations, 200);
}
}
TEST (node, block_confirm)
{
rai::system system (24000, 1);
rai::genesis genesis;
system.nodes [0]->ledger.state_block_parse_canary = genesis.hash ();
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
auto send1 (std::make_shared <rai::state_block> (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.nodes [0]->generate_work (genesis.hash ())));
{
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, true);
ASSERT_EQ (rai::process_result::progress, system.nodes [0]->ledger.process (transaction, *send1).code);
}
system.nodes [0]->block_confirm (send1);
ASSERT_TRUE (system.nodes [0]->active.confirmed.empty ());
auto iterations (0);
while (system.nodes [0]->active.confirmed.empty ())
{
system.poll ();
++iterations;
ASSERT_LT (iterations, 200);
}
}

View file

@ -3509,3 +3509,46 @@ TEST (rpc, confirmation_history)
ASSERT_EQ ((rai::genesis_amount - rai::Gxrb_ratio).convert_to<std::string> (), tally);
system.stop ();
}
TEST (rpc, block_confirm)
{
rai::system system (24000, 1);
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
rai::genesis genesis;
system.nodes [0]->ledger.state_block_parse_canary = genesis.hash ();
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
auto send1 (std::make_shared <rai::state_block> (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.nodes [0]->generate_work (genesis.hash ())));
{
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, true);
ASSERT_EQ (rai::process_result::progress, system.nodes [0]->ledger.process (transaction, *send1).code);
}
rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true));
rpc.start ();
boost::property_tree::ptree request;
request.put ("action", "block_confirm");
request.put ("hash", send1->hash ().to_string ());
test_response response (request, rpc, system.service);
while (response.status == 0)
{
system.poll ();
}
ASSERT_EQ (200, response.status);
ASSERT_EQ ("1", response.json.get <std::string> ("started"));
}
TEST (rpc, block_confirm_absent)
{
rai::system system (24000, 1);
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true));
rpc.start ();
boost::property_tree::ptree request;
request.put ("action", "block_confirm");
request.put ("hash", "0");
test_response response (request, rpc, system.service);
while (response.status == 0)
{
system.poll ();
}
ASSERT_EQ (200, response.status);
ASSERT_EQ ("Block not found", response.json.get <std::string> ("error"));
}

View file

@ -1273,7 +1273,10 @@ void rai::block_processor::process_receive_many (std::unique_lock<std::mutex> &
{
case rai::process_result::progress:
{
progress.push_back (std::make_pair (block, process_result));
if (node.block_arrival.recent (hash))
{
node.active.start (transaction, block);
}
}
case rai::process_result::old:
{
@ -1294,18 +1297,6 @@ void rai::block_processor::process_receive_many (std::unique_lock<std::mutex> &
}
}
lock_a.unlock ();
for (auto & i : progress)
{
node.observers.blocks (i.first, i.second);
if (i.second.amount > 0)
{
node.observers.account_balance (i.second.account, false);
if (!i.second.pending_account.is_zero ())
{
node.observers.account_balance (i.second.pending_account, true);
}
}
}
}
rai::process_return rai::block_processor::process_receive_one (MDB_txn * transaction_a, std::shared_ptr<rai::block> block_a)
@ -1476,30 +1467,23 @@ online_reps (*this)
peers.disconnect_observer = [this]() {
observers.disconnect ();
};
observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::process_return const & result_a) {
if (this->block_arrival.recent (block_a->hash ()))
{
rai::transaction transaction (store.environment, nullptr, false);
active.start (transaction, block_a);
}
});
observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::process_return const & result_a) {
observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::account const & account_a, rai::amount const & amount_a, bool is_state_send_a) {
if (this->block_arrival.recent (block_a->hash ()))
{
auto node_l (shared_from_this ());
background ([node_l, block_a, result_a]() {
background ([node_l, block_a, account_a, amount_a, is_state_send_a]() {
if (!node_l->config.callback_address.empty ())
{
boost::property_tree::ptree event;
event.add ("account", result_a.account.to_account ());
event.add ("account", account_a.to_account ());
event.add ("hash", block_a->hash ().to_string ());
std::string block_text;
block_a->serialize_json (block_text);
event.add ("block", block_text);
event.add ("amount", result_a.amount.to_string_dec ());
if (result_a.state_is_send)
event.add ("amount", amount_a.to_string_dec ());
if (is_state_send_a)
{
event.add ("is_send", *result_a.state_is_send);
event.add ("is_send", is_state_send_a);
}
std::stringstream ostream;
boost::property_tree::write_json (ostream, event);
@ -2407,15 +2391,23 @@ void rai::node::add_initial_peers ()
{
}
void rai::node::block_confirm (std::shared_ptr <rai::block> block_a)
{
rai::transaction transaction (store.environment, nullptr, false);
active.start (transaction, block_a);
network.broadcast_confirm_req (block_a);
}
namespace
{
class confirmed_visitor : public rai::block_visitor
{
public:
confirmed_visitor (MDB_txn * transaction_a, rai::node & node_a, std::shared_ptr<rai::block> block_a) :
confirmed_visitor (MDB_txn * transaction_a, rai::node & node_a, std::shared_ptr<rai::block> block_a, rai::block_hash const & hash_a) :
transaction (transaction_a),
node (node_a),
block (block_a)
block (block_a),
hash (hash_a)
{
}
virtual ~confirmed_visitor () = default;
@ -2429,7 +2421,7 @@ public:
rai::account representative;
rai::pending_info pending;
representative = wallet->store.representative (transaction);
auto error (node.store.pending_get (transaction, rai::pending_key (account_a, block->hash ()), pending));
auto error (node.store.pending_get (transaction, rai::pending_key (account_a, hash), pending));
if (!error)
{
auto node_l (node.shared ());
@ -2438,9 +2430,9 @@ public:
}
else
{
if (!node.store.block_exists (transaction, block->hash ()))
if (!node.store.block_exists (transaction, hash))
{
BOOST_LOG (node.log) << boost::str (boost::format ("Block %1% has already been received") % block->hash ().to_string ());
BOOST_LOG (node.log) << boost::str (boost::format ("Block %1% has already been received") % hash.to_string ());
}
else
{
@ -2470,14 +2462,42 @@ public:
MDB_txn * transaction;
rai::node & node;
std::shared_ptr<rai::block> block;
rai::block_hash const &hash;
};
}
void rai::node::process_confirmed (std::shared_ptr<rai::block> block_a)
{
rai::transaction transaction (store.environment, nullptr, false);
confirmed_visitor visitor (transaction, *this, block_a);
block_a->visit (visitor);
auto hash (block_a->hash ());
if (store.block_exists (transaction, hash))
{
confirmed_visitor visitor (transaction, *this, block_a, hash);
block_a->visit (visitor);
auto account (ledger.account (transaction, hash));
auto amount (ledger.amount (transaction, hash));
bool is_state_send (false);
rai::account pending_account (0);
if (auto state = dynamic_cast <rai::state_block *> (block_a.get ()))
{
rai::transaction transaction (store.environment, nullptr, false);
is_state_send = ledger.is_send (transaction, *state);
pending_account = state->hashables.link;
}
if (auto send = dynamic_cast <rai::send_block *> (block_a.get ()))
{
pending_account = send->hashables.destination;
}
observers.blocks (block_a, account, amount, is_state_send);
if (amount > 0)
{
observers.account_balance (account, false);
if (!pending_account.is_zero ())
{
observers.account_balance (pending_account, true);
}
}
}
}
void rai::node::process_message (rai::message & message_a, rai::endpoint const & sender_a)

View file

@ -458,7 +458,7 @@ public:
class node_observers
{
public:
rai::observer_set<std::shared_ptr<rai::block>, rai::process_return const &> blocks;
rai::observer_set<std::shared_ptr<rai::block>, rai::account const &, rai::uint128_t const &, bool> blocks;
rai::observer_set<bool> wallet;
rai::observer_set<std::shared_ptr<rai::vote>, rai::endpoint const &> vote;
rai::observer_set<rai::account const &, bool> account_balance;
@ -550,6 +550,7 @@ public:
uint64_t generate_work (rai::uint256_union const &);
void generate_work (rai::uint256_union const &, std::function<void(uint64_t)>);
void add_initial_peers ();
void block_confirm (std::shared_ptr <rai::block>);
boost::asio::io_service & service;
rai::node_config config;
rai::alarm & alarm;

View file

@ -141,8 +141,8 @@ void rai::rpc::start ()
}
acceptor.listen ();
node.observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::process_return const & result_a) {
observer_action (result_a.account);
node.observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::account const & account_a, rai::uint128_t const &, bool) {
observer_action (account_a);
});
accept ();
@ -899,6 +899,32 @@ void rai::rpc_handler::block ()
}
}
void rai::rpc_handler::block_confirm ()
{
std::string hash_text (request.get<std::string> ("hash"));
rai::block_hash hash_l;
if (!hash_l.decode_hex (hash_text))
{
rai::transaction transaction (node.store.environment, nullptr, false);
auto block_l (node.store.block_get (transaction, hash_l));
if (block_l != nullptr)
{
node.block_confirm (std::move (block_l));
boost::property_tree::ptree response_l;
response_l.put ("started", "1");
response (response_l);
}
else
{
error_response (response, "Block not found");
}
}
else
{
error_response (response, "Invalid block hash");
}
}
void rai::rpc_handler::blocks ()
{
std::vector<std::string> hashes;
@ -2558,7 +2584,16 @@ void rai::rpc_handler::process ()
{
case rai::process_result::progress:
{
node.observers.blocks (block_a, result);
rai::transaction transaction (node.store.environment, nullptr, false);
auto account (node.ledger.account (transaction, hash));
auto amount (node.ledger.amount (transaction, hash));
bool is_state_send (false);
if (auto state = dynamic_cast <rai::state_block *> (block_a.get ()))
{
rai::transaction transaction (node.store.environment, nullptr, false);
is_state_send = node.ledger.is_send (transaction, *state);
}
node.observers.blocks (block_a, account, amount, is_state_send);
boost::property_tree::ptree response_l;
response_l.put ("hash", hash.to_string ());
response (response_l);
@ -4597,6 +4632,10 @@ void rai::rpc_handler::process_request ()
{
block ();
}
else if (action == "block_confirm")
{
block_confirm ();
}
else if (action == "blocks")
{
blocks ();

View file

@ -133,6 +133,7 @@ public:
void accounts_pending ();
void available_supply ();
void block ();
void block_confirm ();
void blocks ();
void blocks_info ();
void block_account ();

View file

@ -1099,18 +1099,17 @@ void rai_qt::wallet::start ()
this_l->push_main_stack (this_l->send_blocks_window);
}
});
node.observers.blocks.add ([this_w](std::shared_ptr<rai::block> block_a, rai::process_return const & result_a) {
node.observers.blocks.add ([this_w](std::shared_ptr<rai::block> block_a, rai::account const & account_a, rai::uint128_t const & amount_a, bool) {
if (auto this_l = this_w.lock ())
{
auto account (result_a.account);
this_l->application.postEvent (&this_l->processor, new eventloop_event ([this_w, block_a, account]() {
this_l->application.postEvent (&this_l->processor, new eventloop_event ([this_w, block_a, account_a]() {
if (auto this_l = this_w.lock ())
{
if (this_l->wallet_m->exists (account))
if (this_l->wallet_m->exists (account_a))
{
this_l->accounts.refresh ();
}
if (account == this_l->account)
if (account_a == this_l->account)
{
this_l->history.refresh ();
}