EOS系列 - 智能合约进阶

#高级EOSIO编程概念

1.eosio::same_payer

第一个只是一个常量表达式,可在修改多索引表的条目时使用。当使用eosio::same_payer时,将要使用的新RAM(如果有的话)分配给已经为表项支付的相同帐户。

用法:

statstable.modify( st, eosio::same_payer, [&]( auto& s ) {
    s.supply += quantity;
});

它在[multi_index.hpp]中定义,只是空的name(value:0),""_nname(0)的常量表达式,某些开发人员仍在使用该表达式来表示相同的付款人。

2.get_first_receiver,get_self()

contracts.hpp中定义的 get_selfget_first_receiver,返回正在运行的动作的执行上下文的一部分。 (在EOSIO.CDT 1.6中,get_first_receiver的实现是为了支持旧的get_code,现在已弃用。)get_self方法返回当前正在运行代码的合同,而get_first_receiver返回的帐户位于动作源自。除非涉及通过require_recipient发出的通知,否则这两个帐户是相同的。

例如,侦听“ eosio.token”的“转移”操作的通知,“ get_self()”将返回您的合同部署到的帐户,而“ get_first_receiver()”将返回“ eosio.token”帐户。这是因为该操作是由向与您的合同帐户有关的“ eosio.token”帐户发送“转移”操作的帐户发起的。

用法:

[[eosio::on_notify("eosio.token::transfer")]] void cryptoship::transfer(name from, name to, const asset &quantity,
                          string memo) {
  print(get_self()); // cryptoship
  print(get_first_receiver()); // eosio.token
}

3.action_wrapper

对于许多用例,需要从合同代码向另一个合同发送新操作。这是合同之间能够积极沟通的唯一途径。再说一次,有很多方法可以做到这一点,但是最优雅的方法之一是使用eosio::action_wrapper。它为特定智能合约代码的特定操作创建“操作模板”,然后可使用该模板来调用此操作。

第一个参数是动作名称,第二个参数是动作的方法_declaration_。

用法

eosio.token标头在eosio.token.hpp header file中定义了其所有动作的动作包装/include/eosio.token/eosio.token.hpp):

  [[eosio::action]]
  void create( name   issuer,
              asset  maximum_supply);

  [[eosio::action]]
  void issue( name to, asset quantity, string memo );

  [[eosio::action]]
  void retire( asset quantity, string memo );

  [[eosio::action]]
  void transfer( name    from,
                name    to,
                asset   quantity,
                string  memo );

  // ...

  using create_action = eosio::action_wrapper<"create"_n, &token::create>;
  using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>;
  using retire_action = eosio::action_wrapper<"retire"_n, &token::retire>;
  using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>;
  // ...

现在,我们可以通过包含此头文件将内联动作发送到任何eosio.token合同。

要注意的重要一点是,只需要包含带有声明的头文件。这意味着,即使对于实施细节未知的封闭源合同,也可以轻松编写动作包装。仅需要编写声明,即动作签名,可以从ABI获得。

使用eosio-cpp-I标志包含头文件的附加include目录。

包含头文件后,将发送** inline **传输操作,如下所示:

#include <eosio_token/include/eosio_token.hpp>

// can specify the contract to send the action to as first argument
token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n});
// transfer arguments are now passed as postional arguments
payout.send(get_self(), to, quantity, memo);

使用to_action方法对延时交易也适用:

token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n});

transaction t{};
t.actions.emplace_back(payout.to_action(get_self(), to, quantity, memo));
t.delay_sec = 10;
t.send(0 /* sender id */, get_self(), false);

4. EOSIO时间类别time_point, time_point_sec, microseconds

EOSIO库在time.hpp header中定义了两个日期类。 time_point_sec类是标准的UNIX时间戳,将1970年1月1日以来的秒数存储在uint32_t中,time_point具有更精确的精度,将经过的微秒(不是毫秒)存储在uint64_t中。 。 在这两个类别之间进行转换很容易。

为了与时间进行算术运算,人们使用了“微秒”类,该类带有有用的辅助工具,例如“秒”,“分钟”或“小时”。

用法

eosio::time_point tp = eosio::current_time_point();
eosio::time_point_sec tps = eosio::current_time_point();
eosio::microseconds micros = tp.time_since_epoch();
uint64_t count_micros = micros.count();
uint32_t count_seconds = tps.sec_since_epoch();

// no more 60*60*24*1e6
const auto MICROSECONDS_IN_DAY = hours(24);
count_micros += MICROSECONDS_IN_DAY;
// no more 60*60*24
count_seconds += hours(24).to_seconds();

eosio::time_point_sec lastGame = /* ... */;
check((eosio::time_point_sec)(current_time_point() + minutes(1)) >= lastGame,
      "last game not finished");

使用microseconds类及其帮助器可以避免使用诸如const auto SECONDS_PER_DAY = 60 * 60 * 24之类的任何常量,从而使代码更易于推理。

发布了58 篇原创文章 · 获赞 66 · 访问量 8159

猜你喜欢

转载自blog.csdn.net/wcc19840827/article/details/102586321