Skip to content
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

BSIP40 Implementation #1860

Merged
merged 42 commits into from
Oct 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4e70e87
BSIP 40: Core implementation
nathanielhourt Jul 17, 2019
794f1ab
BSIP 40: Improve build time, update docs
nathanielhourt Jul 18, 2019
0a588c1
BSIP 40: Finish writing operations
nathanielhourt Jul 19, 2019
32cdad8
BSIP 40: Add database object
nathanielhourt Jul 19, 2019
18394fe
BSIP 40: Add evaluators, transaction eval code, testing
nathanielhourt Jul 20, 2019
1c9d74e
BSIP 40: Fixes from code review
nathanielhourt Jul 20, 2019
969999b
BSIP 40: Restrictions use member index rather than name
nathanielhourt Jul 22, 2019
ab4a262
BSIP 40: Fix build on old G++
nathanielhourt Jul 24, 2019
a2a5801
BSIP 40: Best build
nathanielhourt Jul 31, 2019
636abb0
BSIP 40: Delete expired authorities in maintenance
nathanielhourt Aug 2, 2019
d28f68c
BSIP 40: Refactor predicates
nathanielhourt Aug 5, 2019
ef87594
BSIP 40: Reduce build RAM usage
nathanielhourt Aug 5, 2019
2e0615a
BSIP 40: Cleanup, disable sign-compare warnings on g++
nathanielhourt Aug 5, 2019
5f49a94
Disable sonar/gcov as it is hanging
nathanielhourt Aug 5, 2019
e6fef06
BSIP 40: Assign restrictions stable IDs
nathanielhourt Aug 7, 2019
fde930b
BSIP 40: Re-enable coverage, but exclude custom authorities code
nathanielhourt Aug 7, 2019
6566995
BSIP 40: Error reporting, part 1
nathanielhourt Aug 9, 2019
58e7ae5
BSIP 40: Make Travis use multi-stage build
nathanielhourt Aug 9, 2019
0ff414f
BSIP 40: [TEMPORARY] Workaround Travis failures
nathanielhourt Aug 9, 2019
e72835b
BSIP 40: Error reporting, part 2
nathanielhourt Aug 10, 2019
670b474
BSIP 40: Add hardfork_visitor
nathanielhourt Aug 11, 2019
de5049a
BSIP 40: Fix build in MSVC 2017
nathanielhourt Aug 12, 2019
d01a8d0
BSIP 40: Use safe signed/unsigned comparisons
nathanielhourt Aug 12, 2019
c02fb98
BSIP 40: Ship a copy of boost's safe_compare.hpp
nathanielhourt Aug 12, 2019
66d1835
BSIP 40: Error handling & static_variant restrictions
nathanielhourt Aug 16, 2019
f3bf343
BSIP 40: Merge/Review Fixes
nathanielhourt Aug 20, 2019
ad7f5ed
BSIP 40: Rebase fixes
nathanielhourt Sep 17, 2019
dbafa02
BSIP 40: Reverse order of predicate rejection paths
nathanielhourt Sep 17, 2019
dd75b13
BSIP 40: Unit test comments
MichelSantos Aug 30, 2019
9574d18
BSIP 40: Authorization and revocation of multiple concurrent CAA
MichelSantos Sep 7, 2019
88f5fd1
BSIP 40: Authorizations of multiple users with a single CAA containin…
MichelSantos Sep 9, 2019
69acd0d
BSIP 40: Unit test for CAA trading
MichelSantos Sep 20, 2019
7429cc4
BSIP 40: Unit test of feed publishing CAA for an account
MichelSantos Sep 20, 2019
7486c9c
BSIP 40: Unit test of feed publishing CAA for a key
MichelSantos Sep 21, 2019
af4cea7
BSIP 40: Unit test of faucet key CAA
MichelSantos Sep 21, 2019
58d556d
BSIP 40: Unit test of cold storage key CAA
MichelSantos Sep 23, 2019
ddc8725
Update custom_authority_tests.cpp
nathanielhourt Oct 18, 2019
4d95742
Merge pull request #3 from MichelSantos/bsip40-unit-tests
nathanielhourt Oct 18, 2019
e658bdd
BSIP 40: Changes from code review
nathanielhourt Oct 19, 2019
51da97d
BSIP 40: Code review, round 2
nathanielhourt Oct 20, 2019
41d27a2
BSIP 40: Add container in and not_in specializations
nathanielhourt Oct 20, 2019
9da10fe
BSIP 40: Maybe fix travis?
nathanielhourt Oct 20, 2019
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
9 changes: 7 additions & 2 deletions libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <graphene/chain/get_config.hpp>
#include <graphene/chain/hardfork.hpp>
#include <graphene/protocol/pts_address.hpp>
#include <graphene/protocol/restriction_predicate.hpp>

#include <fc/crypto/hex.hpp>
#include <fc/rpc/api_connection.hpp>
Expand Down Expand Up @@ -510,7 +511,7 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
// Add the account's balances
const auto& balances = _db.get_index_type< primary_index< account_balance_index > >().
get_secondary_index< balances_by_account_index >().get_account_balances( account->id );
for( const auto balance : balances )
for( const auto& balance : balances )
{
if(acnt.balances.size() >= api_limit_get_full_accounts_lists) {
acnt.more_data_available.balances = true;
Expand Down Expand Up @@ -738,7 +739,7 @@ vector<asset> database_api_impl::get_account_balances( const std::string& accoun
const auto& balance_index = _db.get_index_type< primary_index< account_balance_index > >();
const auto& balances = balance_index.get_secondary_index< balances_by_account_index >()
.get_account_balances( acnt );
for( const auto balance : balances )
for( const auto& balance : balances )
result.push_back( balance.second->get_balance() );
}
else
Expand Down Expand Up @@ -2002,6 +2003,8 @@ bool database_api_impl::verify_authority( const signed_transaction& trx )const
trx.verify_authority( _db.get_chain_id(),
[this]( account_id_type id ){ return &id(_db).active; },
[this]( account_id_type id ){ return &id(_db).owner; },
[this]( account_id_type id, const operation& op, rejected_predicate_map* rejects ) {
return _db.get_viable_custom_authorities(id, op, rejects); },
allow_non_immediate_owner,
_db.get_global_properties().parameters.max_authority_depth );
return true;
Expand All @@ -2027,6 +2030,8 @@ bool database_api_impl::verify_account_authority( const string& account_name_or_
graphene::chain::verify_authority(ops, keys,
[this]( account_id_type id ){ return &id(_db).active; },
[this]( account_id_type id ){ return &id(_db).owner; },
// Use a no-op lookup for custom authorities; we don't want it even if one does apply for our dummy op
[](auto, auto, auto*) { return vector<authority>(); },
true, MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(_db.head_block_time()) );
}
catch (fc::exception& ex)
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ add_library( graphene_chain
htlc_evaluator.cpp
confidential_evaluator.cpp
special_authority_evaluation.cpp
custom_authority_evaluator.cpp
buyback.cpp

account_object.cpp
Expand Down
19 changes: 16 additions & 3 deletions libraries/chain/committee_member_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,30 @@ void_result committee_member_update_evaluator::do_apply( const committee_member_
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }

void_result committee_member_update_global_parameters_evaluator::do_evaluate(const committee_member_update_global_parameters_operation& o)
void_result committee_member_update_global_parameters_evaluator::do_evaluate(
const committee_member_update_global_parameters_operation& o)
{ try {
FC_ASSERT(trx_state->_is_proposed_trx);

FC_ASSERT( db().head_block_time() > HARDFORK_CORE_1468_TIME || !o.new_parameters.extensions.value.updatable_htlc_options.valid(),
auto now = db().head_block_time();
FC_ASSERT( now > HARDFORK_CORE_1468_TIME || !o.new_parameters.extensions.value.updatable_htlc_options.valid(),
"Unable to set HTLC parameters until hardfork." );
if (!HARDFORK_BSIP_40_PASSED( now )) {
FC_ASSERT( !o.new_parameters.extensions.value.custom_authority_options.valid(),
"Unable to set Custom Authority Options until hardfork BSIP 40." );
FC_ASSERT( !o.new_parameters.current_fees->exists<custom_authority_create_operation>(),
"Unable to set Custom Authority operation fees until hardfork BSIP 40." );
FC_ASSERT( !o.new_parameters.current_fees->exists<custom_authority_update_operation>(),
"Unable to set Custom Authority operation fees until hardfork BSIP 40." );
FC_ASSERT( !o.new_parameters.current_fees->exists<custom_authority_delete_operation>(),
"Unable to set Custom Authority operation fees until hardfork BSIP 40." );
}

return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }

void_result committee_member_update_global_parameters_evaluator::do_apply(const committee_member_update_global_parameters_operation& o)
void_result committee_member_update_global_parameters_evaluator::do_apply(
const committee_member_update_global_parameters_operation& o)
{ try {
db().modify(db().get_global_properties(), [&o](global_property_object& p) {
p.pending_parameters = o.new_parameters;
Expand Down
192 changes: 192 additions & 0 deletions libraries/chain/custom_authority_evaluator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*
* Copyright (c) 2019 Contributors.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <graphene/chain/custom_authority_evaluator.hpp>
#include <graphene/chain/custom_authority_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/hardfork_visitor.hpp>

namespace graphene { namespace chain {

void_result custom_authority_create_evaluator::do_evaluate(const custom_authority_create_operation& op)
{ try {
const database& d = db();
auto now = d.head_block_time();
FC_ASSERT(HARDFORK_BSIP_40_PASSED(now), "Custom active authorities are not yet enabled");
nathanielhourt marked this conversation as resolved.
Show resolved Hide resolved

op.account(d);

const auto& config = d.get_global_properties().parameters.extensions.value.custom_authority_options;
FC_ASSERT(config.valid(), "Cannot use custom authorities yet: global configuration not set");
FC_ASSERT(op.valid_to > now, "Custom authority expiration must be in the future");
FC_ASSERT((op.valid_to - now).to_seconds() <= config->max_custom_authority_lifetime_seconds,
"Custom authority lifetime exceeds maximum limit");

bool operation_forked_in = hardfork_visitor(now).visit((operation::tag_type)op.operation_type.value);
FC_ASSERT(operation_forked_in, "Cannot create custom authority for operation which is not valid yet");

auto restriction_count = restriction::restriction_count(op.restrictions);
FC_ASSERT(restriction_count <= config->max_custom_authority_restrictions,
"Custom authority has more than the maximum number of restrictions");

for (const auto& account_weight_pair : op.auth.account_auths)
account_weight_pair.first(d);

const auto& index = d.get_index_type<custom_authority_index>().indices().get<by_account_custom>();
auto range = index.equal_range(op.account);
FC_ASSERT(std::distance(range.first, range.second) < config->max_custom_authorities_per_account,
"Cannot create custom authority: account already has maximum number");
range = index.equal_range(boost::make_tuple(op.account, op.operation_type));
FC_ASSERT(std::distance(range.first, range.second) < config->max_custom_authorities_per_account_op,
"Cannot create custom authority: account already has maximum number for this operation type");

return void_result();
} FC_CAPTURE_AND_RETHROW((op)) }

object_id_type custom_authority_create_evaluator::do_apply(const custom_authority_create_operation& op)
{ try {
database& d = db();

return d.create<custom_authority_object>([&op] (custom_authority_object& obj) mutable {
obj.account = op.account;
obj.enabled = op.enabled;
obj.valid_from = op.valid_from;
obj.valid_to = op.valid_to;
obj.operation_type = op.operation_type;
obj.auth = op.auth;
std::for_each(op.restrictions.begin(), op.restrictions.end(), [&obj](const restriction& r) mutable {
obj.restrictions.insert(std::make_pair(obj.restriction_counter++, r));
});
}).id;
} FC_CAPTURE_AND_RETHROW((op)) }

void_result custom_authority_update_evaluator::do_evaluate(const custom_authority_update_operation& op)
{ try {
const database& d = db();
auto now = d.head_block_time();
old_object = &op.authority_to_update(d);
FC_ASSERT(old_object->account == op.account, "Cannot update a different account's custom authority");

if (op.new_enabled)
FC_ASSERT(*op.new_enabled != old_object->enabled,
"Custom authority update specifies an enabled flag, but flag is not changed");

const auto& config = d.get_global_properties().parameters.extensions.value.custom_authority_options;
auto valid_from = old_object->valid_from;
auto valid_to = old_object->valid_to;
if (op.new_valid_from) {
FC_ASSERT(*op.new_valid_from != old_object->valid_from,
"Custom authority update specifies a new valid from date, but date is not changed");
valid_from = *op.new_valid_from;
}
if (op.new_valid_to) {
FC_ASSERT(*op.new_valid_to != old_object->valid_to,
"Custom authority update specifies a new valid to date, but date is not changed");
FC_ASSERT(*op.new_valid_to > now, "Custom authority expiration must be in the future");
FC_ASSERT((*op.new_valid_to - now).to_seconds() <= config->max_custom_authority_lifetime_seconds,
"Custom authority lifetime exceeds maximum limit");
valid_to = *op.new_valid_to;
}
FC_ASSERT(valid_from < valid_to, "Custom authority validity begin date must be before expiration date");

if (op.new_auth) {
FC_ASSERT(*op.new_auth != old_object->auth,
"Custom authority update specifies a new authentication authority, but authority is not changed");
for (const auto& account_weight_pair : op.new_auth->account_auths)
account_weight_pair.first(d);
}

std::for_each(op.restrictions_to_remove.begin(), op.restrictions_to_remove.end(), [this](uint16_t id) {
FC_ASSERT(old_object->restrictions.count(id) == 1, "Cannot remove restriction ID ${I}: ID not found",
("I", id));
});
if (!op.restrictions_to_add.empty()) {
// Sanity check
if (!old_object->restrictions.empty())
FC_ASSERT((--old_object->restrictions.end())->first < old_object->restriction_counter,
"LOGIC ERROR: Restriction counter overlaps restrictions. Please report this error.");
FC_ASSERT(old_object->restriction_counter + op.restrictions_to_add.size() > old_object->restriction_counter,
"Unable to add restrictions: causes wraparound of restriction IDs");
}

// Add up the restriction counts for all old restrictions not being removed, and all new ones
size_t restriction_count = 0;
for (const auto& restriction_pair : old_object->restrictions)
if (op.restrictions_to_remove.count(restriction_pair.first) == 0)
restriction_count += restriction_pair.second.restriction_count();
restriction_count += restriction::restriction_count(op.restrictions_to_add);
// Check restriction count against limit
FC_ASSERT(restriction_count <= config->max_custom_authority_restrictions,
"Cannot update custom authority: updated authority would exceed the maximum number of restrictions");

get_restriction_predicate(op.restrictions_to_add, old_object->operation_type);
return void_result();
} FC_CAPTURE_AND_RETHROW((op)) }

void_result custom_authority_update_evaluator::do_apply(const custom_authority_update_operation& op)
{ try {
database& d = db();

d.modify(*old_object, [&op](custom_authority_object& obj) {
if (op.new_enabled) obj.enabled = *op.new_enabled;
if (op.new_valid_from) obj.valid_from = *op.new_valid_from;
if (op.new_valid_to) obj.valid_to = *op.new_valid_to;
if (op.new_auth) obj.auth = *op.new_auth;

std::for_each(op.restrictions_to_remove.begin(), op.restrictions_to_remove.end(), [&obj](auto id) mutable {
obj.restrictions.erase(id);
});
std::for_each(op.restrictions_to_add.begin(), op.restrictions_to_add.end(), [&obj](const auto& r) mutable {
obj.restrictions.insert(std::make_pair(obj.restriction_counter++, r));
});

// Clear the predicate cache
obj.clear_predicate_cache();
});

return void_result();
} FC_CAPTURE_AND_RETHROW((op)) }

void_result custom_authority_delete_evaluator::do_evaluate(const custom_authority_delete_operation& op)
{ try {
const database& d = db();

old_object = &op.authority_to_delete(d);
FC_ASSERT(old_object->account == op.account, "Cannot delete a different account's custom authority");

return void_result();
} FC_CAPTURE_AND_RETHROW((op)) }

void_result custom_authority_delete_evaluator::do_apply(const custom_authority_delete_operation& op)
{ try {
database& d = db();

d.remove(*old_object);

return void_result();
} FC_CAPTURE_AND_RETHROW((op)) }

} } // graphene::chain
5 changes: 4 additions & 1 deletion libraries/chain/db_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,11 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
bool allow_non_immediate_owner = ( head_block_time() >= HARDFORK_CORE_584_TIME );
auto get_active = [this]( account_id_type id ) { return &id(*this).active; };
auto get_owner = [this]( account_id_type id ) { return &id(*this).owner; };
auto get_custom = [this]( account_id_type id, const operation& op, rejected_predicate_map* rejects ) {
return get_viable_custom_authorities(id, op, rejects);
};

trx.verify_authority(chain_id, get_active, get_owner, allow_non_immediate_owner,
trx.verify_authority(chain_id, get_active, get_owner, get_custom, allow_non_immediate_owner,
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(head_block_time()),
get_global_properties().parameters.max_authority_depth);
}
Expand Down
28 changes: 28 additions & 0 deletions libraries/chain/db_getter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/chain_property_object.hpp>
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/custom_authority_object.hpp>

namespace graphene { namespace chain {

Expand Down Expand Up @@ -95,6 +96,33 @@ node_property_object& database::node_properties()
return _node_property_object;
}

vector<authority> database::get_viable_custom_authorities(
account_id_type account, const operation &op,
rejected_predicate_map* rejected_authorities) const
{
const auto& index = get_index_type<custom_authority_index>().indices().get<by_account_custom>();
auto range = index.equal_range(boost::make_tuple(account, unsigned_int(op.which()), true));

auto is_valid = [now=head_block_time()](const custom_authority_object& auth) { return auth.is_valid(now); };
vector<std::reference_wrapper<const custom_authority_object>> valid_auths;
std::copy_if(range.first, range.second, std::back_inserter(valid_auths), is_valid);

vector<authority> results;
for (const auto& cust_auth : valid_auths) {
try {
auto result = cust_auth.get().get_predicate()(op);
if (result.success)
results.emplace_back(cust_auth.get().auth);
else if (rejected_authorities != nullptr)
rejected_authorities->insert(std::make_pair(cust_auth.get().id, std::move(result)));
} catch (fc::exception& e) {
rejected_authorities->insert(std::make_pair(cust_auth.get().id, std::move(e)));
}
}

return results;
}

uint32_t database::last_non_undoable_block_num() const
{
//see https://github.com/bitshares/bitshares-core/issues/377
Expand Down
8 changes: 8 additions & 0 deletions libraries/chain/db_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/worker_object.hpp>
#include <graphene/chain/htlc_object.hpp>
#include <graphene/chain/custom_authority_object.hpp>

#include <graphene/chain/account_evaluator.hpp>
#include <graphene/chain/asset_evaluator.hpp>
Expand All @@ -63,6 +64,7 @@
#include <graphene/chain/witness_evaluator.hpp>
#include <graphene/chain/worker_evaluator.hpp>
#include <graphene/chain/htlc_evaluator.hpp>
#include <graphene/chain/custom_authority_evaluator.hpp>

#include <fc/crypto/digest.hpp>

Expand Down Expand Up @@ -127,6 +129,8 @@ const uint8_t worker_object::type_id;
const uint8_t htlc_object::space_id;
const uint8_t htlc_object::type_id;

const uint8_t custom_authority_object::space_id;
const uint8_t custom_authority_object::type_id;

void database::initialize_evaluators()
{
Expand Down Expand Up @@ -178,6 +182,9 @@ void database::initialize_evaluators()
register_evaluator<htlc_create_evaluator>();
register_evaluator<htlc_redeem_evaluator>();
register_evaluator<htlc_extend_evaluator>();
register_evaluator<custom_authority_create_evaluator>();
register_evaluator<custom_authority_update_evaluator>();
register_evaluator<custom_authority_delete_evaluator>();
}

void database::initialize_indexes()
Expand Down Expand Up @@ -207,6 +214,7 @@ void database::initialize_indexes()
add_index< primary_index<balance_index> >();
add_index< primary_index<blinded_balance_index> >();
add_index< primary_index< htlc_index> >();
add_index< primary_index< custom_authority_index> >();

//Implementation object indexes
add_index< primary_index<transaction_index > >();
Expand Down
Loading