Skip to content

Commit f182b60

Browse files
Merge pull request #1860 from nathanhourt/bsip40
BSIP40 Implementation
2 parents 7836bcc + 9da10fe commit f182b60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+4321
-84
lines changed

libraries/app/database_api.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <graphene/chain/get_config.hpp>
2929
#include <graphene/chain/hardfork.hpp>
3030
#include <graphene/protocol/pts_address.hpp>
31+
#include <graphene/protocol/restriction_predicate.hpp>
3132

3233
#include <fc/crypto/hex.hpp>
3334
#include <fc/rpc/api_connection.hpp>
@@ -510,7 +511,7 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
510511
// Add the account's balances
511512
const auto& balances = _db.get_index_type< primary_index< account_balance_index > >().
512513
get_secondary_index< balances_by_account_index >().get_account_balances( account->id );
513-
for( const auto balance : balances )
514+
for( const auto& balance : balances )
514515
{
515516
if(acnt.balances.size() >= api_limit_get_full_accounts_lists) {
516517
acnt.more_data_available.balances = true;
@@ -738,7 +739,7 @@ vector<asset> database_api_impl::get_account_balances( const std::string& accoun
738739
const auto& balance_index = _db.get_index_type< primary_index< account_balance_index > >();
739740
const auto& balances = balance_index.get_secondary_index< balances_by_account_index >()
740741
.get_account_balances( acnt );
741-
for( const auto balance : balances )
742+
for( const auto& balance : balances )
742743
result.push_back( balance.second->get_balance() );
743744
}
744745
else
@@ -2002,6 +2003,8 @@ bool database_api_impl::verify_authority( const signed_transaction& trx )const
20022003
trx.verify_authority( _db.get_chain_id(),
20032004
[this]( account_id_type id ){ return &id(_db).active; },
20042005
[this]( account_id_type id ){ return &id(_db).owner; },
2006+
[this]( account_id_type id, const operation& op, rejected_predicate_map* rejects ) {
2007+
return _db.get_viable_custom_authorities(id, op, rejects); },
20052008
allow_non_immediate_owner,
20062009
_db.get_global_properties().parameters.max_authority_depth );
20072010
return true;
@@ -2027,6 +2030,8 @@ bool database_api_impl::verify_account_authority( const string& account_name_or_
20272030
graphene::chain::verify_authority(ops, keys,
20282031
[this]( account_id_type id ){ return &id(_db).active; },
20292032
[this]( account_id_type id ){ return &id(_db).owner; },
2033+
// Use a no-op lookup for custom authorities; we don't want it even if one does apply for our dummy op
2034+
[](auto, auto, auto*) { return vector<authority>(); },
20302035
true, MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(_db.head_block_time()) );
20312036
}
20322037
catch (fc::exception& ex)

libraries/chain/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ add_library( graphene_chain
5555
htlc_evaluator.cpp
5656
confidential_evaluator.cpp
5757
special_authority_evaluation.cpp
58+
custom_authority_evaluator.cpp
5859
buyback.cpp
5960

6061
account_object.cpp

libraries/chain/committee_member_evaluator.cpp

+16-3
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,30 @@ void_result committee_member_update_evaluator::do_apply( const committee_member_
7272
return void_result();
7373
} FC_CAPTURE_AND_RETHROW( (op) ) }
7474

75-
void_result committee_member_update_global_parameters_evaluator::do_evaluate(const committee_member_update_global_parameters_operation& o)
75+
void_result committee_member_update_global_parameters_evaluator::do_evaluate(
76+
const committee_member_update_global_parameters_operation& o)
7677
{ try {
7778
FC_ASSERT(trx_state->_is_proposed_trx);
7879

79-
FC_ASSERT( db().head_block_time() > HARDFORK_CORE_1468_TIME || !o.new_parameters.extensions.value.updatable_htlc_options.valid(),
80+
auto now = db().head_block_time();
81+
FC_ASSERT( now > HARDFORK_CORE_1468_TIME || !o.new_parameters.extensions.value.updatable_htlc_options.valid(),
8082
"Unable to set HTLC parameters until hardfork." );
83+
if (!HARDFORK_BSIP_40_PASSED( now )) {
84+
FC_ASSERT( !o.new_parameters.extensions.value.custom_authority_options.valid(),
85+
"Unable to set Custom Authority Options until hardfork BSIP 40." );
86+
FC_ASSERT( !o.new_parameters.current_fees->exists<custom_authority_create_operation>(),
87+
"Unable to set Custom Authority operation fees until hardfork BSIP 40." );
88+
FC_ASSERT( !o.new_parameters.current_fees->exists<custom_authority_update_operation>(),
89+
"Unable to set Custom Authority operation fees until hardfork BSIP 40." );
90+
FC_ASSERT( !o.new_parameters.current_fees->exists<custom_authority_delete_operation>(),
91+
"Unable to set Custom Authority operation fees until hardfork BSIP 40." );
92+
}
8193

8294
return void_result();
8395
} FC_CAPTURE_AND_RETHROW( (o) ) }
8496

85-
void_result committee_member_update_global_parameters_evaluator::do_apply(const committee_member_update_global_parameters_operation& o)
97+
void_result committee_member_update_global_parameters_evaluator::do_apply(
98+
const committee_member_update_global_parameters_operation& o)
8699
{ try {
87100
db().modify(db().get_global_properties(), [&o](global_property_object& p) {
88101
p.pending_parameters = o.new_parameters;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* Copyright (c) 2019 Contributors.
3+
*
4+
* The MIT License
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#include <graphene/chain/custom_authority_evaluator.hpp>
26+
#include <graphene/chain/custom_authority_object.hpp>
27+
#include <graphene/chain/account_object.hpp>
28+
#include <graphene/chain/database.hpp>
29+
#include <graphene/chain/exceptions.hpp>
30+
#include <graphene/chain/hardfork_visitor.hpp>
31+
32+
namespace graphene { namespace chain {
33+
34+
void_result custom_authority_create_evaluator::do_evaluate(const custom_authority_create_operation& op)
35+
{ try {
36+
const database& d = db();
37+
auto now = d.head_block_time();
38+
FC_ASSERT(HARDFORK_BSIP_40_PASSED(now), "Custom active authorities are not yet enabled");
39+
40+
op.account(d);
41+
42+
const auto& config = d.get_global_properties().parameters.extensions.value.custom_authority_options;
43+
FC_ASSERT(config.valid(), "Cannot use custom authorities yet: global configuration not set");
44+
FC_ASSERT(op.valid_to > now, "Custom authority expiration must be in the future");
45+
FC_ASSERT((op.valid_to - now).to_seconds() <= config->max_custom_authority_lifetime_seconds,
46+
"Custom authority lifetime exceeds maximum limit");
47+
48+
bool operation_forked_in = hardfork_visitor(now).visit((operation::tag_type)op.operation_type.value);
49+
FC_ASSERT(operation_forked_in, "Cannot create custom authority for operation which is not valid yet");
50+
51+
auto restriction_count = restriction::restriction_count(op.restrictions);
52+
FC_ASSERT(restriction_count <= config->max_custom_authority_restrictions,
53+
"Custom authority has more than the maximum number of restrictions");
54+
55+
for (const auto& account_weight_pair : op.auth.account_auths)
56+
account_weight_pair.first(d);
57+
58+
const auto& index = d.get_index_type<custom_authority_index>().indices().get<by_account_custom>();
59+
auto range = index.equal_range(op.account);
60+
FC_ASSERT(std::distance(range.first, range.second) < config->max_custom_authorities_per_account,
61+
"Cannot create custom authority: account already has maximum number");
62+
range = index.equal_range(boost::make_tuple(op.account, op.operation_type));
63+
FC_ASSERT(std::distance(range.first, range.second) < config->max_custom_authorities_per_account_op,
64+
"Cannot create custom authority: account already has maximum number for this operation type");
65+
66+
return void_result();
67+
} FC_CAPTURE_AND_RETHROW((op)) }
68+
69+
object_id_type custom_authority_create_evaluator::do_apply(const custom_authority_create_operation& op)
70+
{ try {
71+
database& d = db();
72+
73+
return d.create<custom_authority_object>([&op] (custom_authority_object& obj) mutable {
74+
obj.account = op.account;
75+
obj.enabled = op.enabled;
76+
obj.valid_from = op.valid_from;
77+
obj.valid_to = op.valid_to;
78+
obj.operation_type = op.operation_type;
79+
obj.auth = op.auth;
80+
std::for_each(op.restrictions.begin(), op.restrictions.end(), [&obj](const restriction& r) mutable {
81+
obj.restrictions.insert(std::make_pair(obj.restriction_counter++, r));
82+
});
83+
}).id;
84+
} FC_CAPTURE_AND_RETHROW((op)) }
85+
86+
void_result custom_authority_update_evaluator::do_evaluate(const custom_authority_update_operation& op)
87+
{ try {
88+
const database& d = db();
89+
auto now = d.head_block_time();
90+
old_object = &op.authority_to_update(d);
91+
FC_ASSERT(old_object->account == op.account, "Cannot update a different account's custom authority");
92+
93+
if (op.new_enabled)
94+
FC_ASSERT(*op.new_enabled != old_object->enabled,
95+
"Custom authority update specifies an enabled flag, but flag is not changed");
96+
97+
const auto& config = d.get_global_properties().parameters.extensions.value.custom_authority_options;
98+
auto valid_from = old_object->valid_from;
99+
auto valid_to = old_object->valid_to;
100+
if (op.new_valid_from) {
101+
FC_ASSERT(*op.new_valid_from != old_object->valid_from,
102+
"Custom authority update specifies a new valid from date, but date is not changed");
103+
valid_from = *op.new_valid_from;
104+
}
105+
if (op.new_valid_to) {
106+
FC_ASSERT(*op.new_valid_to != old_object->valid_to,
107+
"Custom authority update specifies a new valid to date, but date is not changed");
108+
FC_ASSERT(*op.new_valid_to > now, "Custom authority expiration must be in the future");
109+
FC_ASSERT((*op.new_valid_to - now).to_seconds() <= config->max_custom_authority_lifetime_seconds,
110+
"Custom authority lifetime exceeds maximum limit");
111+
valid_to = *op.new_valid_to;
112+
}
113+
FC_ASSERT(valid_from < valid_to, "Custom authority validity begin date must be before expiration date");
114+
115+
if (op.new_auth) {
116+
FC_ASSERT(*op.new_auth != old_object->auth,
117+
"Custom authority update specifies a new authentication authority, but authority is not changed");
118+
for (const auto& account_weight_pair : op.new_auth->account_auths)
119+
account_weight_pair.first(d);
120+
}
121+
122+
std::for_each(op.restrictions_to_remove.begin(), op.restrictions_to_remove.end(), [this](uint16_t id) {
123+
FC_ASSERT(old_object->restrictions.count(id) == 1, "Cannot remove restriction ID ${I}: ID not found",
124+
("I", id));
125+
});
126+
if (!op.restrictions_to_add.empty()) {
127+
// Sanity check
128+
if (!old_object->restrictions.empty())
129+
FC_ASSERT((--old_object->restrictions.end())->first < old_object->restriction_counter,
130+
"LOGIC ERROR: Restriction counter overlaps restrictions. Please report this error.");
131+
FC_ASSERT(old_object->restriction_counter + op.restrictions_to_add.size() > old_object->restriction_counter,
132+
"Unable to add restrictions: causes wraparound of restriction IDs");
133+
}
134+
135+
// Add up the restriction counts for all old restrictions not being removed, and all new ones
136+
size_t restriction_count = 0;
137+
for (const auto& restriction_pair : old_object->restrictions)
138+
if (op.restrictions_to_remove.count(restriction_pair.first) == 0)
139+
restriction_count += restriction_pair.second.restriction_count();
140+
restriction_count += restriction::restriction_count(op.restrictions_to_add);
141+
// Check restriction count against limit
142+
FC_ASSERT(restriction_count <= config->max_custom_authority_restrictions,
143+
"Cannot update custom authority: updated authority would exceed the maximum number of restrictions");
144+
145+
get_restriction_predicate(op.restrictions_to_add, old_object->operation_type);
146+
return void_result();
147+
} FC_CAPTURE_AND_RETHROW((op)) }
148+
149+
void_result custom_authority_update_evaluator::do_apply(const custom_authority_update_operation& op)
150+
{ try {
151+
database& d = db();
152+
153+
d.modify(*old_object, [&op](custom_authority_object& obj) {
154+
if (op.new_enabled) obj.enabled = *op.new_enabled;
155+
if (op.new_valid_from) obj.valid_from = *op.new_valid_from;
156+
if (op.new_valid_to) obj.valid_to = *op.new_valid_to;
157+
if (op.new_auth) obj.auth = *op.new_auth;
158+
159+
std::for_each(op.restrictions_to_remove.begin(), op.restrictions_to_remove.end(), [&obj](auto id) mutable {
160+
obj.restrictions.erase(id);
161+
});
162+
std::for_each(op.restrictions_to_add.begin(), op.restrictions_to_add.end(), [&obj](const auto& r) mutable {
163+
obj.restrictions.insert(std::make_pair(obj.restriction_counter++, r));
164+
});
165+
166+
// Clear the predicate cache
167+
obj.clear_predicate_cache();
168+
});
169+
170+
return void_result();
171+
} FC_CAPTURE_AND_RETHROW((op)) }
172+
173+
void_result custom_authority_delete_evaluator::do_evaluate(const custom_authority_delete_operation& op)
174+
{ try {
175+
const database& d = db();
176+
177+
old_object = &op.authority_to_delete(d);
178+
FC_ASSERT(old_object->account == op.account, "Cannot delete a different account's custom authority");
179+
180+
return void_result();
181+
} FC_CAPTURE_AND_RETHROW((op)) }
182+
183+
void_result custom_authority_delete_evaluator::do_apply(const custom_authority_delete_operation& op)
184+
{ try {
185+
database& d = db();
186+
187+
d.remove(*old_object);
188+
189+
return void_result();
190+
} FC_CAPTURE_AND_RETHROW((op)) }
191+
192+
} } // graphene::chain

libraries/chain/db_block.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,11 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
651651
bool allow_non_immediate_owner = ( head_block_time() >= HARDFORK_CORE_584_TIME );
652652
auto get_active = [this]( account_id_type id ) { return &id(*this).active; };
653653
auto get_owner = [this]( account_id_type id ) { return &id(*this).owner; };
654+
auto get_custom = [this]( account_id_type id, const operation& op, rejected_predicate_map* rejects ) {
655+
return get_viable_custom_authorities(id, op, rejects);
656+
};
654657

655-
trx.verify_authority(chain_id, get_active, get_owner, allow_non_immediate_owner,
658+
trx.verify_authority(chain_id, get_active, get_owner, get_custom, allow_non_immediate_owner,
656659
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(head_block_time()),
657660
get_global_properties().parameters.max_authority_depth);
658661
}

libraries/chain/db_getter.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <graphene/chain/asset_object.hpp>
2828
#include <graphene/chain/chain_property_object.hpp>
2929
#include <graphene/chain/global_property_object.hpp>
30+
#include <graphene/chain/custom_authority_object.hpp>
3031

3132
namespace graphene { namespace chain {
3233

@@ -95,6 +96,33 @@ node_property_object& database::node_properties()
9596
return _node_property_object;
9697
}
9798

99+
vector<authority> database::get_viable_custom_authorities(
100+
account_id_type account, const operation &op,
101+
rejected_predicate_map* rejected_authorities) const
102+
{
103+
const auto& index = get_index_type<custom_authority_index>().indices().get<by_account_custom>();
104+
auto range = index.equal_range(boost::make_tuple(account, unsigned_int(op.which()), true));
105+
106+
auto is_valid = [now=head_block_time()](const custom_authority_object& auth) { return auth.is_valid(now); };
107+
vector<std::reference_wrapper<const custom_authority_object>> valid_auths;
108+
std::copy_if(range.first, range.second, std::back_inserter(valid_auths), is_valid);
109+
110+
vector<authority> results;
111+
for (const auto& cust_auth : valid_auths) {
112+
try {
113+
auto result = cust_auth.get().get_predicate()(op);
114+
if (result.success)
115+
results.emplace_back(cust_auth.get().auth);
116+
else if (rejected_authorities != nullptr)
117+
rejected_authorities->insert(std::make_pair(cust_auth.get().id, std::move(result)));
118+
} catch (fc::exception& e) {
119+
rejected_authorities->insert(std::make_pair(cust_auth.get().id, std::move(e)));
120+
}
121+
}
122+
123+
return results;
124+
}
125+
98126
uint32_t database::last_non_undoable_block_num() const
99127
{
100128
//see https://github.com/bitshares/bitshares-core/issues/377

libraries/chain/db_init.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <graphene/chain/witness_schedule_object.hpp>
4848
#include <graphene/chain/worker_object.hpp>
4949
#include <graphene/chain/htlc_object.hpp>
50+
#include <graphene/chain/custom_authority_object.hpp>
5051

5152
#include <graphene/chain/account_evaluator.hpp>
5253
#include <graphene/chain/asset_evaluator.hpp>
@@ -63,6 +64,7 @@
6364
#include <graphene/chain/witness_evaluator.hpp>
6465
#include <graphene/chain/worker_evaluator.hpp>
6566
#include <graphene/chain/htlc_evaluator.hpp>
67+
#include <graphene/chain/custom_authority_evaluator.hpp>
6668

6769
#include <fc/crypto/digest.hpp>
6870

@@ -127,6 +129,8 @@ const uint8_t worker_object::type_id;
127129
const uint8_t htlc_object::space_id;
128130
const uint8_t htlc_object::type_id;
129131

132+
const uint8_t custom_authority_object::space_id;
133+
const uint8_t custom_authority_object::type_id;
130134

131135
void database::initialize_evaluators()
132136
{
@@ -178,6 +182,9 @@ void database::initialize_evaluators()
178182
register_evaluator<htlc_create_evaluator>();
179183
register_evaluator<htlc_redeem_evaluator>();
180184
register_evaluator<htlc_extend_evaluator>();
185+
register_evaluator<custom_authority_create_evaluator>();
186+
register_evaluator<custom_authority_update_evaluator>();
187+
register_evaluator<custom_authority_delete_evaluator>();
181188
}
182189

183190
void database::initialize_indexes()
@@ -207,6 +214,7 @@ void database::initialize_indexes()
207214
add_index< primary_index<balance_index> >();
208215
add_index< primary_index<blinded_balance_index> >();
209216
add_index< primary_index< htlc_index> >();
217+
add_index< primary_index< custom_authority_index> >();
210218

211219
//Implementation object indexes
212220
add_index< primary_index<transaction_index > >();

0 commit comments

Comments
 (0)