Skip to content

Commit

Permalink
Adding send restrictions filter which ensures sending transaction bal…
Browse files Browse the repository at this point in the history
…ances don't increase.
  • Loading branch information
clemahieu committed Mar 4, 2022
1 parent 9b14009 commit 9c7ea8a
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 1 deletion.
1 change: 1 addition & 0 deletions nano/core_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ add_executable(
receive_restrictions_filter.cpp
request_aggregator.cpp
reserved_account_filter.cpp
send_restrictions_filter.cpp
signal_manager.cpp
signing.cpp
socket.cpp
Expand Down
142 changes: 142 additions & 0 deletions nano/core_test/send_restrictions_filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include <nano/lib/blockbuilders.hpp>
#include <nano/lib/stats.hpp>
#include <nano/node/block_pipeline/context.hpp>
#include <nano/node/block_pipeline/send_restrictions_filter.hpp>
#include <nano/secure/common.hpp>
#include <nano/secure/ledger.hpp>
#include <nano/secure/store.hpp>
#include <nano/secure/utility.hpp>

#include <gtest/gtest.h>

namespace
{
class context
{
public:
context ()
{
filter.pass = [this] (nano::block_pipeline::context & context) {
pass.push_back (context);
};
filter.reject = [this] (nano::block_pipeline::context & context) {
reject.push_back (context);
};
}
nano::block_pipeline::send_restrictions_filter filter;
std::vector<nano::block_pipeline::context> pass;
std::vector<nano::block_pipeline::context> reject;
};
nano::block_pipeline::context pass_state_block ()
{
nano::block_builder builder;
nano::block_pipeline::context result;
result.state = nano::account_info{};
result.state->balance = nano::dev::constants.genesis_amount; // Genesis amount in account
result.block = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - 1) // 1 raw nano is sent
.link (nano::dev::genesis_key.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
return result;
}
nano::block_pipeline::context pass_send_block ()
{
nano::block_builder builder;
nano::block_pipeline::context result;
result.state = nano::account_info{};
result.state->balance = nano::dev::constants.genesis_amount; // Genesis amount in account
result.block = builder.send ()
.previous (nano::dev::genesis->hash ())
.destination (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - 1) // 1 raw nano is sent
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
return result;
}
nano::block_pipeline::context reject_state_block ()
{
nano::block_builder builder;
nano::block_pipeline::context result;
auto send = builder.state () // Dummy block
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - 1) // 1 raw nano is sent
.link (nano::dev::genesis_key.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
result.state = nano::account_info{};
result.state->balance = nano::dev::constants.genesis_amount - 1;
result.block = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount) // Balance has increased
.link (nano::dev::genesis_key.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
return result;
}
nano::block_pipeline::context reject_send_block ()
{
nano::block_builder builder;
nano::block_pipeline::context result;
auto send = builder.send () // Dummy block
.previous (nano::dev::genesis->hash ())
.balance (nano::dev::constants.genesis_amount - 1) // 1 raw nano is sent
.destination (nano::dev::genesis_key.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
result.state = nano::account_info{};
result.state->balance = nano::dev::constants.genesis_amount - 1;
result.block = builder.send ()
.previous (nano::dev::genesis->hash ())
.balance (nano::dev::constants.genesis_amount) // Balance has increased
.destination (nano::dev::genesis_key.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
return result;
}
}

TEST (send_restrictions_filter, pass_send)
{
context context;
auto pass = pass_send_block ();
context.filter.sink (pass);
ASSERT_EQ (1, context.pass.size ());
}

TEST (send_restrictions_filter, pass_state)
{
context context;
auto pass = pass_state_block ();
context.filter.sink (pass);
ASSERT_EQ (1, context.pass.size ());
}

TEST (send_restrictions_filter, reject_send)
{
context context;
auto pass = reject_send_block ();
context.filter.sink (pass);
ASSERT_EQ (1, context.reject.size ());
}

TEST (send_restrictions_filter, reject_state)
{
context context;
auto pass = reject_send_block ();
context.filter.sink (pass);
ASSERT_EQ (1, context.reject.size ());
}
6 changes: 6 additions & 0 deletions nano/lib/stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,12 @@ std::string nano::stat::detail_to_string (stat::detail detail)
case nano::stat::detail::reserved_account_filter_reject:
res = "reserved_account_filter_reject";
break;
case nano::stat::detail::send_restrictions_filter_pass:
res = "send_restrictions_filter_pass";
break;
case nano::stat::detail::send_restrictions_filter_reject:
res = "send_restrictions_filter_reject";
break;
case nano::stat::detail::stateless_signer_filter_pass:
res = "stateless_signer_filter_pass";
break;
Expand Down
2 changes: 2 additions & 0 deletions nano/lib/stats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ class stat final
receive_restrictions_filter_reject_pending,
reserved_account_filter_pass,
reserved_account_filter_reject,
send_restrictions_filter_pass,
send_restrictions_filter_reject,
signer_decorator_output,
stateless_signer_filter_pass,
stateless_signer_filter_reject,
Expand Down
2 changes: 2 additions & 0 deletions nano/node/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ add_library(
block_pipeline/receive_restrictions_filter.hpp
block_pipeline/reserved_account_filter.cpp
block_pipeline/reserved_account_filter.hpp
block_pipeline/send_restrictions_filter.cpp
block_pipeline/send_restrictions_filter.hpp
block_pipeline/signer_decorator.cpp
block_pipeline/signer_decorator.hpp
block_pipeline/stateless_signer_filter.cpp
Expand Down
14 changes: 14 additions & 0 deletions nano/node/block_pipeline/send_restrictions_filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <nano/node/block_pipeline/context.hpp>
#include <nano/node/block_pipeline/send_restrictions_filter.hpp>
#include <nano/secure/ledger.hpp>
#include <nano/secure/store.hpp>

void nano::block_pipeline::send_restrictions_filter::sink (context & context)
{
debug_assert (context.block->type () == nano::block_type::send || context.block->type () == nano::block_type::state);
if (context.state->balance < context.block->balance ())
{
reject (context);
}
pass (context);
}
22 changes: 22 additions & 0 deletions nano/node/block_pipeline/send_restrictions_filter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <functional>

namespace nano
{
namespace block_pipeline
{
class context;
/**
This class filters blocks that don't follow restrictions on sending.
Sending must not increase its balance
*/
class send_restrictions_filter
{
public:
void sink (context & context);
std::function<void (context & context)> pass;
std::function<void (context & context)> reject;
};
} // namespace block_pipeline
} // namespacenano
11 changes: 10 additions & 1 deletion nano/node/blockprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ nano::block_processor::block_processor (nano::node & node_a, nano::write_databas
};
link.account = [this] (block_pipeline::context & context) {
node.stats.inc (nano::stat::type::block_pipeline, nano::stat::detail::link_filter_account);
enqueue (context);
send_restrictions.sink (context);
};
link.noop = [this] (block_pipeline::context & context) {
node.stats.inc (nano::stat::type::block_pipeline, nano::stat::detail::link_filter_noop);
Expand All @@ -132,6 +132,13 @@ nano::block_processor::block_processor (nano::node & node_a, nano::write_databas
node.gap_cache.add (context.block->hash ());
node.unchecked.put (context.source (), context.block);
};
send_restrictions.pass = [this] (block_pipeline::context & context) {
node.stats.inc (nano::stat::type::block_pipeline, nano::stat::detail::send_restrictions_filter_pass);
enqueue (context);
};
send_restrictions.reject = [this] (block_pipeline::context & context) {
node.stats.inc (nano::stat::type::block_pipeline, nano::stat::detail::send_restrictions_filter_reject);
};
// Pipeline end
state_block_signature_verification.transition_inactive_callback = [this] () {
if (this->flushing)
Expand Down Expand Up @@ -291,6 +298,8 @@ void nano::block_processor::pipeline_dump ()
dump_stage (nano::stat::detail::receive_restrictions_filter_reject_pending);
dump_stage (nano::stat::detail::reserved_account_filter_pass);
dump_stage (nano::stat::detail::reserved_account_filter_reject);
dump_stage (nano::stat::detail::send_restrictions_filter_pass);
dump_stage (nano::stat::detail::send_restrictions_filter_reject);
dump_stage (nano::stat::detail::signer_decorator_output);
dump_stage (nano::stat::detail::stateless_signer_filter_pass);
dump_stage (nano::stat::detail::stateless_signer_filter_reject);
Expand Down
2 changes: 2 additions & 0 deletions nano/node/blockprocessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <nano/node/block_pipeline/metastable_filter.hpp>
#include <nano/node/block_pipeline/receive_restrictions_filter.hpp>
#include <nano/node/block_pipeline/reserved_account_filter.hpp>
#include <nano/node/block_pipeline/send_restrictions_filter.hpp>
#include <nano/node/block_pipeline/signer_decorator.hpp>
#include <nano/node/block_pipeline/stateless_signer_filter.hpp>
#include <nano/node/state_block_signature_verification.hpp>
Expand Down Expand Up @@ -115,6 +116,7 @@ class block_processor final
nano::block_pipeline::link_filter link;
nano::block_pipeline::epoch_restrictions_filter epoch_restrictions;
nano::block_pipeline::receive_restrictions_filter receive_restrictions;
nano::block_pipeline::send_restrictions_filter send_restrictions;
nano::block_pipeline::signer_decorator signer_decorator;
nano::state_block_signature_verification state_block_signature_verification;

Expand Down

0 comments on commit 9c7ea8a

Please sign in to comment.