EOS智能合約開發(fā)系列(17): 神秘的eosio.code

上篇文章中型宙,我們講解了deferred actioninline action,并且舉了兩個例子伦吠。然而妆兑,那兩個例子中,我們從合約發(fā)出的action毛仪,都是發(fā)給自己的搁嗓。那么可以發(fā)給其他的合約嗎?這就引出今天的知識點了:神秘的eosio.code箱靴。

eosio.code狼人殺游戲里有用到腺逛,并且備受爭議;本文將詳細介紹一下eosio.code衡怀。

開菜之前棍矛,我們先做好準備工作:

更新一下MakeContract

MakeContract是我們之前寫的一個編譯腳本安疗。為了便于后面的使用,更改了一下這個腳本:

#/bin/bash
cd $1
filename=`basename $1`
eosiocpp -o $filename.wast $filename.cpp
eosiocpp -g $filename.abi $filename.cpp

相比之前的腳本茄靠,此腳本可以編譯子文件夾下的合約了茂契。

編寫兩個合約send.coderecv.code

我們先在~/eos-workspace里面建立相關(guān)的智能合約文件夾:

mkdir testAB
cd testAB
mkdir sender
mkdir receiver

testAB/sender文件夾里建立一個sender.cpp蝶桶,并寫入如下合約內(nèi)容:

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

using namespace eosio;

class sender : public eosio::contract {
  public:
      using contract::contract;
      
      void send( account_name user ) {
        require_auth( user );
        print( "before send inline code sender Say, ", name{user});
        action(
          permission_level{user, N(active)},
          N(recv.code), N(receive),
        user).send();
      }
};

EOSIO_ABI( sender, (send) )

可以看到慨绳,這個合約中有個inline action,它在原action的處理器里真竖,向recv.code發(fā)了個receive action脐雪。

然后在testAB/receiver文件夾里建立一個receiver.cpp,并寫入如下合約內(nèi)容:

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


using namespace eosio;

class receiver1 : public eosio::contract {
  public:
      using contract::contract;
      
      void receive( account_name user ) {
         require_auth( user );
         print( "receiver Say, ", name{user});
      }
};

EOSIO_ABI( receiver1, (receive) )

這個合約更為簡單恢共,僅僅打印一個文字战秋,代表收到了receive action。
你可能注意到了讨韭,這個類名是receiver1而不是receiver脂信,是為了避免與EOSIO_ABI中的receiver名字沖突,從而引起編譯錯誤透硝。

編譯和部署合約

以前都介紹過狰闪,這里僅列出命令,不再做解釋了:

./MakeContract testAB/receiver
./MakeContract testAB/sender
cleos create account user send.code  \
        EOS83sN8bfKGk3jTBezN41UN7LfXSVFa1w3YQcGApE67J26t3HLcr \
     EOS83sN8bfKGk3jTBezN41UN7LfXSVFa1w3YQcGApE67J26t3HLcr

cleos create account user recv.code  \
        EOS83sN8bfKGk3jTBezN41UN7LfXSVFa1w3YQcGApE67J26t3HLcr \
        EOS83sN8bfKGk3jTBezN41UN7LfXSVFa1w3YQcGApE67J26t3HLcr

cleos wallet unlock
cleos set contract recv.code ./testAB/receiver -p recv.code@active
cleos set contract send.code ./testAB/sender -p send.code@active

send.code合約發(fā)送send action

~ cleos push action send.code send '["user"]' -p user@active
Error 3090003: Provided keys, permissions, and delays do not satisfy declared authorizations
Ensure that you have the related private keys inside your wallet and your wallet is unlocked.

再看一下nodeos的output濒生,有如下內(nèi)容:

pending console output: before send inline code sender Say, user
    {"console":"before send inline code sender Say, user"}

send action handler 的 log已經(jīng)在在pending console里了埋泵,說明send.code合約的send action handler已經(jīng)成功觸發(fā)了。后面的錯誤是inline action失敗的信息罪治。

為什么會失敗呢丽声?

我們想想看,如果一個用戶向某個合約里發(fā)送了action消息觉义,這個合約就能夠使用該用戶的權(quán)限發(fā)送任何的inline action是不是很可怕雁社?比如把該用戶的所有的EOS都轉(zhuǎn)走,那用戶豈不是很慘晒骇?

在一開始霉撵,EOS的確存在這個漏洞,后來為了限制合約濫用用戶的授權(quán)厉碟,就不再允許inline action使用原有action的權(quán)限了喊巍。

那沒有用戶授權(quán),智能合約如何互相發(fā)inline action消息呢箍鼓?

BM想了一個辦法崭参,設(shè)計了一個eosio.code許可,這個許可是虛擬的款咖。我們對比下這個方式和之前方式的區(qū)別:

以前的方式是:用戶對交易(或者稱為事務(wù))簽名授權(quán)后何暮,發(fā)送給合約奄喂,合約收到action之后,以當前合約被授權(quán)的許可執(zhí)行新的inline action海洼。我們知道用戶通常使用active許可簽名的跨新,并且此權(quán)限可以做很多事情,比如把資產(chǎn)轉(zhuǎn)移等等坏逢。
現(xiàn)在的方式是:用戶把交易(或者稱為事務(wù))簽名域帐,發(fā)送給合約,合約收到action之后是整,以當前合約賬號的eosio.code許可肖揣,執(zhí)行inline action

解決方案

根據(jù)我們之前學的賬號和權(quán)限相關(guān)的知識浮入,如果要讓send.codeeosio.code能夠代表user執(zhí)行inline action龙优,那么需要四步:

  1. send.code設(shè)置一個eosio.code許可
  2. user的某個許可(可以是active,不過我們這次不用active了事秀,新建一個sendp許可吧)授權(quán)給send.codeeosio.code許可
  3. 把user的這個sendp許可和recv.codereceive關(guān)聯(lián)起來
  4. 因為新建了一個sendp許可彤断,所以為了能向send.code發(fā)送send action,我們還需要把它和send.codesend action關(guān)聯(lián)起來易迹。

我們先給send.code加上一個eosio.code許可:

~ cleos set account permission send.code eosio.code EOS83sN8bfKGk3jTBezN41UN7LfXSVFa1w3YQcGApE67J26t3HLcr -p send.code@active
Error 3050000: Action validate exceptio

失敗了宰衙,nodeos的output有詳情:

Permission names that start with 'eosio.' are reserved

說明eosio.是保留給系統(tǒng)用的,我們沒法給合約賬號設(shè)置eosio.code許可了赴蝇。這也說明了菩浙,我們無需給合約設(shè)置eosio.code許可,系統(tǒng)會幫我們處理好相關(guān)的問題句伶。

那我們進入第二步吧劲蜻, 給user新建一個許可sendp,并把它授權(quán)給send.codeeosio.code許可:

~ cleos set account permission user sendp '{"threshold": 1,"keys": [{"key":"EOS83sN8bfKGk3jTBezN41UN7LfXSVFa1w3YQcGApE67J26t3HLcr", "weight":1}],"accounts": [{"permission":{"actor":"send.code","permission":"eosio.code"},"weight":1}]}' owner -p user@owner
executed transaction: aa60976084adbada1d89b35a023a88cc2d8535a284d1fca04084a952168fbfd6  184 bytes  1076 us
#         eosio <= eosio::updateauth            {"account":"user","permission":"sendp","parent":"owner","auth":{"threshold":1,"keys":[{"key":"EOS83s...

很成功考余。
進入第三步先嬉,把user的sendp許可和recv.codereceive關(guān)聯(lián)起來:

 ~ cleos set action permission user recv.code receive sendp -p user@active
executed transaction: f85293c5ef00f1ca56b8ae75f02b74f94f45e22d8dbf31ffddc4dc235e60c492  128 bytes  4338 us
#         eosio <= eosio::linkauth              {"account":"user","code":"recv.code","type":"receive","requirement":"sendp"}

第四步, 把sendpsend.codesend action關(guān)聯(lián)起來:

~ cleos set action permission user send.code send sendp -p user@active
executed transaction: d4670605d0a64648158cc96ade52b86fc6818a5fa0d62c393acccaca6106a254  128 bytes  943 us
#         eosio <= eosio::linkauth              {"account":"user","code":"send.code","type":"send","requirement":"sendp"}

再修改一下send.code的合約代碼楚堤,主要是發(fā)送action這里疫蔓,把原來的active許可,修改為sendp許可:

        action(
          permission_level{user, N(sendp))},
          N(recv.code), N(receive),
        user).send();

最后身冬,我們使用sendp許可向send.code發(fā)送send action:

~ cleos push action send.code send '["user"]' -p user@sendp
executed transaction: 7c5262c16ca32fd809258794e259846f012ae6ba57b97b6fda0c3c7a13849ca3  104 bytes  2534 us
#     send.code <= send.code::send              {"user":"user"}
>> before send inline code sender Say, user
#     recv.code <= recv.code::receive           {"user":"user"}
>> receiver Say, user

哈哈衅胀,成功了。

注意事項

  • 我們在給user設(shè)置sendp許可的時候酥筝,使用的是這樣的命令:
~ cleos set account permission user sendp '{"threshold": 1,"keys": [{"key":"EOS83sN8bfKGk3jTBezN41UN7LfXSVFa1w3YQcGApE67J26t3HLcr", "weight":1}],"accounts": [{"permission":{"actor":"send.code","permission":"eosio.code"},"weight":1}]}' owner -p user@owner

我們除了授權(quán)給send.codeeosio.code許可外滚躯,還授權(quán)給了一個key,其實這個key是什么無關(guān)緊要,只要你的錢包里有這個key就可以了掸掏。問題是茁影,可以把這個key去掉嗎?可以只授權(quán)給send.codeeosio.code許可嗎丧凤?

答案是不可以募闲。如果只授權(quán)給send.codeeosio.code許可,那么觸發(fā)send.codesend action的交易愿待,就找不到合適的key簽名浩螺,因為用戶是沒有eosio.code許可所對應(yīng)的key的。

  • 真的會比沒有eosio.code許可權(quán)限之前的情況要好嗎呼盆?

在之前沒有eosio.code許可權(quán)限以前年扩,系統(tǒng)允許inline action以原有的action的權(quán)限運行,存在重大隱患访圃,因為合約可以很容易的轉(zhuǎn)移到用戶的資產(chǎn)。

在引入eosio.code之后相嵌,原來的方式行不通了腿时。合約要想代表用戶,必須要用戶自己同意添加eosio.code授權(quán)饭宾。這中間多了個用戶授權(quán)的過程批糟。如果用戶信任該合約,那么可以授權(quán)看铆;如果不信任徽鼎,則不予授權(quán),相對來說的確安全了一些弹惦。

等一下否淤,這真的安全嗎?

這真的安全嗎棠隐?狼人殺也用了eosio.code石抡,不是說有漏洞嗎?我們下次詳解助泽。

簡介:不羈啰扛,一名程序員;專研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,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溜嗜,死亡現(xiàn)場離奇詭異宵膨,居然都是意外死亡,警方通過查閱死者的電腦和手機炸宵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門辟躏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人土全,你說我怎么就攤上這事捎琐。” “怎么了裹匙?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長概页。 經(jīng)常有香客問我籽御,道長技掏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任项鬼,我火速辦了婚禮哑梳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绘盟。我一直安慰自己鸠真,他們只是感情好,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布龄毡。 她就那樣靜靜地躺著吠卷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稚虎。 梳的紋絲不亂的頭發(fā)上撤嫩,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音蠢终,去河邊找鬼序攘。 笑死,一個胖子當著我的面吹牛寻拂,可吹牛的內(nèi)容都是我干的程奠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼祭钉,長吁一口氣:“原來是場噩夢啊……” “哼瞄沙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后康吵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咪辱,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡猜惋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡霹粥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疼鸟,到底是詐尸還是另有隱情后控,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布空镜,位于F島的核電站浩淘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏姑裂。R本人自食惡果不足惜馋袜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望舶斧。 院中可真熱鬧,春花似錦察皇、人聲如沸茴厉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矾缓。三九已至,卻和暖如春稻爬,著一層夾襖步出監(jiān)牢的瞬間嗜闻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工桅锄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留琉雳,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓友瘤,卻偏偏與公主長得像翠肘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辫秧,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

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