Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libraries/chain/hardfork.d/1002.hf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#ifndef HARDFORK_1002_TIME
#define HARDFORK_1002_TIME (fc::time_point_sec( 1566927111 )) // 08/27/2019 5:31pm (UTC)
#endif
21 changes: 21 additions & 0 deletions libraries/chain/include/graphene/chain/proposal_evaluator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@

namespace graphene { namespace chain {

class hardfork_visitor_1002
{
public:
typedef void result_type;

uint64_t max_update_instance = 0;
uint64_t nested_update_count = 0;

template<typename T>
void operator()(const T &v) const {}

void operator()(const proposal_update_operation &v);

void operator()(const proposal_delete_operation &v);

// loop and self visit in proposals
void operator()(const graphene::chain::proposal_create_operation &v);
};

class proposal_create_evaluator : public evaluator<proposal_create_evaluator>
{
public:
Expand All @@ -39,6 +58,8 @@ namespace graphene { namespace chain {
object_id_type do_apply( const proposal_create_operation& o );

transaction _proposed_trx;

hardfork_visitor_1002 vtor_1002;
};

class proposal_update_evaluator : public evaluator<proposal_update_evaluator>
Expand Down
36 changes: 36 additions & 0 deletions libraries/chain/proposal_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,34 @@ struct proposal_operation_hardfork_visitor
}
};

void hardfork_visitor_1002::operator()(const proposal_update_operation &v)
{
if( nested_update_count == 0 || v.proposal.instance.value > max_update_instance )
max_update_instance = v.proposal.instance.value;
nested_update_count++;
}

void hardfork_visitor_1002::operator()(const proposal_delete_operation &v)
{
if( nested_update_count == 0 || v.proposal.instance.value > max_update_instance )
max_update_instance = v.proposal.instance.value;
nested_update_count++;
}

// loop and self visit in proposals
void hardfork_visitor_1002::operator()(const graphene::chain::proposal_create_operation &v)
{
for (const op_wrapper &op : v.proposed_ops)
op.op.visit(*this);
}

void_result proposal_create_evaluator::do_evaluate(const proposal_create_operation& o)
{ try {
const database& d = db();

proposal_operation_hardfork_visitor vtor( d.head_block_time() );
vtor( o );
vtor_1002( o );

const auto& global_parameters = d.get_global_properties().parameters;

Expand Down Expand Up @@ -218,6 +240,20 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati
std::set_difference(required_active.begin(), required_active.end(),
proposal.required_owner_approvals.begin(), proposal.required_owner_approvals.end(),
std::inserter(proposal.required_active_approvals, proposal.required_active_approvals.begin()));

if( d.head_block_time() > HARDFORK_1002_TIME )
FC_ASSERT( vtor_1002.nested_update_count == 0 || proposal.id.instance() > vtor_1002.max_update_instance,
"Cannot update/delete a proposal with a future id!" );
else if( vtor_1002.nested_update_count > 0 && proposal.id.instance() <= vtor_1002.max_update_instance )
{
// prevent approval
transfer_operation top;
top.from = GRAPHENE_NULL_ACCOUNT;
top.to = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT;
top.amount = asset( GRAPHENE_MAX_SHARE_SUPPLY );
proposal.proposed_transaction.operations.emplace_back( top );
wlog( "Issue 1479 on BitShares: ${p}", ("p",proposal) );
}
});

return proposal.id;
Expand Down
67 changes: 67 additions & 0 deletions tests/tests/authority_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/committee_member_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/hardfork.hpp>

#include <graphene/db/simple_index.hpp>

Expand Down Expand Up @@ -1316,4 +1317,70 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
}
}

BOOST_AUTO_TEST_CASE( self_approving_proposal )
{ try {
ACTORS( (alice) );
fund( alice );

generate_blocks( HARDFORK_1002_TIME );
trx.clear();
set_expiration( db, trx );

proposal_update_operation pup;
pup.fee_paying_account = alice_id;
pup.proposal = proposal_id_type(0);
pup.active_approvals_to_add.insert( alice_id );

proposal_create_operation pop;
pop.proposed_ops.emplace_back(pup);
pop.fee_paying_account = alice_id;
pop.expiration_time = db.head_block_time() + fc::days(1);
trx.operations.push_back(pop);
const proposal_id_type pid1 = PUSH_TX( db, trx, ~0 ).operation_results[0].get<object_id_type>();
trx.clear();
BOOST_REQUIRE_EQUAL( 0, pid1.instance.value );
db.get<proposal_object>(pid1);

trx.operations.push_back(pup);
PUSH_TX( db, trx, ~0 );

// Proposal failed and still exists
db.get<proposal_object>(pid1);
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE( self_deleting_proposal )
{ try {
ACTORS( (alice) );
fund( alice );

generate_blocks( HARDFORK_1002_TIME );
trx.clear();
set_expiration( db, trx );

proposal_delete_operation pdo;
pdo.fee_paying_account = alice_id;
pdo.proposal = proposal_id_type(0);
pdo.using_owner_authority = false;

proposal_create_operation pop;
pop.proposed_ops.emplace_back( pdo );
pop.fee_paying_account = alice_id;
pop.expiration_time = db.head_block_time() + fc::days(1);
trx.operations.push_back( pop );
const proposal_id_type pid1 = PUSH_TX( db, trx, ~0 ).operation_results[0].get<object_id_type>();
trx.clear();
BOOST_REQUIRE_EQUAL( 0, pid1.instance.value );
db.get<proposal_object>(pid1);

proposal_update_operation pup;
pup.fee_paying_account = alice_id;
pup.proposal = proposal_id_type(0);
pup.active_approvals_to_add.insert( alice_id );
trx.operations.push_back(pup);
PUSH_TX( db, trx, ~0 );

// Proposal failed and still exist
db.get<proposal_object>(pid1);
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()