Skip to content

Commit 58c0c49

Browse files
authored
Merge pull request #1484 from bitshares/release
Bugfix release
2 parents 3aeb5aa + 3eb2cfa commit 58c0c49

File tree

5 files changed

+128
-1
lines changed

5 files changed

+128
-1
lines changed
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// bitshares-core issue #1479 nodes crashing on self-approving proposal
2+
#ifndef HARDFORK_CORE_1479_TIME
3+
#define HARDFORK_CORE_1479_TIME (fc::time_point_sec( 1545436800 )) // 2018-12-22T00:00:00Z
4+
#endif

libraries/chain/include/graphene/chain/config.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
122122
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3
123123

124-
#define GRAPHENE_CURRENT_DB_VERSION "BTS2.181127"
124+
#define GRAPHENE_CURRENT_DB_VERSION "BTS2.181221"
125125

126126
#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)
127127

libraries/chain/include/graphene/chain/proposal_evaluator.hpp

+21
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@
2828

2929
namespace graphene { namespace chain {
3030

31+
class hardfork_visitor_1479
32+
{
33+
public:
34+
typedef void result_type;
35+
36+
uint64_t max_update_instance = 0;
37+
uint64_t nested_update_count = 0;
38+
39+
template<typename T>
40+
void operator()(const T &v) const {}
41+
42+
void operator()(const proposal_update_operation &v);
43+
44+
void operator()(const proposal_delete_operation &v);
45+
46+
// loop and self visit in proposals
47+
void operator()(const graphene::chain::proposal_create_operation &v);
48+
};
49+
3150
class proposal_create_evaluator : public evaluator<proposal_create_evaluator>
3251
{
3352
public:
@@ -37,6 +56,8 @@ namespace graphene { namespace chain {
3756
object_id_type do_apply( const proposal_create_operation& o );
3857

3958
transaction _proposed_trx;
59+
60+
hardfork_visitor_1479 vtor_1479;
4061
};
4162

4263
class proposal_update_evaluator : public evaluator<proposal_update_evaluator>

libraries/chain/proposal_evaluator.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,27 @@ struct hardfork_visitor_214 // non-recursive proposal visitor
113113
}
114114
};
115115

116+
void hardfork_visitor_1479::operator()(const proposal_update_operation &v)
117+
{
118+
if( nested_update_count == 0 || v.proposal.instance.value > max_update_instance )
119+
max_update_instance = v.proposal.instance.value;
120+
nested_update_count++;
121+
}
122+
123+
void hardfork_visitor_1479::operator()(const proposal_delete_operation &v)
124+
{
125+
if( nested_update_count == 0 || v.proposal.instance.value > max_update_instance )
126+
max_update_instance = v.proposal.instance.value;
127+
nested_update_count++;
128+
}
129+
130+
// loop and self visit in proposals
131+
void hardfork_visitor_1479::operator()(const graphene::chain::proposal_create_operation &v)
132+
{
133+
for (const op_wrapper &op : v.proposed_ops)
134+
op.op.visit(*this);
135+
}
136+
116137
void_result proposal_create_evaluator::do_evaluate(const proposal_create_operation& o)
117138
{ try {
118139
const database& d = db();
@@ -128,6 +149,7 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati
128149
for (const op_wrapper &op : o.proposed_ops)
129150
op.op.visit( hf214 );
130151
}
152+
vtor_1479( o );
131153

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

@@ -199,6 +221,20 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati
199221
std::set_difference(required_active.begin(), required_active.end(),
200222
proposal.required_owner_approvals.begin(), proposal.required_owner_approvals.end(),
201223
std::inserter(proposal.required_active_approvals, proposal.required_active_approvals.begin()));
224+
225+
if( d.head_block_time() > HARDFORK_CORE_1479_TIME )
226+
FC_ASSERT( vtor_1479.nested_update_count == 0 || proposal.id.instance() > vtor_1479.max_update_instance,
227+
"Cannot update/delete a proposal with a future id!" );
228+
else if( vtor_1479.nested_update_count > 0 && proposal.id.instance() <= vtor_1479.max_update_instance )
229+
{
230+
// prevent approval
231+
transfer_operation top;
232+
top.from = GRAPHENE_NULL_ACCOUNT;
233+
top.to = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT;
234+
top.amount = asset( GRAPHENE_MAX_SHARE_SUPPLY );
235+
proposal.proposed_transaction.operations.emplace_back( top );
236+
wlog( "Issue 1479: ${p}", ("p",proposal) );
237+
}
202238
});
203239

204240
return proposal.id;

tests/tests/authority_tests.cpp

+66
Original file line numberDiff line numberDiff line change
@@ -1677,4 +1677,70 @@ BOOST_AUTO_TEST_CASE( issue_214 )
16771677
BOOST_CHECK_EQUAL( top.amount.amount.value, get_balance( bob_id, top.amount.asset_id ) );
16781678
} FC_LOG_AND_RETHROW() }
16791679

1680+
BOOST_AUTO_TEST_CASE( self_approving_proposal )
1681+
{ try {
1682+
ACTORS( (alice) );
1683+
fund( alice );
1684+
1685+
generate_blocks( HARDFORK_CORE_1479_TIME );
1686+
trx.clear();
1687+
set_expiration( db, trx );
1688+
1689+
proposal_update_operation pup;
1690+
pup.fee_paying_account = alice_id;
1691+
pup.proposal = proposal_id_type(0);
1692+
pup.active_approvals_to_add.insert( alice_id );
1693+
1694+
proposal_create_operation pop;
1695+
pop.proposed_ops.emplace_back(pup);
1696+
pop.fee_paying_account = alice_id;
1697+
pop.expiration_time = db.head_block_time() + fc::days(1);
1698+
trx.operations.push_back(pop);
1699+
const proposal_id_type pid1 = PUSH_TX( db, trx, ~0 ).operation_results[0].get<object_id_type>();
1700+
trx.clear();
1701+
BOOST_REQUIRE_EQUAL( 0, pid1.instance.value );
1702+
db.get<proposal_object>(pid1);
1703+
1704+
trx.operations.push_back(pup);
1705+
PUSH_TX( db, trx, ~0 );
1706+
1707+
// Proposal failed and still exists
1708+
db.get<proposal_object>(pid1);
1709+
} FC_LOG_AND_RETHROW() }
1710+
1711+
BOOST_AUTO_TEST_CASE( self_deleting_proposal )
1712+
{ try {
1713+
ACTORS( (alice) );
1714+
fund( alice );
1715+
1716+
generate_blocks( HARDFORK_CORE_1479_TIME );
1717+
trx.clear();
1718+
set_expiration( db, trx );
1719+
1720+
proposal_delete_operation pdo;
1721+
pdo.fee_paying_account = alice_id;
1722+
pdo.proposal = proposal_id_type(0);
1723+
pdo.using_owner_authority = false;
1724+
1725+
proposal_create_operation pop;
1726+
pop.proposed_ops.emplace_back( pdo );
1727+
pop.fee_paying_account = alice_id;
1728+
pop.expiration_time = db.head_block_time() + fc::days(1);
1729+
trx.operations.push_back( pop );
1730+
const proposal_id_type pid1 = PUSH_TX( db, trx, ~0 ).operation_results[0].get<object_id_type>();
1731+
trx.clear();
1732+
BOOST_REQUIRE_EQUAL( 0, pid1.instance.value );
1733+
db.get<proposal_object>(pid1);
1734+
1735+
proposal_update_operation pup;
1736+
pup.fee_paying_account = alice_id;
1737+
pup.proposal = proposal_id_type(0);
1738+
pup.active_approvals_to_add.insert( alice_id );
1739+
trx.operations.push_back(pup);
1740+
PUSH_TX( db, trx, ~0 );
1741+
1742+
// Proposal failed and still exists
1743+
db.get<proposal_object>(pid1);
1744+
} FC_LOG_AND_RETHROW() }
1745+
16801746
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)