EOS智能合約開發(fā)系列(16): deferred action與inline action

前面兩篇文章我們分析了eosio.msig合約勒奇,中間有些內(nèi)容因?yàn)槠鶝]有仔細(xì)講解,今天開始打算把一些知識點(diǎn)攻克一下巧骚,有些比較難的知識點(diǎn)赊颠,自然會詳細(xì)介紹;有些呢劈彪,則看起來比較簡單竣蹦,然而深入進(jìn)去之后,確可以加深對EOS系統(tǒng)的理解沧奴。今天介紹第三個知識點(diǎn):deferred action與inline action痘括。

action

EOS系統(tǒng)是以消息通信為基礎(chǔ)的,action就是EOS上消息的載體滔吠。如果你想調(diào)用某個智能合約纲菌,那么就要給它發(fā)action消息挠日。如果你的智能合約要提供某種服務(wù),供別人調(diào)用驰后,那該智能合約就要提供action的處理器(handler)函數(shù)肆资,這些handler函數(shù)就是你對外界發(fā)來的action做出響應(yīng)地方,也可以說是灶芝,你給別人提供服務(wù)的地方郑原。

在沒有嚴(yán)加區(qū)分的時候,我說的action函數(shù)夜涕,實(shí)際上就是action的handler函數(shù)犯犁;說成action函數(shù)是為了方便。

這種通過消息調(diào)用其他智能合約接口的方式女器,有點(diǎn)類似于遠(yuǎn)程調(diào)用(RPC)酸役,實(shí)際上,它們的原理也是很類似的驾胆,都是發(fā)起方把自己的調(diào)用參數(shù)和相關(guān)數(shù)據(jù)序列化涣澡,通過某種消息通道,發(fā)送給接收方丧诺,接收方反序列化消息并解析出相關(guān)要求入桂,然后按照要求執(zhí)行操作,最后把操作結(jié)果以類似的方式返回給發(fā)起方驳阎。

RPC有同步調(diào)用和異步調(diào)用之分抗愁,同步調(diào)用是指,發(fā)起方在發(fā)送調(diào)用消息之后呵晚,會等待服務(wù)方的返回蜘腌,直到調(diào)用方返回數(shù)據(jù)后才執(zhí)行后面的語句。異步調(diào)用是指饵隙,發(fā)起方在發(fā)送調(diào)用消息之后撮珠,不會傻傻等待服務(wù)方的返回,而是繼續(xù)執(zhí)行下面的語句癞季;當(dāng)收到服務(wù)方返回數(shù)據(jù)的時候劫瞳,發(fā)起方也會作出相應(yīng)的處理。

與RPC調(diào)用類似绷柒,action消息也有類似的兩種形式:分別對應(yīng)于deferred actioninline action。不過涮因,這兩種action消息都是異步的废睦,沒有同步的action消息。

那么deferred actioninline action有什么區(qū)別呢养泡?

inline action

inline action有人翻譯成在線 action嗜湃,有人翻譯成內(nèi)聯(lián)action奈应。我傾向于后者,后者更能表明它的含義购披。inline action相當(dāng)于原有action的一部分杖挣,它和原有的action在同一個事務(wù)中執(zhí)行;如果inline action失敗了刚陡,則整個事務(wù)也就失敗了惩妇,并會回滾該事務(wù)已經(jīng)產(chǎn)生的任何結(jié)果。

我們修改一下hello合約筐乳,演示一下這種情況歌殃;再創(chuàng)建一個action處理器,命名為say:

#include <eosiolib/eosio.hpp>
#include <eosiolib/transaction.hpp>

using namespace eosio;

class hello : public eosio::contract {
  public:
      using contract::contract;
      /// @abi action 
      void hi( account_name user ) {
         require_auth( user);
         
         print("before inline action\n");

         action(
            permission_level{user, N(active)},
            N(hello.code), N(say),
            user
         ).send();

         print("end of hi");
      }

      void say( account_name user ) {
         require_auth( user );
         print( "Say, ", name{user});
      }

};

EOSIO_ABI( hello, (hi)(say) )

與之前部署hello合約一樣蝙云,我們編譯并部署到hello.code賬戶:

~  ./MakeContract hello
~  cleos set contract hello.code ./hello -p hello.code@active
Reading WAST/WASM from ./hello/hello.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: ec3e7517282b946c2c17e952936a1c22f89e68b88558790cd4545f1bf7f53629  2728 bytes  16026 us
#         eosio <= eosio::setcode               {"account":"hello.code","vmtype":0,"vmversion":0,"code":"0061736d01000000013b0c60027f7e0060000060000...
#         eosio <= eosio::setabi                {"account":"hello.code","abi":"0e656f73696f3a3a6162692f312e30000202686900010475736572046e616d6503736...

MakeContract是之前我們寫的一個編譯腳本氓皱,還記得吧。

然后我們再向hello.code發(fā)送hi action:

 ~ cleos push action hello.code hi '["user"]' -p user@active
executed transaction: 637e139bd4d332ed116c087f45605e61ec593225636ff35ee93b86096c749e39  104 bytes  1790 us
#    hello.code <= hello.code::hi               {"user":"user"}
>> before inline action
#    hello.code <= hello.code::say              {"user":"user"}
>> Say, user

可以看到print("end of hi");沒有把"end of hi"打印出來勃刨,這是因?yàn)槊钚羞@里的打印結(jié)果有時候會有缺失波材,不要緊,我們可以從nodeos里看log身隐,要這樣啟動nodeos才能看到合約執(zhí)行的log:

nodeos --contracts-console

然后我們再重新發(fā)送hi action廷区,我們可以nodeos的output里看到綠色的執(zhí)行l(wèi)og如下:

2018-08-27T08:53:04.692 thread-0   apply_context.cpp:28          print_debug          ]
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT BEGIN =====================
before inline action
end of hi
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT END   =====================
2018-08-27T08:53:04.692 thread-0   apply_context.cpp:28          print_debug          ]
[(hello.code,say)->hello.code]: CONSOLE OUTPUT BEGIN =====================
Say, user
[(hello.code,say)->hello.code]: CONSOLE OUTPUT END   =====================

在這里,你會發(fā)現(xiàn)抡医,先打印出end of hi躲因,后打印出Say, user。而我們的代碼忌傻,是先發(fā)送say action再打印end of hi的大脉。這正說明,發(fā)送say action是異步進(jìn)行的水孩。

我們這里發(fā)送inline action的方式是構(gòu)造一個action對象镰矿,然后調(diào)用它的send方法:

        action(
            permission_level{user, N(active)},
            N(hello.code), N(say),
            user
         ).send();

你也可以用這種方式:

INLINE_ACTION_SENDER(hello, say)(N(hello.code), {N(user), N(active)}, {user});

INLINE_ACTION_SENDER是一個宏,它的用法格式是這樣的:

INLINE_ACTION_SENDER(<class-name>, <action-handler-name>)(<receiver-contract>, {<account>, <permission>}, {<data>});

這里通過inline action調(diào)用自己的其他的action handler俘种,能正常成功秤标,但如果調(diào)用其他的合約呢?我們下一篇文章詳解其中玄機(jī)宙刘。

deferred action

有人翻譯成延遲的action苍姜,我覺得不錯,我們以后也這樣翻譯吧悬包。既然是延遲衙猪,那肯定是異步了,那這里的異步與inline action的異步有何區(qū)別呢?區(qū)別有3:

  1. inline action與原來的action是同一個事務(wù)垫释。如果inline action失敗了丝格,整個事務(wù)會回滾;deferred action 與原來的action不屬于同一個事務(wù)棵譬,并且不保證deferred action 能夠成功執(zhí)行显蝌,如果失敗了,也不會引起原有action的事務(wù)回滾订咸。
  2. 因?yàn)?code>inline action與原來的action是同一個事務(wù)曼尊,所以他們肯定會被打包在同一個塊中;而deferred action不保證這一點(diǎn)算谈,實(shí)際上涩禀,一般情況都不會在同一個區(qū)塊中。
  3. deferred action可以設(shè)置延遲多少時間后執(zhí)行然眼;而inline action艾船,BP會保證他們在同一個事務(wù)中,因而會盡可能快的執(zhí)行它高每,所以不能設(shè)置延遲時間屿岂。

我們看個deferred action的例子吧?

#include <eosiolib/eosio.hpp>
#include <eosiolib/transaction.hpp>


using namespace eosio;

class hello : public eosio::contract {
  public:
      using contract::contract;
      /// @abi action 
      void hi( account_name user ) {
        require_auth( user);
         
        print("before deferred action\n");

        eosio::transaction txn{};
        const uint128_t sender_id = 100;
        txn.actions.emplace_back(
          action(eosio::permission_level(user, N(active)),
                N(hello.code),
                N(say),
                std::make_tuple(user)));
        txn.delay_sec = 0;
        txn.send(sender_id, user);
         
         print("end of hi");
      }

      void say( account_name user ) {
         require_auth( user );
         print( "Say, ", name{user});
      }

};

EOSIO_ABI( hello, (hi)(say) )

這里故意把延遲時間delay_sec設(shè)置為0鲸匿,可以從下面nodeos的output看到:

2018-08-27T09:32:04.002 thread-0   producer_plugin.cpp:1234      produce_block        ] Produced block 000105488afa390b... #66888 @ 2018-08-27T09:32:04.000 signed by eosio [trxs: 0, lib: 66887, confirmed: 0]
2018-08-27T09:32:04.419 thread-0   apply_context.cpp:28          print_debug          ]
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT BEGIN =====================
before inline action
end of hi
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT END   =====================
2018-08-27T09:32:04.505 thread-0   producer_plugin.cpp:1234      produce_block        ] Produced block 00010549e3d459b0... #66889 @ 2018-08-27T09:32:04.500 signed by eosio [trxs: 1, lib: 66888, confirmed: 0]
2018-08-27T09:32:04.510 thread-0   apply_context.cpp:28          print_debug          ]
[(hello.code,say)->hello.code]: CONSOLE OUTPUT BEGIN =====================
Say, user
[(hello.code,say)->hello.code]: CONSOLE OUTPUT END   =====================

可以看到爷怀,即便我們把delay_sec置為0,deferred action還是和原有的action不在同一個區(qū)塊里带欢。

我們發(fā)送deferred action是這么做的:

        eosio::transaction txn{};
        const uint128_t sender_id = 100;
        txn.actions.emplace_back(
          action(eosio::permission_level(user, N(active)),
                N(hello.code),
                N(say),
                std::make_tuple(user)));
        txn.delay_sec = 0;
        txn.send(sender_id, user);

我們構(gòu)造了一個transaction對象运授, 然后調(diào)用它的send方法,這個send的實(shí)現(xiàn)是這樣的:

      void send(const uint128_t& sender_id, account_name payer, bool replace_existing = false) const {
         auto serialize = pack(*this);
         send_deferred(sender_id, payer, serialize.data(), serialize.size(), replace_existing);
      }

你可能注意到了乔煞,sender_idreplace_existing這兩個參數(shù)吁朦。

sender_id具體的值,實(shí)際上是你自己定的渡贾,可以取消還沒有發(fā)生的延遲交易逗宜。cancel的方法簽名如下:

 int cancel_deferred(const uint128_t& sender_id);

replace_existing如果為true,代表想要替換掉之前同一sender_id對應(yīng)的延遲action空骚;如果為false纺讲,代表不替換之前的,也就是新增一個當(dāng)前參數(shù)指定的延遲action囤屹。


今天就這樣吧熬甚。

簡介:不羈,一名程序員肋坚;專研EOS技術(shù)则涯,玩轉(zhuǎn)EOS智能合約開發(fā)复局。
微信公眾號:know_it_well
知識星球地址:https://t.zsxq.com/QvbuzFM

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冲簿,一起剝皮案震驚了整個濱河市粟判,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌峦剔,老刑警劉巖档礁,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吝沫,居然都是意外死亡呻澜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門惨险,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羹幸,“玉大人,你說我怎么就攤上這事辫愉≌な埽” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵恭朗,是天一觀的道長屏镊。 經(jīng)常有香客問我,道長痰腮,這世上最難降的妖魔是什么而芥? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮膀值,結(jié)果婚禮上棍丐,老公的妹妹穿的比我還像新娘。我一直安慰自己沧踏,他們只是感情好歌逢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悦冀,像睡著了一般趋翻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盒蟆,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天踏烙,我揣著相機(jī)與錄音,去河邊找鬼历等。 笑死讨惩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寒屯。 我是一名探鬼主播荐捻,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼黍少,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了处面?” 一聲冷哼從身側(cè)響起厂置,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎魂角,沒想到半個月后昵济,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡野揪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年访忿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斯稳。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡海铆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挣惰,到底是詐尸還是另有隱情卧斟,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布通熄,位于F島的核電站唆涝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏唇辨。R本人自食惡果不足惜廊酣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赏枚。 院中可真熱鬧亡驰,春花似錦、人聲如沸饿幅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栗恩。三九已至透乾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間磕秤,已是汗流浹背乳乌。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留市咆,地道東北人汉操。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像蒙兰,于是被迫代替她去往敵國和親磷瘤。 傳聞我的和親對象是個殘疾皇子芒篷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 什么是智能合約?在解釋智能合約前,我們先來看看傳統(tǒng)合約的形態(tài)采缚。合約的本質(zhì)是由一系列條款組成针炉,每個條款由若干條規(guī)則組...
    vdes閱讀 1,302評論 0 2
  • 點(diǎn)擊查看原文 Web SDK 開發(fā)手冊 SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個完善的 IM 系統(tǒng)...
    layjoy閱讀 13,761評論 0 15
  • 1 EOS智能合約的介紹1.1 所需背景知識1.2 EOS智能合約基礎(chǔ)知識1.3 技術(shù)局限性 2 智能合約文件2....
    cenkai88閱讀 30,502評論 5 28
  • 第二天《肉肉里藏著什么?》 晚上回家的路上仰担,等公交車人很多舶沛,我站在線上排隊(duì)缭贡,上車的時候被一個大嬸兒從旁邊擠過來插隊(duì)...
    田京晶閱讀 171評論 0 0
  • 做事先做人 這是亙古不變的道理 一個人不管多聰明,多能干 背景條件有多好 如果不懂得做人盏触,人品很差 那么愉耙,他的事業(yè)...
    陳柚潤閱讀 416評論 0 0