New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix release #1484

Merged
merged 11 commits into from Dec 21, 2018
@@ -0,0 +1,4 @@
// bitshares-core issue #1479 nodes crashing on self-approving proposal
#ifndef HARDFORK_CORE_1479_TIME
#define HARDFORK_CORE_1479_TIME (fc::time_point_sec( 1545436800 )) // 2018-12-22T00:00:00Z
#endif
@@ -121,7 +121,7 @@
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3

#define GRAPHENE_CURRENT_DB_VERSION "BTS2.181127"
#define GRAPHENE_CURRENT_DB_VERSION "BTS2.181221"

#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)

@@ -28,6 +28,25 @@

namespace graphene { namespace chain {

class hardfork_visitor_1479
{
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:
@@ -37,6 +56,8 @@ namespace graphene { namespace chain {
object_id_type do_apply( const proposal_create_operation& o );

transaction _proposed_trx;

hardfork_visitor_1479 vtor_1479;
};

class proposal_update_evaluator : public evaluator<proposal_update_evaluator>
@@ -113,6 +113,27 @@ struct hardfork_visitor_214 // non-recursive proposal visitor
}
};

void hardfork_visitor_1479::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_1479::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_1479::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();
@@ -128,6 +149,7 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati
for (const op_wrapper &op : o.proposed_ops)
op.op.visit( hf214 );
}
vtor_1479( o );

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

@@ -199,6 +221,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_CORE_1479_TIME )
FC_ASSERT( vtor_1479.nested_update_count == 0 || proposal.id.instance() > vtor_1479.max_update_instance,
"Cannot update/delete a proposal with a future id!" );
else if( vtor_1479.nested_update_count > 0 && proposal.id.instance() <= vtor_1479.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: ${p}", ("p",proposal) );
}
});

return proposal.id;
Copy path View file
@@ -1677,4 +1677,70 @@ BOOST_AUTO_TEST_CASE( issue_214 )
BOOST_CHECK_EQUAL( top.amount.amount.value, get_balance( bob_id, top.amount.asset_id ) );
} FC_LOG_AND_RETHROW() }

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

generate_blocks( HARDFORK_CORE_1479_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_CORE_1479_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 exists
db.get<proposal_object>(pid1);
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()
ProTip! Use n and p to navigate between commits in a pull request.