#高级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),""_n
或name(0)
的常量表达式,某些开发人员仍在使用该表达式来表示相同的付款人。
2.get_first_receiver
,get_self()
在 contracts.hpp中定义的 get_self
和get_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
之类的任何常量,从而使代码更易于推理。