提交 81248dfe 编写于 作者: B Bart Wyatt

merging changes to master @73434fe2

......@@ -33,6 +33,7 @@
#include <eos/chain/transaction_object.hpp>
#include <eos/chain/producer_object.hpp>
#include <eos/chain/permission_link_object.hpp>
#include <eos/chain/authority_checker.hpp>
#include <eos/chain/wasm_interface.hpp>
......@@ -246,6 +247,7 @@ ProcessedTransaction chain_controller::_push_transaction(const SignedTransaction
_pending_tx_session = _db.start_undo_session(true);
auto temp_session = _db.start_undo_session(true);
validate_referenced_accounts(trx);
check_transaction_authorization(trx);
auto pt = _apply_transaction(trx);
_pending_transactions.push_back(trx);
......@@ -345,6 +347,7 @@ signed_block chain_controller::_generate_block(
auto temp_session = _db.start_undo_session(true);
if (trx.contains<SignedTransaction const *>()) {
auto const &t = *trx.get<SignedTransaction const *>();
validate_referenced_accounts(t);
check_transaction_authorization(t);
auto processed = _apply_transaction(t);
block_thread.user_input.emplace_back(processed);
......@@ -481,8 +484,10 @@ void chain_controller::_apply_block(const signed_block& next_block)
for (const auto& cycle : next_block.cycles)
for (const auto& thread : cycle)
for (const auto& trx : thread.user_input)
for (const auto& trx : thread.user_input) {
validate_referenced_accounts(trx);
check_transaction_authorization(trx);
}
/* We do not need to push the undo state for each transaction
* because they either all apply and are valid or the
......@@ -546,6 +551,9 @@ void chain_controller::check_transaction_authorization(const SignedTransaction&
("auth", declaredAuthority));
}
}
EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
"Transaction bears irrelevant signatures from these keys: ${keys}", ("keys", checker.unused_keys()));
}
ProcessedTransaction chain_controller::apply_transaction(const SignedTransaction& trx, uint32_t skip)
......@@ -561,7 +569,6 @@ try {
validate_expiration(trx);
validate_uniqueness(trx);
validate_tapos(trx);
validate_referenced_accounts(trx);
} FC_CAPTURE_AND_RETHROW( (trx) ) }
......
......@@ -30,62 +30,15 @@ struct shared_authority {
shared_vector<types::KeyPermissionWeight> keys;
};
/**
* @brief This class determines whether a set of signing keys are sufficient to satisfy an authority or not
*
* To determine whether an authority is satisfied or not, we first determine which keys have approved of a message, and
* then determine whether that list of keys is sufficient to satisfy the authority. This class takes a list of keys and
* provides the @ref satisfied method to determine whether that list of keys satisfies a provided authority.
*
* @tparam F A callable which takes a single argument of type @ref AccountPermission and returns the corresponding
* authority
*/
template<typename F>
class AuthorityChecker {
F PermissionToAuthority;
flat_set<public_key_type> signingKeys;
public:
AuthorityChecker(F PermissionToAuthority, const flat_set<public_key_type>& signingKeys)
: PermissionToAuthority(PermissionToAuthority), signingKeys(signingKeys) {}
bool satisfied(const types::AccountPermission& permission) const {
return satisfied(PermissionToAuthority(permission));
}
template<typename AuthorityType>
bool satisfied(const AuthorityType& authority) const {
UInt32 weight = 0;
for (const auto& kpw : authority.keys) {
if (signingKeys.count(kpw.key)) {
weight += kpw.weight;
if (weight >= authority.threshold)
return true;
}
}
for (const auto& apw : authority.accounts)
//#warning TODO: Recursion limit? Yes: implement as producer-configurable parameter
if (satisfied(apw.permission)) {
weight += apw.weight;
if (weight >= authority.threshold)
return true;
}
return false;
}
};
inline bool operator < ( const types::AccountPermission& a, const types::AccountPermission& b ) {
return std::tie( a.account, a.permission ) < std::tie( b.account, b.permission );
}
template<typename F>
AuthorityChecker<F> MakeAuthorityChecker(F&& pta, const flat_set<public_key_type>& signingKeys) {
return AuthorityChecker<F>(std::forward<F>(pta), signingKeys);
inline bool operator< (const types::AccountPermission& a, const types::AccountPermission& b) {
return std::tie(a.account, a.permission) < std::tie(b.account, b.permission);
}
/**
* Makes sure all keys are unique and sorted and all account permissions are unique and sorted and that authority can
* be satisfied
*/
inline bool validate( types::Authority& auth ) {
inline bool validate(const types::Authority& auth) {
const types::KeyPermissionWeight* prev = nullptr;
decltype(auth.threshold) totalWeight = 0;
......
#pragma once
#include <eos/chain/types.hpp>
#include <eos/types/generated.hpp>
#include <eos/utilities/parallel_markers.hpp>
#include <fc/scoped_exit.hpp>
#include <boost/range/algorithm/find.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
namespace eos { namespace chain {
namespace detail {
using MetaPermission = static_variant<types::KeyPermissionWeight, types::AccountPermissionWeight>;
struct GetWeightVisitor {
using result_type = UInt32;
template<typename Permission>
UInt32 operator()(const Permission& permission) { return permission.weight; }
};
// Orders permissions descending by weight, and breaks ties with Key permissions being less than Account permissions
struct MetaPermissionComparator {
bool operator()(const MetaPermission& a, const MetaPermission& b) const {
GetWeightVisitor scale;
if (a.visit(scale) > b.visit(scale)) return true;
return a.contains<types::KeyPermissionWeight>() && !b.contains<types::KeyPermissionWeight>();
}
};
using MetaPermissionSet = boost::container::flat_multiset<MetaPermission, MetaPermissionComparator>;
}
/**
* @brief This class determines whether a set of signing keys are sufficient to satisfy an authority or not
*
* To determine whether an authority is satisfied or not, we first determine which keys have approved of a message, and
* then determine whether that list of keys is sufficient to satisfy the authority. This class takes a list of keys and
* provides the @ref satisfied method to determine whether that list of keys satisfies a provided authority.
*
* @tparam F A callable which takes a single argument of type @ref AccountPermission and returns the corresponding
* authority
*/
template<typename F>
class AuthorityChecker {
F PermissionToAuthority;
vector<public_key_type> signingKeys;
vector<bool> usedKeys;
struct WeightTallyVisitor {
using result_type = UInt32;
AuthorityChecker& checker;
UInt32 totalWeight = 0;
WeightTallyVisitor(AuthorityChecker& checker)
: checker(checker) {}
UInt32 operator()(const types::KeyPermissionWeight& permission) {
auto itr = boost::find(checker.signingKeys, permission.key);
if (itr != checker.signingKeys.end()) {
checker.usedKeys[itr - checker.signingKeys.begin()] = true;
totalWeight += permission.weight;
}
return totalWeight;
}
UInt32 operator()(const types::AccountPermissionWeight& permission) {
//TODO: Recursion limit? Yes: implement as producer-configurable parameter
if (checker.satisfied(permission.permission))
totalWeight += permission.weight;
return totalWeight;
}
};
public:
AuthorityChecker(F PermissionToAuthority, const flat_set<public_key_type>& signingKeys)
: PermissionToAuthority(PermissionToAuthority),
signingKeys(signingKeys.begin(), signingKeys.end()),
usedKeys(signingKeys.size(), false)
{}
bool satisfied(const types::AccountPermission& permission) {
return satisfied(PermissionToAuthority(permission));
}
template<typename AuthorityType>
bool satisfied(const AuthorityType& authority) {
// Save the current used keys; if we do not satisfy this authority, the newly used keys aren't actually used
auto KeyReverter = fc::make_scoped_exit([this, keys = usedKeys] () mutable {
usedKeys = keys;
});
// Sort key permissions and account permissions together into a single set of MetaPermissions
detail::MetaPermissionSet permissions;
permissions.insert(authority.keys.begin(), authority.keys.end());
permissions.insert(authority.accounts.begin(), authority.accounts.end());
// Check all permissions, from highest weight to lowest, seeing if signingKeys satisfies them or not
WeightTallyVisitor visitor(*this);
for (const auto& permission : permissions)
// If we've got enough weight, to satisfy the authority, return!
if (permission.visit(visitor) >= authority.threshold) {
KeyReverter.cancel();
return true;
}
return false;
}
bool all_keys_used() const { return boost::algorithm::all_of_equal(usedKeys, true); }
flat_set<public_key_type> used_keys() const {
auto range = utilities::FilterDataByMarker(signingKeys, usedKeys, true);
return {range.begin(), range.end()};
}
flat_set<public_key_type> unused_keys() const {
auto range = utilities::FilterDataByMarker(signingKeys, usedKeys, false);
return {range.begin(), range.end()};
}
};
template<typename F>
AuthorityChecker<F> MakeAuthorityChecker(F&& pta, const flat_set<public_key_type>& signingKeys) {
return AuthorityChecker<F>(std::forward<F>(pta), signingKeys);
}
}} // namespace eos::chain
......@@ -4,11 +4,10 @@
#include <eos/chain/key_value_object.hpp>
#include <eos/chain/chain_controller.hpp>
#include <eos/utilities/parallel_markers.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/range/combine.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
namespace eos { namespace chain {
......@@ -48,15 +47,7 @@ bool apply_context::all_authorizations_used() const {
}
vector<types::AccountPermission> apply_context::unused_authorizations() const {
auto RemoveUsed = boost::adaptors::filtered([](const auto& tuple) {
return !boost::get<0>(tuple);
});
auto ToPermission = boost::adaptors::transformed([](const auto& tuple) {
return boost::get<1>(tuple);
});
// zip the parallel arrays, filter out the used authorizations, and return just the permissions that are left
auto range = boost::combine(used_authorizations, msg.authorization) | RemoveUsed | ToPermission;
auto range = utilities::FilterDataByMarker(msg.authorization, used_authorizations, false);
return {range.begin(), range.end()};
}
......
......@@ -9,12 +9,15 @@ namespace fc {
scoped_exit( C&& c ):callback( std::forward<C>(c) ){}
scoped_exit( scoped_exit&& mv ):callback( std::move( mv.callback ) ){}
void cancel() { canceled = true; }
~scoped_exit() {
try { callback(); } catch( ... ) {}
if (!canceled)
try { callback(); } catch( ... ) {}
}
scoped_exit& operator = ( scoped_exit&& mv ) {
callback = std::move(mv);
callback = std::move(mv.callback);
return *this;
}
private:
......@@ -22,6 +25,7 @@ namespace fc {
scoped_exit& operator=( const scoped_exit& );
Callback callback;
bool canceled = false;
};
template<typename Callback>
......
......@@ -105,11 +105,10 @@ namespace eos { namespace types {
const auto len = strnlen(str,14);
FC_ASSERT( len <= 13 );
value = string_to_name(str);
FC_ASSERT( toString() == String(str), "name not properly normalized", ("name",String(str))("normalized",toString()) );
}FC_CAPTURE_AND_RETHROW( (str) ) }
Name( uint64_t v = 0 ):value(v){
// FC_ASSERT( !(v>>(5*12)), "invalid name id" );
}
Name( uint64_t v = 0 ):value(v){}
explicit operator String()const {
static const char* charmap = ".abcdefghijklmnopqrstuvwxyz12345";
......
#pragma once
#include <boost/range/combine.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
namespace eos { namespace utilities {
/**
* @brief Return values in DataRange corresponding to matching Markers
*
* Takes two parallel ranges, a Data range containing data values, and a Marker range containing markers on the
* corresponding data values. Returns a new Data range containing only the values corresponding to markers which match
* markerValue
*
* For example:
* @code{.cpp}
* vector<char> data = {'A', 'B', 'C'};
* vector<bool> markers = {true, false, true};
* auto markedData = FilterDataByMarker(data, markers, true);
* // markedData contains {'A', 'C'}
* @endcode
*/
template<typename DataRange, typename MarkerRange, typename Marker>
DataRange FilterDataByMarker(DataRange data, MarkerRange markers, const Marker& markerValue) {
auto RemoveMismatchedMarkers = boost::adaptors::filtered([&markerValue](const auto& tuple) {
return boost::get<0>(tuple) == markerValue;
});
auto ToData = boost::adaptors::transformed([](const auto& tuple) {
return boost::get<1>(tuple);
});
// Zip the ranges together, filter out data with markers that don't match, and return the data without the markers
auto range = boost::combine(markers, data) | RemoveMismatchedMarkers | ToData;
return {range.begin(), range.end()};
}
}} // namespace eos::utilities
......@@ -27,6 +27,7 @@
#include <eos/chain/account_object.hpp>
#include <eos/chain/producer_object.hpp>
#include <eos/chain/authority_checker.hpp>
#include <eos/utilities/tempdir.hpp>
......@@ -37,6 +38,8 @@
#include <fc/crypto/digest.hpp>
#include <fc/smart_ref_impl.hpp>
#include <boost/range/adaptor/map.hpp>
#include <iostream>
#include <iomanip>
#include <sstream>
......@@ -94,9 +97,15 @@ private_key_type testing_fixture::get_private_key(const public_key_type& public_
return itr->second;
}
flat_set<public_key_type> testing_fixture::available_keys() const {
auto range = key_ring | boost::adaptors::map_keys;
return {range.begin(), range.end()};
}
testing_blockchain::testing_blockchain(chainbase::database& db, fork_database& fork_db, block_log& blocklog,
chain_initializer_interface& initializer, testing_fixture& fixture)
: chain_controller(db, fork_db, blocklog, initializer, native_contract::make_administrator()),
db(db),
fixture(fixture) {}
void testing_blockchain::produce_blocks(uint32_t count, uint32_t blocks_to_miss) {
......@@ -157,6 +166,34 @@ types::PublicKey testing_blockchain::get_block_signing_key(const types::AccountN
return get_database().get<producer_object, by_owner>(producerName).signing_key;
}
void testing_blockchain::sign_transaction(SignedTransaction& trx) {
auto GetAuthority = [this](const types::AccountPermission& permission) {
auto key = boost::make_tuple(permission.account, permission.permission);
return db.get<permission_object, by_owner>(key).auth;
};
auto checker = MakeAuthorityChecker(GetAuthority, fixture.available_keys());
for (const auto& message : trx.messages)
for (const auto& authorization : message.authorization)
if (!checker.satisfied(authorization))
elog("Attempting to automatically sign transaction, but testing_fixture doesn't have the keys!");
for (const auto& key : checker.used_keys())
// TODO: Use a real chain_id here
trx.sign(fixture.get_private_key(key), chain_id_type{});
}
ProcessedTransaction testing_blockchain::push_transaction(SignedTransaction trx, uint32_t skip_flags) {
if (skip_trx_sigs)
skip_flags |= chain_controller::skip_transaction_signatures;
if (auto_sign_trxs) {
sign_transaction(trx);
}
return chain_controller::push_transaction(trx, skip_flags);
}
void testing_network::connect_blockchain(testing_blockchain& new_database) {
if (blockchains.count(&new_database))
return;
......
......@@ -119,6 +119,7 @@ public:
void store_private_key(const private_key_type& key);
private_key_type get_private_key(const public_key_type& public_key) const;
flat_set<public_key_type> available_keys() const;
protected:
std::vector<fc::temp_directory> anonymous_temp_dirs;
......@@ -178,8 +179,27 @@ public:
/// @brief Get the specified block producer's signing key
PublicKey get_block_signing_key(const AccountName& producerName);
/// @brief Attempt to sign the provided transaction using the keys available to the testing_fixture
void sign_transaction(SignedTransaction& trx);
/// @brief Override push_transaction to apply testing policies
ProcessedTransaction push_transaction(SignedTransaction trx, uint32_t skip_flags = 0);
/// @brief Set whether testing_blockchain::push_transaction checks signatures by default
/// @param skip_sigs If true, push_transaction will skip signature checks; otherwise, no changes will be made
void set_skip_transaction_signature_checking(bool skip_sigs) {
skip_trx_sigs = skip_sigs;
}
/// @brief Set whether testing_blockchain::push_transaction attempts to sign transactions or not
void set_auto_sign_transactions(bool auto_sign) {
auto_sign_trxs = auto_sign;
}
protected:
chainbase::database& db;
testing_fixture& fixture;
bool skip_trx_sigs = true;
bool auto_sign_trxs = false;
};
using boost::signals2::scoped_connection;
......
......@@ -51,7 +51,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"newaccount", types::newaccount{#creator, #name, owner, active, recovery, deposit}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Created account " << #name); \
}
#define MKACCT2(chain, name) \
......@@ -83,7 +83,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"updateauth", types::updateauth{#account, authname, parentname, auth}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Set " << #account << "'s " << authname << " authority."); \
}
......@@ -96,7 +96,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"deleteauth", types::deleteauth{#account, authname}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Deleted " << #account << "'s " << authname << " authority."); \
}
......@@ -109,7 +109,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"linkauth", types::linkauth{#account, #codeacct, messagetype, authname}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Link " << #codeacct << "::" << messagetype << " to " << #account \
<< "'s " << authname << " authority."); \
}
......@@ -124,7 +124,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"unlinkauth", types::unlinkauth{#account, #codeacct, messagetype}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Unlink " << #codeacct << "::" << messagetype << " from " << #account); \
}
#define LINKAUTH3(chain, account, codeacct) LINKAUTH5(chain, account, codeacct, "")
......@@ -138,7 +138,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"transfer", types::transfer{#sender, #recipient, Amount.amount}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Transfered " << Amount << " from " << #sender << " to " << #recipient); \
}
#define XFER4(chain, sender, recipient, amount) XFER5(chain, sender, recipient, amount, "")
......@@ -151,7 +151,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"lock", types::lock{#sender, #recipient, amount}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Staked " << amount << " to " << #recipient); \
}
#define STAKE3(chain, account, amount) STAKE4(chain, account, account, amount)
......@@ -165,7 +165,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"unlock", types::unlock{#account, amount}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Begin unstake " << amount << " to " << #account); \
}
......@@ -177,7 +177,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"claim", types::claim{#account, amount}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Finish unstake " << amount << " to " << #account); \
}
......@@ -190,7 +190,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"setproducer", types::setproducer{#owner, key, cfg}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Create producer " << #owner); \
}
#define MKPDCR3(chain, owner, key) MKPDCR4(chain, owner, key, BlockchainConfiguration{});
......@@ -207,7 +207,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"okproducer", types::okproducer{#voter, #producer, approved? 1 : 0}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Set producer approval from " << #voter << " for " << #producer << " to " << approved); \
}
......@@ -220,7 +220,7 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
"setproducer", types::setproducer{owner, key, cfg}); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx, chain_controller::skip_transaction_signatures); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Update producer " << owner); \
}
#define UPPDCR3(chain, owner, key) UPPDCR4(chain, owner, key, chain.get_producer(owner).configuration)
#include <eos/chain/BlockchainConfiguration.hpp>
#include <eos/chain/authority.hpp>
#include <eos/chain/authority_checker.hpp>
#include <eos/utilities/key_conversion.hpp>
#include <eos/utilities/rand.hpp>
......@@ -88,13 +88,39 @@ BOOST_AUTO_TEST_CASE(authority_checker)
Make_Key(c);
auto& c = c_public_key;
auto GetNullAuthority = [](auto){return Authority();};
auto GetNullAuthority = [](auto){abort(); return Authority();};
auto A = Complex_Authority(2, ((a,1))((b,1)),);
BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {a, b}).satisfied(A));
BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {a, b, c}).satisfied(A));
BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {a, c}).satisfied(A));
BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {b, c}).satisfied(A));
{
auto checker = MakeAuthorityChecker(GetNullAuthority, {a, b});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 2);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 0);
}
{
auto checker = MakeAuthorityChecker(GetNullAuthority, {a, c});
BOOST_CHECK(!checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 0);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 2);
}
{
auto checker = MakeAuthorityChecker(GetNullAuthority, {a, b, c});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 2);
BOOST_CHECK_EQUAL(checker.used_keys().count(a), 1);
BOOST_CHECK_EQUAL(checker.used_keys().count(b), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().count(c), 1);
}
{
auto checker = MakeAuthorityChecker(GetNullAuthority, {b, c});
BOOST_CHECK(!checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 0);
}
A = Complex_Authority(3, ((a,1))((b,1))((c,1)),);
BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {c, b, a}).satisfied(A));
......@@ -115,10 +141,44 @@ BOOST_AUTO_TEST_CASE(authority_checker)
auto GetCAuthority = [c_public_key](auto){return Complex_Authority(1, ((c, 1)),);};
A = Complex_Authority(2, ((a, 2))((b, 1)), (("hello", "world", 1)));
BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a}).satisfied(A));
BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {b}).satisfied(A));
BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {c}).satisfied(A));
BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {b,c}).satisfied(A));
{
auto checker = MakeAuthorityChecker(GetCAuthority, {a});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(checker.all_keys_used());
}
{
auto checker = MakeAuthorityChecker(GetCAuthority, {b});
BOOST_CHECK(!checker.satisfied(A));
BOOST_CHECK_EQUAL(checker.used_keys().size(), 0);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().count(b), 1);
}
{
auto checker = MakeAuthorityChecker(GetCAuthority, {c});
BOOST_CHECK(!checker.satisfied(A));
BOOST_CHECK_EQUAL(checker.used_keys().size(), 0);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().count(c), 1);
}
{
auto checker = MakeAuthorityChecker(GetCAuthority, {b,c});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 2);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 0);
BOOST_CHECK_EQUAL(checker.used_keys().count(b), 1);
BOOST_CHECK_EQUAL(checker.used_keys().count(c), 1);
}
{
auto checker = MakeAuthorityChecker(GetCAuthority, {b,c,a});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 1);
BOOST_CHECK_EQUAL(checker.used_keys().count(a), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 2);
BOOST_CHECK_EQUAL(checker.unused_keys().count(b), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().count(c), 1);
}
A = Complex_Authority(2, ((a, 1))((b, 1)), (("hello", "world", 1)));
BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {a}).satisfied(A));
......@@ -127,12 +187,60 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a,b}).satisfied(A));
BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {b,c}).satisfied(A));
BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a,c}).satisfied(A));
{
auto checker = MakeAuthorityChecker(GetCAuthority, {a,b,c});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 2);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().count(c), 1);
}
A = Complex_Authority(2, ((a, 1))((b, 1)), (("hello", "world", 2)));
BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a,b}).satisfied(A));
BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {c}).satisfied(A));
BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {a}).satisfied(A));
BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {b}).satisfied(A));
{
auto checker = MakeAuthorityChecker(GetCAuthority, {a,b,c});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 1);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 2);
BOOST_CHECK_EQUAL(checker.used_keys().count(c), 1);
}
Make_Key(d);
auto& d = d_public_key;
Make_Key(e);
auto& e = e_public_key;
auto GetAuthority = [d_public_key, e] (const types::AccountPermission& perm) {
if (perm.account == "top")
return Complex_Authority(2, ((d, 1)), (("bottom", "bottom", 1)));
return Key_Authority(e);
};
A = Complex_Authority(5, ((a, 2))((b, 2))((c, 2)), (("top", "top", 5)));
{
auto checker = MakeAuthorityChecker(GetAuthority, {a,b,c,d,e});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 2);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 3);
BOOST_CHECK_EQUAL(checker.used_keys().count(d), 1);
BOOST_CHECK_EQUAL(checker.used_keys().count(e), 1);
}
{
auto checker = MakeAuthorityChecker(GetAuthority, {a,b,c,e});
BOOST_CHECK(checker.satisfied(A));
BOOST_CHECK(!checker.all_keys_used());
BOOST_CHECK_EQUAL(checker.used_keys().size(), 3);
BOOST_CHECK_EQUAL(checker.unused_keys().size(), 1);
BOOST_CHECK_EQUAL(checker.used_keys().count(a), 1);
BOOST_CHECK_EQUAL(checker.used_keys().count(b), 1);
BOOST_CHECK_EQUAL(checker.used_keys().count(c), 1);
}
} FC_LOG_AND_RETHROW() }
/// Test creating the wallet
......
......@@ -5,6 +5,7 @@
#include <eos/chain/permission_object.hpp>
#include <eos/chain/permission_link_object.hpp>
#include <eos/chain/key_value_object.hpp>
#include <eos/chain/authority_checker.hpp>
#include <eos/native_contract/producer_objects.hpp>
......@@ -33,6 +34,7 @@ BOOST_FIXTURE_TEST_CASE(create_account, testing_fixture)
BOOST_CHECK_EQUAL(chain.get_liquid_balance("inita"), Asset(100000));
Make_Account(chain, joe, inita, Asset(1000));
chain.produce_blocks();
Transfer_Asset(chain, inita, joe, Asset(1000));
{ // test in the pending state
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册