Files

691 lines
30 KiB
C++

#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/authorization_manager.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio/chain/resource_limits_private.hpp>
#include <eosio/testing/tester_network.hpp>
#include <test_contracts.hpp>
using namespace eosio;
using namespace eosio::chain;
using namespace eosio::testing;
BOOST_AUTO_TEST_SUITE(auth_tests)
BOOST_FIXTURE_TEST_CASE( missing_sigs, validating_tester ) { try {
create_accounts( {"alice"_n} );
produce_block();
BOOST_REQUIRE_THROW( push_reqauth( "alice"_n, {permission_level{"alice"_n, config::active_name}}, {} ), unsatisfied_authorization );
auto trace = push_reqauth("alice"_n, "owner");
produce_block();
BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id));
} FC_LOG_AND_RETHROW() } /// missing_sigs
BOOST_FIXTURE_TEST_CASE( missing_multi_sigs, validating_tester ) { try {
produce_block();
create_account("alice"_n, config::system_account_name, true);
produce_block();
BOOST_REQUIRE_THROW(push_reqauth("alice"_n, "owner"), unsatisfied_authorization); // without multisig
auto trace = push_reqauth("alice"_n, "owner", true); // with multisig
produce_block();
BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id));
} FC_LOG_AND_RETHROW() } /// missing_multi_sigs
BOOST_FIXTURE_TEST_CASE( missing_auths, validating_tester ) { try {
create_accounts( {"alice"_n, "bob"_n} );
produce_block();
/// action not provided from authority
BOOST_REQUIRE_THROW( push_reqauth( "alice"_n, {permission_level{"bob"_n, config::active_name}}, { get_private_key("bob"_n, "active") } ), missing_auth_exception);
} FC_LOG_AND_RETHROW() } /// transfer_test
/**
* This test case will attempt to allow one account to transfer on behalf
* of another account by updating the active authority.
*/
BOOST_FIXTURE_TEST_CASE( delegate_auth, validating_tester ) { try {
create_accounts( {"alice"_n,"bob"_n});
produce_block();
auto delegated_auth = authority( 1, {},
{
{ .permission = {"bob"_n,config::active_name}, .weight = 1}
});
auto original_auth = control->get_authorization_manager().get_permission({"alice"_n, config::active_name}).auth.to_authority();
wdump((original_auth));
set_authority( "alice"_n, config::active_name, delegated_auth );
auto new_auth = control->get_authorization_manager().get_permission({"alice"_n, config::active_name}).auth.to_authority();
wdump((new_auth));
BOOST_CHECK_EQUAL((new_auth == delegated_auth), true);
produce_block();
produce_block();
auto auth = control->get_authorization_manager().get_permission({"alice"_n, config::active_name}).auth.to_authority();
wdump((auth));
BOOST_CHECK_EQUAL((new_auth == auth), true);
/// execute nonce from alice signed by bob
auto trace = push_reqauth("alice"_n, {permission_level{"alice"_n, config::active_name}}, { get_private_key("bob"_n, "active") } );
produce_block();
//todoBOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id));
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(update_auths) {
try {
validating_tester chain;
chain.create_account(name("alice"));
chain.create_account(name("bob"));
// Deleting active or owner should fail
BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("active")), action_validate_exception);
BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("owner")), action_validate_exception);
// Change owner permission
const auto new_owner_priv_key = chain.get_private_key(name("alice"), "new_owner");
const auto new_owner_pub_key = new_owner_priv_key.get_public_key();
chain.set_authority(name("alice"), name("owner"), authority(new_owner_pub_key), {});
chain.produce_blocks();
// Ensure the permission is updated
permission_object::id_type owner_id;
{
auto obj = chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("owner")));
BOOST_TEST(obj != nullptr);
BOOST_TEST(obj->owner == name("alice"));
BOOST_TEST(obj->name == name("owner"));
BOOST_TEST(obj->parent == 0);
owner_id = obj->id;
auto auth = obj->auth.to_authority();
BOOST_TEST(auth.threshold == 1u);
BOOST_TEST(auth.keys.size() == 1u);
BOOST_TEST(auth.accounts.size() == 0u);
BOOST_TEST(auth.keys[0].key.to_string({}) == new_owner_pub_key.to_string({}));
BOOST_TEST(auth.keys[0].key == new_owner_pub_key);
BOOST_TEST(auth.keys[0].weight == 1);
}
// Change active permission, remember that the owner key has been changed
const auto new_active_priv_key = chain.get_private_key(name("alice"), "new_active");
const auto new_active_pub_key = new_active_priv_key.get_public_key();
chain.set_authority(name("alice"), name("active"), authority(new_active_pub_key), name("owner"),
{ permission_level{name("alice"), name("active")} }, { chain.get_private_key(name("alice"), "active") });
chain.produce_blocks();
{
auto obj = chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("active")));
BOOST_TEST(obj != nullptr);
BOOST_TEST(obj->owner == name("alice"));
BOOST_TEST(obj->name == name("active"));
BOOST_TEST(obj->parent == owner_id);
auto auth = obj->auth.to_authority();
BOOST_TEST(auth.threshold == 1u);
BOOST_TEST(auth.keys.size() == 1u);
BOOST_TEST(auth.accounts.size() == 0u);
BOOST_TEST(auth.keys[0].key == new_active_pub_key);
BOOST_TEST(auth.keys[0].weight == 1u);
}
auto spending_priv_key = chain.get_private_key(name("alice"), "spending");
auto spending_pub_key = spending_priv_key.get_public_key();
auto trading_priv_key = chain.get_private_key(name("alice"), "trading");
auto trading_pub_key = trading_priv_key.get_public_key();
// Bob attempts to create new spending auth for Alice
BOOST_CHECK_THROW( chain.set_authority( name("alice"), name("spending"), authority(spending_pub_key), name("active"),
{ permission_level{name("bob"), name("active")} },
{ chain.get_private_key(name("bob"), "active") } ),
irrelevant_auth_exception );
// Create new spending auth
chain.set_authority(name("alice"), name("spending"), authority(spending_pub_key), name("active"),
{ permission_level{name("alice"), name("active")} }, { new_active_priv_key });
chain.produce_blocks();
{
auto obj = chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("spending")));
BOOST_TEST(obj != nullptr);
BOOST_TEST(obj->owner == name("alice"));
BOOST_TEST(obj->name == name("spending"));
BOOST_TEST(chain.get<permission_object>(obj->parent).owner == name("alice"));
BOOST_TEST(chain.get<permission_object>(obj->parent).name == name("active"));
}
// Update spending auth parent to be its own, should fail
BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("spending"), authority{spending_pub_key}, name("spending"),
{ permission_level{name("alice"), name("spending")} }, { spending_priv_key }), action_validate_exception);
// Update spending auth parent to be owner, should fail
BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("spending"), authority{spending_pub_key}, name("owner"),
{ permission_level{name("alice"), name("spending")} }, { spending_priv_key }), action_validate_exception);
// Remove spending auth
chain.delete_authority(name("alice"), name("spending"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key });
{
auto obj = chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("spending")));
BOOST_TEST(obj == nullptr);
}
chain.produce_blocks();
// Create new trading auth
chain.set_authority(name("alice"), name("trading"), authority{trading_pub_key}, name("active"),
{ permission_level{name("alice"), name("active")} }, { new_active_priv_key });
// Recreate spending auth again, however this time, it's under trading instead of owner
chain.set_authority(name("alice"), name("spending"), authority{spending_pub_key}, name("trading"),
{ permission_level{name("alice"), name("trading")} }, { trading_priv_key });
chain.produce_blocks();
// Verify correctness of trading and spending
{
const auto* trading = chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("trading")));
const auto* spending = chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("spending")));
BOOST_TEST(trading != nullptr);
BOOST_TEST(spending != nullptr);
BOOST_TEST(trading->owner == name("alice"));
BOOST_TEST(spending->owner == name("alice"));
BOOST_TEST(trading->name == name("trading"));
BOOST_TEST(spending->name == name("spending"));
BOOST_TEST(spending->parent == trading->id);
BOOST_TEST(chain.get(trading->parent).owner == name("alice"));
BOOST_TEST(chain.get(trading->parent).name == name("active"));
}
// Delete trading, should fail since it has children (spending)
BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("trading"),
{ permission_level{name("alice"), name("active")} }, { new_active_priv_key }), action_validate_exception);
// Update trading parent to be spending, should fail since changing parent authority is not supported
BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("trading"), authority{trading_pub_key}, name("spending"),
{ permission_level{name("alice"), name("trading")} }, { trading_priv_key }), action_validate_exception);
// Delete spending auth
chain.delete_authority(name("alice"), name("spending"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key });
BOOST_TEST((chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("spending")))) == nullptr);
// Delete trading auth, now it should succeed since it doesn't have any children anymore
chain.delete_authority(name("alice"), name("trading"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key });
BOOST_TEST((chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("trading")))) == nullptr);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(update_auth_unknown_private_key) {
try {
validating_tester chain;
chain.create_account(name("alice"));
// public key with no corresponding private key
fc::ecc::public_key_data data;
data.data[0] = 0x80; // not necessary, 0 also works
fc::sha256 hash = fc::sha256::hash("unknown key");
std::memcpy(&data.data[1], hash.data(), hash.data_size() );
fc::ecc::public_key_shim shim(data);
fc::crypto::public_key new_owner_pub_key(std::move(shim));
chain.set_authority(name("alice"), name("owner"), authority(new_owner_pub_key), {});
chain.produce_blocks();
// Ensure the permission is updated
permission_object::id_type owner_id;
{
auto obj = chain.find<permission_object, by_owner>(boost::make_tuple(name("alice"), name("owner")));
BOOST_TEST(obj != nullptr);
BOOST_TEST(obj->owner == name("alice"));
BOOST_TEST(obj->name == name("owner"));
BOOST_TEST(obj->parent == 0);
owner_id = obj->id;
auto auth = obj->auth.to_authority();
BOOST_TEST(auth.threshold == 1u);
BOOST_TEST(auth.keys.size() == 1u);
BOOST_TEST(auth.accounts.size() == 0u);
BOOST_TEST(auth.keys[0].key == new_owner_pub_key);
BOOST_TEST(auth.keys[0].weight == 1);
}
} FC_LOG_AND_RETHROW()
}
BOOST_AUTO_TEST_CASE(link_auths) { try {
validating_tester chain;
chain.create_accounts({name("alice"),name("bob")});
const auto spending_priv_key = chain.get_private_key(name("alice"), "spending");
const auto spending_pub_key = spending_priv_key.get_public_key();
const auto scud_priv_key = chain.get_private_key(name("alice"), "scud");
const auto scud_pub_key = scud_priv_key.get_public_key();
chain.set_authority(name("alice"), name("spending"), authority{spending_pub_key}, name("active"));
chain.set_authority(name("alice"), name("scud"), authority{scud_pub_key}, name("spending"));
// Send req auth action with alice's spending key, it should fail
BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("spending")} }, { spending_priv_key }), irrelevant_auth_exception);
// Link authority for eosio reqauth action with alice's spending key
chain.link_authority(name("alice"), name("eosio"), name("spending"), name("reqauth"));
// Now, req auth action with alice's spending key should succeed
chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("spending")} }, { spending_priv_key });
chain.produce_block();
// Relink the same auth should fail
BOOST_CHECK_THROW( chain.link_authority(name("alice"), name("eosio"), name("spending"), name("reqauth")), action_validate_exception);
// Unlink alice with eosio reqauth
chain.unlink_authority(name("alice"), name("eosio"), name("reqauth"));
// Now, req auth action with alice's spending key should fail
BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("spending")} }, { spending_priv_key }), irrelevant_auth_exception);
chain.produce_block();
// Send req auth action with scud key, it should fail
BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("scud")} }, { scud_priv_key }), irrelevant_auth_exception);
// Link authority for any eosio action with alice's scud key
chain.link_authority(name("alice"), name("eosio"), name("scud"));
// Now, req auth action with alice's scud key should succeed
chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("scud")} }, { scud_priv_key });
// req auth action with alice's spending key should also be fine, since it is the parent of alice's scud key
chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("spending")} }, { spending_priv_key });
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(link_then_update_auth) { try {
validating_tester chain;
chain.create_account(name("alice"));
const auto first_priv_key = chain.get_private_key(name("alice"), "first");
const auto first_pub_key = first_priv_key.get_public_key();
const auto second_priv_key = chain.get_private_key(name("alice"), "second");
const auto second_pub_key = second_priv_key.get_public_key();
chain.set_authority(name("alice"), name("first"), authority{first_pub_key}, name("active"));
chain.link_authority(name("alice"), name("eosio"), name("first"), name("reqauth"));
chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("first")} }, { first_priv_key });
chain.produce_blocks(13); // Wait at least 6 seconds for first push_reqauth transaction to expire.
// Update "first" auth public key
chain.set_authority(name("alice"), name("first"), authority{second_pub_key}, name("active"));
// Authority updated, using previous "first" auth should fail on linked auth
BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("first")} }, { first_priv_key }), unsatisfied_authorization);
// Using updated authority, should succeed
chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("first")} }, { second_priv_key });
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(create_account) {
try {
validating_tester chain;
chain.create_account(name("joe"));
chain.produce_block();
// Verify account created properly
const auto& joe_owner_authority = chain.get<permission_object, by_owner>(boost::make_tuple(name("joe"), name("owner")));
BOOST_TEST(joe_owner_authority.auth.threshold == 1u);
BOOST_TEST(joe_owner_authority.auth.accounts.size() == 1u);
BOOST_TEST(joe_owner_authority.auth.keys.size() == 1u);
BOOST_TEST(joe_owner_authority.auth.keys[0].key.to_string({}) == chain.get_public_key(name("joe"), "owner").to_string({}));
BOOST_TEST(joe_owner_authority.auth.keys[0].weight == 1u);
const auto& joe_active_authority = chain.get<permission_object, by_owner>(boost::make_tuple(name("joe"), name("active")));
BOOST_TEST(joe_active_authority.auth.threshold == 1u);
BOOST_TEST(joe_active_authority.auth.accounts.size() == 1u);
BOOST_TEST(joe_active_authority.auth.keys.size() == 1u);
BOOST_TEST(joe_active_authority.auth.keys[0].key.to_string({}) == chain.get_public_key(name("joe"), "active").to_string({}));
BOOST_TEST(joe_active_authority.auth.keys[0].weight == 1u);
// Create duplicate name
BOOST_CHECK_EXCEPTION(chain.create_account(name("joe")), action_validate_exception,
fc_exception_message_is("Cannot create account named joe, as that name is already taken"));
// Creating account with name more than 12 chars
BOOST_CHECK_EXCEPTION(chain.create_account(name("aaaaaaaaaaaaa")), action_validate_exception,
fc_exception_message_is("account names can only be 12 chars long"));
// Creating account with eosio. prefix with privileged account
chain.create_account(name("eosio.test1"));
// Creating account with eosio. prefix with non-privileged account, should fail
BOOST_CHECK_EXCEPTION(chain.create_account(name("eosio.test2"), name("joe")), action_validate_exception,
fc_exception_message_is("only privileged accounts can have names that start with 'eosio.'"));
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE( any_auth ) { try {
validating_tester chain;
chain.create_accounts( {name("alice"), name("bob")} );
chain.produce_block();
const auto spending_priv_key = chain.get_private_key(name("alice"), "spending");
const auto spending_pub_key = spending_priv_key.get_public_key();
const auto bob_spending_pub_key = spending_priv_key.get_public_key();
chain.set_authority(name("alice"), name("spending"), authority{spending_pub_key}, name("active"));
chain.set_authority(name("bob"), name("spending"), authority{bob_spending_pub_key}, name("active"));
/// this should fail because spending is not active which is default for reqauth
BOOST_REQUIRE_THROW( chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("spending")} }, { spending_priv_key }),
irrelevant_auth_exception );
chain.produce_block();
//test.push_reqauth( "alice"_n, { permission_level{"alice"_n,"spending"} }, { spending_priv_key });
chain.link_authority( name("alice"), name("eosio"), name("eosio.any"), name("reqauth") );
chain.link_authority( name("bob"), name("eosio"), name("eosio.any"), name("reqauth") );
/// this should succeed because eosio::reqauth is linked to any permission
chain.push_reqauth(name("alice"), { permission_level{"alice"_n, name("spending")} }, { spending_priv_key });
/// this should fail because bob cannot authorize for alice, the permission given must be one-of alices
BOOST_REQUIRE_THROW( chain.push_reqauth(name("alice"), { permission_level{"bob"_n, name("spending")} }, { spending_priv_key }),
missing_auth_exception );
chain.produce_block();
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(no_double_billing) {
try {
fc::temp_directory tempdir;
validating_tester chain( tempdir, true );
chain.execute_setup_policy( setup_policy::preactivate_feature_and_new_bios );
chain.produce_block();
account_name acc1 = "bill1"_n;
account_name acc2 = "bill2"_n;
account_name acc1a = "bill1a"_n;
chain.create_account(acc1);
chain.create_account(acc1a);
chain.produce_block();
const chainbase::database &db = chain.control->db();
using resource_usage_object = eosio::chain::resource_limits::resource_usage_object;
using by_owner = eosio::chain::resource_limits::by_owner;
auto create_acc = [&](account_name a) {
signed_transaction trx;
chain.set_transaction_headers(trx);
authority owner_auth = authority( chain.get_public_key( a, "owner" ) );
vector<permission_level> pls = {{acc1, name("active")}};
pls.push_back({acc1, name("owner")}); // same account but different permission names
pls.push_back({acc1a, name("owner")});
trx.actions.emplace_back( pls,
newaccount{
.creator = acc1,
.name = a,
.owner = owner_auth,
.active = authority( chain.get_public_key( a, "active" ) )
});
chain.set_transaction_headers(trx);
trx.sign( chain.get_private_key( acc1, "active" ), chain.control->get_chain_id() );
trx.sign( chain.get_private_key( acc1, "owner" ), chain.control->get_chain_id() );
trx.sign( chain.get_private_key( acc1a, "owner" ), chain.control->get_chain_id() );
return chain.push_transaction( trx );
};
create_acc(acc2);
const auto &usage = db.get<resource_usage_object,by_owner>(acc1);
const auto &usage2 = db.get<resource_usage_object,by_owner>(acc1a);
BOOST_TEST(usage.cpu_usage.average() > 0U);
BOOST_TEST(usage.net_usage.average() > 0U);
BOOST_REQUIRE_EQUAL(usage.cpu_usage.average(), usage2.cpu_usage.average());
BOOST_REQUIRE_EQUAL(usage.net_usage.average(), usage2.net_usage.average());
chain.produce_block();
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(stricter_auth) {
try {
validating_tester chain;
chain.produce_block();
account_name acc1 = "acc1"_n;
account_name acc2 = "acc2"_n;
account_name acc3 = "acc3"_n;
account_name acc4 = "acc4"_n;
chain.create_account(acc1);
chain.produce_block();
auto create_acc = [&](account_name a, account_name creator, int threshold) {
signed_transaction trx;
chain.set_transaction_headers(trx);
authority invalid_auth = authority(threshold, {key_weight{chain.get_public_key( a, "owner" ), 1}}, {permission_level_weight{{creator, config::active_name}, 1}});
vector<permission_level> pls;
pls.push_back({creator, name("active")});
trx.actions.emplace_back( pls,
newaccount{
.creator = creator,
.name = a,
.owner = authority( chain.get_public_key( a, "owner" ) ),
.active = invalid_auth//authority( chain.get_public_key( a, "active" ) ),
});
chain.set_transaction_headers(trx);
trx.sign( chain.get_private_key( creator, "active" ), chain.control->get_chain_id() );
return chain.push_transaction( trx );
};
try {
create_acc(acc2, acc1, 0);
BOOST_FAIL("threshold can't be zero");
} catch (...) { }
try {
create_acc(acc4, acc1, 3);
BOOST_FAIL("threshold can't be more than total weight");
} catch (...) { }
create_acc(acc3, acc1, 1);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE( linkauth_special ) { try {
validating_tester chain;
const auto& tester_account = "tester"_n;
std::vector<transaction_id_type> ids;
chain.produce_blocks();
chain.create_account("currency"_n);
chain.produce_blocks();
chain.create_account("tester"_n);
chain.create_account("tester2"_n);
chain.produce_blocks();
chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("permission", "first")
("parent", "active")
("auth", authority(chain.get_public_key(tester_account, "first"), 5))
);
auto validate_disallow = [&] (const char *type) {
BOOST_REQUIRE_EXCEPTION(
chain.push_action(config::system_account_name, linkauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("code", "eosio")
("type", type)
("requirement", "first")),
action_validate_exception,
fc_exception_message_is(std::string("Cannot link eosio::") + std::string(type) + std::string(" to a minimum permission"))
);
};
validate_disallow("linkauth");
validate_disallow("unlinkauth");
validate_disallow("deleteauth");
validate_disallow("updateauth");
validate_disallow("canceldelay");
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(delete_auth) { try {
validating_tester chain;
const auto& tester_account = "tester"_n;
chain.produce_blocks();
chain.create_account("eosio.token"_n);
chain.produce_blocks(10);
chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm());
chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi());
chain.produce_blocks();
chain.create_account("tester"_n);
chain.create_account("tester2"_n);
chain.produce_blocks(10);
transaction_trace_ptr trace;
// can't delete auth because it doesn't exist
BOOST_REQUIRE_EXCEPTION(
trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("permission", "first")),
permission_query_exception,
[] (const permission_query_exception &e)->bool {
expect_assert_message(e, "permission_query_exception: Permission Query Exception\nFailed to retrieve permission");
return true;
});
// update auth
chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("permission", "first")
("parent", "active")
("auth", authority(chain.get_public_key(tester_account, "first")))
);
// link auth
chain.push_action(config::system_account_name, linkauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("code", "eosio.token")
("type", "transfer")
("requirement", "first"));
// create CUR token
chain.produce_blocks();
chain.push_action("eosio.token"_n, "create"_n, "eosio.token"_n, mutable_variant_object()
("issuer", "eosio.token" )
("maximum_supply", "9000000.0000 CUR" )
);
// issue to account "eosio.token"
chain.push_action("eosio.token"_n, name("issue"), "eosio.token"_n, fc::mutable_variant_object()
("to", "eosio.token")
("quantity", "1000000.0000 CUR")
("memo", "for stuff")
);
// transfer from eosio.token to tester
trace = chain.push_action("eosio.token"_n, name("transfer"), "eosio.token"_n, fc::mutable_variant_object()
("from", "eosio.token")
("to", "tester")
("quantity", "100.0000 CUR")
("memo", "hi" )
);
BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status);
chain.produce_blocks();
auto liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "eosio.token"_n);
BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance);
liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester"_n);
BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance);
trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object()
("from", "tester")
("to", "tester2")
("quantity", "1.0000 CUR")
("memo", "hi" )
);
BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status);
liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "eosio.token"_n);
BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance);
liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester"_n);
BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance);
liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester2"_n);
BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance);
// can't delete auth because it's linked
BOOST_REQUIRE_EXCEPTION(
trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("permission", "first")),
action_validate_exception,
[] (const action_validate_exception &e)->bool {
expect_assert_message(e, "action_validate_exception: message validation exception\nCannot delete a linked authority");
return true;
});
// unlink auth
trace = chain.push_action(config::system_account_name, unlinkauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("code", "eosio.token")
("type", "transfer"));
BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status);
// delete auth
trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object()
("account", "tester")
("permission", "first"));
BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status);
chain.produce_blocks(1);;
trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object()
("from", "tester")
("to", "tester2")
("quantity", "3.0000 CUR")
("memo", "hi" )
);
BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status);
chain.produce_blocks();
liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester"_n);
BOOST_REQUIRE_EQUAL(asset::from_string("96.0000 CUR"), liquid_balance);
liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester2"_n);
BOOST_REQUIRE_EQUAL(asset::from_string("4.0000 CUR"), liquid_balance);
} FC_LOG_AND_RETHROW() }/// delete_auth
BOOST_AUTO_TEST_SUITE_END()