eos 账户名与uint64_t转换(N与name)

N与name

弁言

在EOS智能合约中,你应当见到过相似如许的语句:

require_auth( N(user));

结合上一篇的内容,这句话的意义是指,搜检:在以后action的已受权的允许列表中,是不是存在user账号,若是存在,则甚么也不做;若是不存在,则抛出非常。

还记得我们之前写的hello合约吗?外面的hi 这个action的处置惩罚函数(handler)大抵是如许的:

      /// @abi action 
void hi( account_name user ) {
require_auth( user );
print( "Hi, ", name{user} );
}

那末这个require_auth( user );与后面的require_auth( N(user) );有甚么区别呢?下一行中的name{user}又是甚么意义呢?
我们下面逐一解说。

N的用法

在EOS合约中,你会经常看到N的用法,它是甚么东西呢?实际上,它是一个宏界说:


/** * Used to generate a compile time uint64_t from the base32 encoded string interpretation of X * * @brief Used to generate a compile time uint64_t from the base32 encoded string interpretation of X * @param X - String representation of the name * @return constexpr uint64_t - 64-bit unsigned integer representation of the name * @ingroup types */
#define N(X) ::eosio::string_to_name(#X)

这是间接从eos源码中的types.h文件里,摘取出来的。可以或许看到N(x)等同于::eosio::string_to_name(#X)#X代表把X转化它的字面量的字符串形式,若是X是user,那末#X就即是"user"。这是C语言中宏界说的一种语法

eosio::string_to_name是一个函数,它可以或许把一个字符串转化为一个数字。我们来看下它的界说:

/**
    *  Converts a base32 string to a uint64_t. This is a constexpr so that
    *  this method can be used in template arguments as well.
    *
    *  @brief Converts a base32 string to a uint64_t.
    *  @param str - String representation of the name
    *  @return constexpr uint64_t - 64-bit unsigned integer representation of the name
    *  @ingroup types
    */
   static constexpr uint64_t string_to_name( const char* str ) {

      uint32_t len = 0;
      while( str[len] ) ++len;

      uint64_t value = 0;

      for( uint32_t i = 0; i <= 12; ++i ) {
         uint64_t c = 0;
         if( i < len && i <= 12 ) c = uint64_t(char_to_symbol( str[i] ));

         if( i < 12 ) {
            c &= 0x1f;
            c <<= 64-5*(i+1);
         }
         else {
            c &= 0x0f;
         }

         value |= c;
      }

      return value;
   }

详细在for轮回里的运算细节可以或许没必要穷究,它实际上是把传出去的字符串str看成一个base32编码的字符串,然后把它转化为对应的整数形式(uint64_t范例的)。

在EOS体系中,险些一切的标识性的name,都是以和base32编码可以或许相互转换的整数范例(详细是uint64_t)存在的。好比,账户名, 权限名,table的名字,多重署名提案的名字等等。

为了包管这些名字可以或许以base32位编码,而且能被一个对应的unint64_t整数独一标识,划定这些名字要知足以下请求:长度不超过12个字符,而且每一个字符必需是以下之一:.12345abcdefghijklmnopqrstuvwxyz

如今你应当知晓,为何账户名要有这些限定了吧?实在不止账户名,也不止下面的这些名字,哪怕是你未来自身的智能合约界说了一个可以或许标识某种耐久化数据的名字,最好也恪守这个商定,如此可以确保它能转化位uint64_t整型。
为何非要能转化为uint64_t呢?由于EOS体系的设想云云。能转化uint64_t是一个在效力和易用性下面的均衡,起首这12位字符可以或许透露表现32^12次方个名字,也就是2^60 次方,这是个天文数字,充足运用;同时不凌驾64位bit;其次,uint64_t数值,在现代的64位CPU上,一个时钟周期就可以或许运算一次。若是是uint128_t,则须要拆分红一个个64位的局部去运算,就慢了许多;若是uint32_t呢,缺乏64位,也异样须要一个时钟周期。所以64位刚恰好。

我们回到后面我们抛出的哪一个题目:

require_auth( user );require_auth( N(user) );有甚么区别?

require_auth(user)中,user是一个变量,它的值可能是bob也可以或许是carl,也或许为一个名为user"user"账户,以user变量的值而定。

我们看下hi这个action 处置惩罚器的函数声明:

void hi( account_name user );

eos在挪用action handler的时刻,传出去的account_name范例,实际上就是uint64_t范例,若是user变量所代表的账户的是bob,那末user自身并非"bob"字符串,而是它对应的uint64_t范例的值。

若是这里的user是bob账户,那末require_auth( user );就是在磨练:

bob账户是不是存在于以后action的已受权允许列表中。

require_auth( N(user) );是甚么意义呢?N(user)user转化成了"user"字符串代表的整数形式,那么require_auth( N(user) );的意义就是在校验:

名为user的账户是不是存在于以后action的已受权允许列表中。

name

name是一种范例,它的源码是如许的:

​
/** * Wraps a uint64_t to ensure it is only passed to methods that expect a Name and * that no mathematical operations occur. It also enables specialization of print * so that it is printed as a base32 string. * * @brief wraps a uint64_t to ensure it is only passed to methods that expect a Name * @ingroup types */
struct name {
/** * Conversion Operator to convert name to uint64_t * * @brief Conversion Operator * @return uint64_t - Converted result */
operator uint64_t()const { return value; }
// keep in sync with name::operator string() in eosio source code definition for name
std::string to_string() const {
static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";
std::string str(13,".");
uint64_t tmp = value;
for( uint32_t i = 0; i <= 12; ++i ) {
char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)];
str[12-i] = c;
tmp >>= (i == 0 ? 4 : 5);
}
trim_right_dots( str );
return str;
}
/** * Equality Operator for name * * @brief Equality Operator for name * @param a - First data to be compared * @param b - Second data to be compared * @return true - if equal * @return false - if unequal */
friend bool operator==( const name& a, const name& b ) { return a.value == b.value; }
/** * Internal Representation of the account name * * @brief Internal Representation of the account name */
account_name value = 0;
private:
static void trim_right_dots(std::string& str ) {
const auto last = str.find_last_not_of(".");
if (last != std::string::npos)
str = str.substr(0, last + 1);
}
};
} // namespace eosio

就像name类的正文中说的那样,它的作用是把一个uint64_t的值转化位base32编码字符串形式,作用恰好和N相反。

再看下下面我们看过的hi 函数:

      /// @abi action 
void hi( account_name user ) {
require_auth( user );
print( "Hi, ", name{user} );
}

name{user},这里user是个某个账户的整数形式,它本来的字符串多是"bob",也多是其他的名字。我们假设是"bob"吧,那末name{user}就是"bob"了。
这里在print函数外面,我们就可以打印出bob了,若是我们间接用print( "Hi, ",user );,那末打印出来的user局部,就是一个让人摸不着头脑的数字了。

所以,name这个类关于我们打印一个name名字。关于name{user}这句话的语法寄义,是实际上是挪用了name类的默许组织函数,生成了一个name工具,print函数在打印的时刻,会主动挪用name工具的to_string函数,转换为字符串并打印出来。由于本文着重于EOS,所以关于C++语法寄义,本文由于篇幅题目,只能点到为止,更多C++的信息,发起购置相干书本或许网上搜刮相干材料进修。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值