第一种:创建系统账号 eosio 的方式。
直接调用 create_native_account 方法直接进行创建。并将资源设置成无限。
void create_native_account(account_name name, const authority& owner, const authority& active, bool is_privileged = false) {
//create account 直接创建账号,不会做任何资源判断,因为创建的是系统账号
db.create<account_object>([&](auto& a) {
a.name = name;
a.creation_date = conf.genesis.initial_timestamp;
a.privileged = is_privileged;
if(name == config::system_account_name) {
a.set_abi(eosio_contract_abi(abi_def()));
}
});
db.create<account_sequence_object>([&](auto & a) {
a.name = name;
});
const auto& owner_permission = authorization.create_permission(name, config::owner_name, 0,
owner, conf.genesis.initial_timestamp );
const auto& active_permission = authorization.create_permission(name, config::active_name, owner_permission.id,
active, conf.genesis.initial_timestamp );
// 初始化账号资源,但是初始化赋值只赋了 resource_limits_object 的 owner 值,其他 cpu,ram,net 等资源默认是 -1,也就是 unlimit。
resource_limits.initialize_account(name);
int64_t ram_delta = config::overhead_per_account_ram_bytes;
ram_delta += 2*config::billable_size_v<permission_object>;
ram_delta += owner_permission.auth.get_billable_size();
ram_delta += active_permission.auth.get_billable_size();
resource_limits.add_pending_ram_usage(name, ram_delta);
resource_limits.verify_account_ram_usage(name);
}
void resource_limits_manager::initialize_account(const account_name& account) {
_db.create<resource_limits_object>([&](resource_limits_object& bl) {
bl.owner = account;
});
_db.create<resource_usage_object>([&](resource_usage_object& bu) {
bu.owner = account;
});
}
/**
* Every account that authorizes a transaction is billed for the full size of that transaction. This object
* tracks the average usage of that account.
*/
struct resource_limits_object : public chainbase::object<resource_limits_object_type, resource_limits_object> {
OBJECT_CTOR(resource_limits_object)
id_type id;
account_name owner;
bool pending = false;
int64_t net_weight = -1;
int64_t cpu_weight = -1;
int64_t ram_bytes = -1;
};
第二种:cleos create account 方式创建账号,调用的是 eosio 的默认合约,但该方式在 eosio 部署了 eosio.system 后不可用。因为默认合约被替换掉。eosio 的默认合约是来自源码提前定义好的。
具体的 abi 信息在:libraries/chain/eosio_contract_abi.cpp,libraries/chain/eosio_contract.cpp。
跟第一种一样,同样是将资源的使用权设置为无限。下一次再介绍 eosio 默认合约的形成原理,以及调用流程。
/**
* This method is called assuming precondition_system_newaccount succeeds a
*/
void apply_eosio_newaccount(apply_context& context) {
auto create = context.act.data_as<newaccount>();
try {
context.require_authorization(create.creator);
// context.require_write_lock(config::eosio_auth_scope);
auto& authorization = context.control.get_mutable_authorization_manager();
// 判断公钥是否合法。
EOS_ASSERT(validate(create.owner), action_validate_exception, “Invalid owner authority”);
EOS_ASSERT(validate(create.active), action_validate_exception, “Invalid active authority”);
auto& db = context.db;
auto name_str = name(create.name).to_string();
// 判断 account name 的合法性
EOS_ASSERT(!create.name.empty(), action_validate_exception, “account name cannot be empty” );
EOS_ASSERT(name_str.size() <= 12, action_validate_exception, “account names can only be 12 chars long” );
// Check if the creator is privileged
// 只有 eosio 才能创建 eosio. 为前缀的账号。
const auto &creator = db.get<account_object, by_name>(create.creator);
if(!creator.privileged) {
EOS_ASSERT(name_str.find( “eosio.”) != 0, action_validate_exception,
“only privileged accounts can have names that start with ‘eosio.'” );
}
// 判断用户名是否存在。
auto existing_account = db.find<account_object, by_name>(create.name);
EOS_ASSERT(existing_account == nullptr, account_name_exists_exception,
“Cannot create account named ${name}, as that name is already taken”,
(“name”, create.name));
const auto& new_account = db.create<account_object>([&](auto& a) {
a.name = create.name;
a.creation_date = context.control.pending_block_time();
});
db.create<account_sequence_object>([&](auto& a) {
a.name = create.name;
});
for(const auto& auth : { create.owner, create.active} ){
validate_authority_precondition(context, auth);
}
const auto& owner_permission = authorization.create_permission(create.name, config::owner_name, 0,
std::move(create.owner) );
const auto& active_permission = authorization.create_permission(create.name, config::active_name, owner_permission.id,
std::move(create.active) );
context.control.get_mutable_resource_limits_manager().initialize_account(create.name);
int64_t ram_delta = config::overhead_per_account_ram_bytes;
ram_delta += 2*config::billable_size_v<permission_object>;
ram_delta += owner_permission.auth.get_billable_size();
ram_delta += active_permission.auth.get_billable_size();
context.trx_context.add_ram_usage(create.name, ram_delta);
} FC_CAPTURE_AND_RETHROW((create) ) }
跟第一种一样,同样是将资源的使用权设置为无限。下一次再介绍当没有部署 eosio.system 合约时,eosio 默认合约的形成原理。
第三种:当部署 eosio.system 合约时,创建账号都必须使用该合约的 newaccount 的 action。值得一提的是用第三种方式创建时,第二种方式的 apply_eosio_newaccount 也会执行。
void native::newaccount(account_name creator,
account_name newact
/* no need to parse authorities
const authority& owner,
const authority& active*/ ) {
// 当 creator 不是 eosio 时,需要判断创建者的资源以及低于 12 个字符的名字是否通过拍卖。
if(creator != _self) {
auto tmp = newact >> 4;
bool has_dot = false;
for(uint32_t i = 0; i < 12; ++i) {
has_dot |= !(tmp & 0x1f);
tmp >>= 5;
}
if(has_dot) {// or is less than 12 characters
auto suffix = eosio::name_suffix(newact);
if(suffix == newact) {
name_bid_table bids(_self,_self);
auto current = bids.find(newact);
eosio_assert(current != bids.end(), “no active bid for name” );
eosio_assert(current->high_bidder == creator, “only highest bidder can claim”);
eosio_assert(current->high_bid < 0, “auction for name is not closed yet”);
bids.erase(current);
} else {
eosio_assert(creator == suffix, “only suffix may create this account”);
}
}
}
user_resources_table userres(_self, newact);
userres.emplace(newact, [&](auto& res) {
res.owner = newact;
});
// 将账号资源初始化为 0,不购买资源无法进行相关动作
set_resource_limits(newact, 0, 0, 0);
}