Skip to content

Commit

Permalink
Adding block_pipeline::epoch_restrictions_filter which only allows ep…
Browse files Browse the repository at this point in the history
…och blocks to pass if they don't modify the state of the account other than its epoch.
  • Loading branch information
clemahieu committed Mar 3, 2022
1 parent 3bbb4c5 commit c28a82f
Show file tree
Hide file tree
Showing 7 changed files with 158 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 @@ -19,6 +19,7 @@ add_executable(
stateless_signer_filter.cpp
election.cpp
election_scheduler.cpp
epoch_restrictions_filter.cpp
epochs.cpp
existing_block_filter.cpp
metastable_filter.cpp
Expand Down
111 changes: 111 additions & 0 deletions nano/core_test/epoch_restrictions_filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include <nano/node/block_pipeline/context.hpp>
#include <nano/node/block_pipeline/epoch_restrictions_filter.hpp>
#include <nano/secure/common.hpp>

#include <gtest/gtest.h>

namespace
{
class context
{
public:
context ()
{
filter.pass = [this] (nano::block_pipeline::context & context) {
pass.push_back (context);
};
filter.reject_balance = [this] (nano::block_pipeline::context & context) {
reject_balance.push_back (context);
};
filter.reject_representative = [this] (nano::block_pipeline::context & context) {
reject_representative.push_back (context);
};
}
nano::block_pipeline::epoch_restrictions_filter filter;
std::vector<nano::block_pipeline::context> pass;
std::vector<nano::block_pipeline::context> reject_balance;
std::vector<nano::block_pipeline::context> reject_representative;
};
nano::block_pipeline::context epoch_pass_blocks ()
{
nano::block_builder builder;
nano::block_pipeline::context result;
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) // Unchanged balance
.link (nano::dev::constants.epochs.link (nano::epoch::epoch_1))
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
result.previous = nano::dev::genesis;
result.state = nano::account_info{};
result.state->balance = nano::dev::constants.genesis_amount;
result.state->representative = nano::dev::genesis_key.pub;
return result;
}
nano::block_pipeline::context epoch_reject_balance_blocks ()
{
nano::block_builder builder;
nano::block_pipeline::context result;
result.block = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub) // Unchacked representative
.balance (nano::dev::constants.genesis_amount - 1)
.link (nano::dev::constants.epochs.link (nano::epoch::epoch_1))
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
result.previous = nano::dev::genesis;
result.state = nano::account_info{};
result.state->balance = nano::dev::constants.genesis_amount; // Changed balance
result.state->representative = nano::dev::genesis_key.pub;
return result;
}
nano::block_pipeline::context epoch_reject_representative_blocks ()
{
nano::block_builder builder;
nano::block_pipeline::context result;
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) // Unchanged balance
.link (nano::dev::constants.epochs.link (nano::epoch::epoch_1))
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (0)
.build_shared ();
result.previous = nano::dev::genesis;
result.state = nano::account_info{};
result.state->balance = nano::dev::constants.genesis_amount;
nano::keypair dummy;
result.state->representative = dummy.pub; // Changed representative
return result;
}
}

TEST (epoch_restrictions_filter, epoch_pass)
{
context context;
auto blocks = epoch_pass_blocks ();
context.filter.sink (blocks);
ASSERT_EQ (1, context.pass.size ());
}

TEST (epoch_restrictions_filter, epoch_reject_balance)
{
context context;
auto blocks = epoch_reject_balance_blocks ();
context.filter.sink (blocks);
ASSERT_EQ (1, context.reject_balance.size ());
}

TEST (epoch_restrictions_filter, epoch_reject_representative)
{
context context;
auto blocks = epoch_reject_representative_blocks ();
context.filter.sink (blocks);
ASSERT_EQ (1, context.reject_representative.size ());
}
2 changes: 2 additions & 0 deletions nano/node/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ add_library(
block_pipeline/block_position_filter.hpp
block_pipeline/context.cpp
block_pipeline/context.hpp
block_pipeline/epoch_restrictions_filter.cpp
block_pipeline/epoch_restrictions_filter.hpp
block_pipeline/existing_block_filter.cpp
block_pipeline/existing_block_filter.hpp
block_pipeline/link_filter.cpp
Expand Down
2 changes: 1 addition & 1 deletion nano/node/block_pipeline/account_state_decorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ nano::block_pipeline::account_state_decorator::account_state_decorator (nano::le

void nano::block_pipeline::account_state_decorator::sink (context & context) const
{
context.info = ledger.account_info (ledger.store.tx_begin_read (), context.account ());
context.state = ledger.account_info (ledger.store.tx_begin_read (), context.account ());
output (context);
}
18 changes: 18 additions & 0 deletions nano/node/block_pipeline/epoch_restrictions_filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <nano/node/block_pipeline/context.hpp>
#include <nano/node/block_pipeline/epoch_restrictions_filter.hpp>

void nano::block_pipeline::epoch_restrictions_filter::sink (context & context)
{
debug_assert (context.state.has_value ());
if (context.state->balance != context.block->balance ())
{
reject_balance (context);
return;
}
if (context.state->representative != context.block->representative ())
{
reject_representative (context);
return;
}
pass (context);
}
23 changes: 23 additions & 0 deletions nano/node/block_pipeline/epoch_restrictions_filter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <functional>

namespace nano
{
namespace block_pipeline
{
class context;
/**
This filter checks the restrictions on epoch blocks.
Epoch blocks cannot change the state of an account other than changing the account's epoch
*/
class epoch_restrictions_filter
{
public:
void sink (context & context);
std::function<void (context & context)> pass;
std::function<void (context & context)> reject_balance;
std::function<void (context & context)> reject_representative;
};
}
}
2 changes: 2 additions & 0 deletions nano/node/blockprocessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <nano/node/block_pipeline/account_state_decorator.hpp>
#include <nano/node/block_pipeline/block_position_filter.hpp>
#include <nano/node/block_pipeline/context.hpp>
#include <nano/node/block_pipeline/epoch_restrictions_filter.hpp>
#include <nano/node/block_pipeline/existing_block_filter.hpp>
#include <nano/node/block_pipeline/gap_previous_filter.hpp>
#include <nano/node/block_pipeline/link_filter.hpp>
Expand Down Expand Up @@ -111,6 +112,7 @@ class block_processor final
nano::block_pipeline::account_state_decorator account_state;
nano::block_pipeline::metastable_filter metastable;
nano::block_pipeline::link_filter link;
nano::block_pipeline::epoch_restrictions_filter epoch_restrictions;
nano::block_pipeline::signer_decorator signer_decorator;
nano::state_block_signature_verification state_block_signature_verification;

Expand Down

0 comments on commit c28a82f

Please sign in to comment.