State blocks subtype check for RPC "process" (#1704)
* State blocks subtype check for RPC "process" * Using else if instead of switch * Tests for RPC process with subtypes
This commit is contained in:
parent
3778a8c033
commit
da73cdca90
4 changed files with 232 additions and 0 deletions
|
@ -1236,6 +1236,159 @@ TEST (rpc, process_republish)
|
|||
}
|
||||
}
|
||||
|
||||
TEST (rpc, process_subtype_send)
|
||||
{
|
||||
nano::system system (24000, 2);
|
||||
nano::keypair key;
|
||||
auto latest (system.nodes[0]->latest (nano::test_genesis_key.pub));
|
||||
auto & node1 (*system.nodes[0]);
|
||||
nano::state_block send (nano::genesis_account, latest, nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, node1.work_generate_blocking (latest));
|
||||
nano::rpc rpc (system.io_ctx, node1, nano::rpc_config (true));
|
||||
rpc.start ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "process");
|
||||
std::string json;
|
||||
send.serialize_json (json);
|
||||
request.put ("block", json);
|
||||
request.put ("subtype", "receive");
|
||||
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);
|
||||
std::error_code ec (nano::error_rpc::invalid_subtype_balance);
|
||||
ASSERT_EQ (response.json.get<std::string> ("error"), ec.message ());
|
||||
request.put ("subtype", "change");
|
||||
test_response response2 (request, rpc, system.io_ctx);
|
||||
while (response2.status == 0)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_EQ (200, response2.status);
|
||||
ASSERT_EQ (response2.json.get<std::string> ("error"), ec.message ());
|
||||
request.put ("subtype", "send");
|
||||
test_response response3 (request, rpc, system.io_ctx);
|
||||
while (response3.status == 0)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_EQ (200, response3.status);
|
||||
ASSERT_EQ (send.hash ().to_string (), response3.json.get<std::string> ("hash"));
|
||||
system.deadline_set (10s);
|
||||
while (system.nodes[1]->latest (nano::test_genesis_key.pub) != send.hash ())
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, process_subtype_open)
|
||||
{
|
||||
nano::system system (24000, 2);
|
||||
nano::keypair key;
|
||||
auto latest (system.nodes[0]->latest (nano::test_genesis_key.pub));
|
||||
auto & node1 (*system.nodes[0]);
|
||||
nano::state_block send (nano::genesis_account, latest, nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, node1.work_generate_blocking (latest));
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, send).code);
|
||||
}
|
||||
node1.active.start (std::make_shared<nano::state_block> (send));
|
||||
nano::state_block open (key.pub, 0, key.pub, nano::Gxrb_ratio, send.hash (), key.prv, key.pub, node1.work_generate_blocking (key.pub));
|
||||
nano::rpc rpc (system.io_ctx, node1, nano::rpc_config (true));
|
||||
rpc.start ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "process");
|
||||
std::string json;
|
||||
open.serialize_json (json);
|
||||
request.put ("block", json);
|
||||
request.put ("subtype", "send");
|
||||
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);
|
||||
std::error_code ec (nano::error_rpc::invalid_subtype_balance);
|
||||
ASSERT_EQ (response.json.get<std::string> ("error"), ec.message ());
|
||||
request.put ("subtype", "epoch");
|
||||
test_response response2 (request, rpc, system.io_ctx);
|
||||
while (response2.status == 0)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_EQ (200, response2.status);
|
||||
ASSERT_EQ (response2.json.get<std::string> ("error"), ec.message ());
|
||||
request.put ("subtype", "open");
|
||||
test_response response3 (request, rpc, system.io_ctx);
|
||||
while (response3.status == 0)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_EQ (200, response3.status);
|
||||
ASSERT_EQ (open.hash ().to_string (), response3.json.get<std::string> ("hash"));
|
||||
system.deadline_set (10s);
|
||||
while (system.nodes[1]->latest (key.pub) != open.hash ())
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, process_subtype_receive)
|
||||
{
|
||||
nano::system system (24000, 2);
|
||||
auto latest (system.nodes[0]->latest (nano::test_genesis_key.pub));
|
||||
auto & node1 (*system.nodes[0]);
|
||||
nano::state_block send (nano::genesis_account, latest, nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, node1.work_generate_blocking (latest));
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, send).code);
|
||||
}
|
||||
node1.active.start (std::make_shared<nano::state_block> (send));
|
||||
nano::state_block receive (nano::test_genesis_key.pub, send.hash (), nano::test_genesis_key.pub, nano::genesis_amount, send.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, node1.work_generate_blocking (send.hash ()));
|
||||
nano::rpc rpc (system.io_ctx, node1, nano::rpc_config (true));
|
||||
rpc.start ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "process");
|
||||
std::string json;
|
||||
receive.serialize_json (json);
|
||||
request.put ("block", json);
|
||||
request.put ("subtype", "send");
|
||||
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);
|
||||
std::error_code ec (nano::error_rpc::invalid_subtype_balance);
|
||||
ASSERT_EQ (response.json.get<std::string> ("error"), ec.message ());
|
||||
request.put ("subtype", "open");
|
||||
test_response response2 (request, rpc, system.io_ctx);
|
||||
while (response2.status == 0)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_EQ (200, response2.status);
|
||||
ec = nano::error_rpc::invalid_subtype_previous;
|
||||
ASSERT_EQ (response2.json.get<std::string> ("error"), ec.message ());
|
||||
request.put ("subtype", "receive");
|
||||
test_response response3 (request, rpc, system.io_ctx);
|
||||
while (response3.status == 0)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_EQ (200, response3.status);
|
||||
ASSERT_EQ (receive.hash ().to_string (), response3.json.get<std::string> ("hash"));
|
||||
system.deadline_set (10s);
|
||||
while (system.nodes[1]->latest (nano::test_genesis_key.pub) != receive.hash ())
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, keepalive)
|
||||
{
|
||||
nano::system system (24000, 1);
|
||||
|
|
|
@ -158,6 +158,14 @@ std::string nano::error_rpc_messages::message (int ev) const
|
|||
return "Invalid root hash";
|
||||
case nano::error_rpc::invalid_sources:
|
||||
return "Invalid sources number";
|
||||
case nano::error_rpc::invalid_subtype:
|
||||
return "Invalid block subtype";
|
||||
case nano::error_rpc::invalid_subtype_balance:
|
||||
return "Invalid block balance for given subtype";
|
||||
case nano::error_rpc::invalid_subtype_epoch_link:
|
||||
return "Invalid epoch link";
|
||||
case nano::error_rpc::invalid_subtype_previous:
|
||||
return "Invalid previous block for given subtype";
|
||||
case nano::error_rpc::invalid_timestamp:
|
||||
return "Invalid timestamp";
|
||||
case nano::error_rpc::payment_account_balance:
|
||||
|
|
|
@ -95,6 +95,10 @@ enum class error_rpc
|
|||
invalid_missing_type,
|
||||
invalid_root,
|
||||
invalid_sources,
|
||||
invalid_subtype,
|
||||
invalid_subtype_balance,
|
||||
invalid_subtype_epoch_link,
|
||||
invalid_subtype_previous,
|
||||
invalid_timestamp,
|
||||
payment_account_balance,
|
||||
payment_unable_create_account,
|
||||
|
|
|
@ -2484,6 +2484,73 @@ void nano::rpc_handler::payment_wait ()
|
|||
void nano::rpc_handler::process ()
|
||||
{
|
||||
auto block (block_impl (true));
|
||||
// State blocks subtype check
|
||||
if (!ec && block->type () == nano::block_type::state)
|
||||
{
|
||||
std::string subtype_text (request.get<std::string> ("subtype", ""));
|
||||
if (!subtype_text.empty ())
|
||||
{
|
||||
std::shared_ptr<nano::state_block> block_state (std::static_pointer_cast<nano::state_block> (block));
|
||||
auto transaction (node.store.tx_begin_read ());
|
||||
if (!block_state->hashables.previous.is_zero () && !node.store.block_exists (transaction, block_state->hashables.previous))
|
||||
{
|
||||
ec = nano::error_process::gap_previous;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto balance (node.ledger.account_balance (transaction, block_state->hashables.account));
|
||||
if (subtype_text == "send")
|
||||
{
|
||||
if (balance <= block_state->hashables.balance.number ())
|
||||
{
|
||||
ec = nano::error_rpc::invalid_subtype_balance;
|
||||
}
|
||||
// Send with previous == 0 fails balance check. No previous != 0 check required
|
||||
}
|
||||
else if (subtype_text == "receive")
|
||||
{
|
||||
if (balance > block_state->hashables.balance.number ())
|
||||
{
|
||||
ec = nano::error_rpc::invalid_subtype_balance;
|
||||
}
|
||||
// Receive can be point to open block. No previous != 0 check required
|
||||
}
|
||||
else if (subtype_text == "open")
|
||||
{
|
||||
if (!block_state->hashables.previous.is_zero ())
|
||||
{
|
||||
ec = nano::error_rpc::invalid_subtype_previous;
|
||||
}
|
||||
}
|
||||
else if (subtype_text == "change")
|
||||
{
|
||||
if (balance != block_state->hashables.balance.number ())
|
||||
{
|
||||
ec = nano::error_rpc::invalid_subtype_balance;
|
||||
}
|
||||
else if (block_state->hashables.previous.is_zero ())
|
||||
{
|
||||
ec = nano::error_rpc::invalid_subtype_previous;
|
||||
}
|
||||
}
|
||||
else if (subtype_text == "epoch")
|
||||
{
|
||||
if (balance != block_state->hashables.balance.number ())
|
||||
{
|
||||
ec = nano::error_rpc::invalid_subtype_balance;
|
||||
}
|
||||
else if (!node.ledger.is_epoch_link (block_state->hashables.link))
|
||||
{
|
||||
ec = ec = nano::error_rpc::invalid_subtype_epoch_link;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = nano::error_rpc::invalid_subtype;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ec)
|
||||
{
|
||||
if (!nano::work_validate (*block))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue