1. 程式人生 > >【問鏈-EOS公開課】第十一課 EOS 智慧合約相互呼叫

【問鏈-EOS公開課】第十一課 EOS 智慧合約相互呼叫

EOS中合約之間是可以相互呼叫的,主要通過inline action完成合約之間的呼叫。

譬如在擲骰子游戲中,存在兩個玩家先下注資金,然後比較骰子大小後決定勝負,贏的那一方將獲得所有的下注資金。在eosio原始碼eos/build/contract/dice 智慧合約示例中,Alice和Bob是兩個玩家,他們各自將資金賬戶裡的3個EOS作為賭注,先抵押給Dice賬戶,然後在遊戲決出勝負後,Dice賬戶就自動把賭注歸還給勝方。這其中就涉及到代幣的轉賬操作,因此很自然的可以想到,在deposit(下注抵押資金)和最後的withdraw(勝方贏取資金)這兩個操作中,就可以通過呼叫eosio.token的transfer動作來完成。

dice合約說明
此合約實現了一個簡單的骰子游戲,兩位玩家各有 50% 機率獲勝

玩家 1 下注 3 EOS,並提交一個 SHA256 加密的金鑰1
玩家 2 下注 3 EOS,並提交一個 SHA256 加密的金鑰2
因為兩玩家下注數量相同,所以匹配,遊戲開始

一位玩家公佈金鑰
五分鐘倒計時後,如果第二位玩家沒有公佈金鑰,則第一位玩家直接獲勝
另一位玩家公佈金鑰,基於兩個金鑰決出獲勝者,並支付賭注
遊戲結束後,勝者可以取回獎勵

下面是deposit 和 withdraw 的函式實現。其中均對eosio.token的action—— transfer進行了呼叫。

//@abi action  
      void deposit( const account_name from, const asset& quantity ) {//下注抵押資金
         
         eosio_assert( quantity.is_valid(), "invalid quantity" );
         eosio_assert( quantity.amount > 0, "must deposit positive quantity" );

         auto itr = accounts.find(from);//在賬戶列表中查詢要轉出代幣的賬號是否存在
         if( itr == accounts.end() ) {//不存在的話就插入賬號列表
            itr = accounts.emplace(_self, [&](auto& acnt){
               acnt.owner = from;
            });
         }
         
        //對eosio.token的transfer進行合約呼叫,玩家開始下注資金
        //賬戶(from)對賬戶( _self)進行轉賬,對應於遊戲中,抵押代幣到
         action(
            permission_level{ from, N(active) },
            N(eosio.token), N(transfer),
            std::make_tuple(from, _self, quantity, std::string(""))
         ).send();

         accounts.modify( itr, 0, [&]( auto& acnt ) {//修改轉出賬號的代幣餘額
            acnt.eos_balance += quantity;
         });
      }


//@abi action
      void withdraw( const account_name to, const asset& quantity ) {//勝方贏取資金
         require_auth( to );

         eosio_assert( quantity.is_valid(), "invalid quantity" );
         eosio_assert( quantity.amount > 0, "must withdraw positive quantity" );

         auto itr = accounts.find( to );//在賬戶列表中查詢要轉入代幣的賬號是否存在
         eosio_assert(itr != accounts.end(), "unknown account");

         accounts.modify( itr, 0, [&]( auto& acnt ) {//轉出代幣
            eosio_assert( acnt.eos_balance >= quantity, "insufficient balance" );
            acnt.eos_balance -= quantity;
         });

         //對eosio.token的transfer進行合約呼叫,Dice主賬號對勝利一方傳送資金
         //代表在資金撤回操作中,通過呼叫eosio.token的transfer,賬戶(_self)對賬戶(to)進行轉賬,對應於遊戲中,Dice主賬戶為勝利的一方發放所贏的賭注
         action(
            permission_level{ _self, N(active) },
            N(eosio.token), N(transfer),
            std::make_tuple(_self, to, quantity, std::string(""))
         ).send();

         if( itr->is_empty() ) {
            accounts.erase(itr);
         }
      }

1.啟動nodeos

nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin

2.設定 Bios 合約

cleos set contract eosio build/contracts/eosio.bios -p eosio

3. 部署eosio.token合約

cleos create account eosio eosio.token EOS8YMWk6vxawJEDML7mYXA3mGUap7L68L3GroGUpDhpbuadwHXom
返回結果:
executed transaction: 968f488926441009ecfaf899379a2c304a7e771b46a5536330a3bd5c747550a3  200 bytes  135 us
      eosio <= eosio::newaccount            {"creator":"eosio","name":"eosio.token","owner":{"threshold":1,"keys":[{"key":"EOS8YMWk6vxawJEDML7mY...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

4.給 eosio.token 設定 eosio.token 合約用於發幣

cleos set contract eosio.token build/contracts/eosio.token -p eosio.token

5.建立 dice 賬號

cleos create account eosio dice EOS7EjVuYKxPRFECDkzsMtD57ootfQUMGQKrtmdmS3GPvTJTcwfSi
執行結果:
executed transaction: c9d7de164bf4749d958502ff9202087ca7d45a7463f72f8ab96054c589a694fb  200 bytes  169 us
     eosio <= eosio::newaccount            {"creator":"eosio","name":"dice","owner":{"threshold":1,"keys":[{"key":"EOS7EjVuYKxPRFECDkzsMtD57oot...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

6.給 dice 設定 dice 合約

cleos set contract dice build/contracts/dice -p dice

7.建立EOS代幣

cleos push action eosio.token create '["eosio","100000000.0000 EOS"]' -p eosio.token
執行結果:
executed transaction: ff0a266a3125331d13d796a26c78d388ff6242e78e23ba404f86df6a2f28fbb0  120 bytes  437 us
 eosio.token <= eosio.token::create          {"issuer":"eosio","maximum_supply":"100000000.0000 EOS"}
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

8.建立alice和bob賬戶

cleos create account eosio alice EOS5JUBZXokmgHR7yHFgxoZdQZyfvu2oCHiPBeGUE3fQyZ9MHdmi8
執行結果:
executed transaction: aac0663610d3763bb9f282c507a0923e1a1b973741525257f6e012fdac143535  200 bytes  183 us
    eosio <= eosio::newaccount            {"creator":"eosio","name":"alice","owner":{"threshold":1,"keys":[{"key":"EOS5JUBZXokmgHR7yHFgxoZdQZy...

cleos create account eosio bob EOS6FMtV7gnbBLQ2CbD7J3YAKA8hY6u6jZ2KGtcy628z8QQ8MvXBz
執行結果:
executed transaction: d53956cc2fea6e85d67dee1a17b1f3e85b9838f9acd02ad6d87a9672443774e3  200 bytes  138 us
        eosio <= eosio::newaccount            {"creator":"eosio","name":"bob","owner":{"threshold":1,"keys":[{"key":"EOS6FMtV7gnbBLQ2CbD7J3YAKA8hY...

9.空投 1000 個 EOS 給 alice

cleos push action eosio.token issue '[ "alice", "1000.0000 EOS", "" ]' -p eosio

10.空投 1000 個 EOS 給 bob

cleos push action eosio.token issue '[ "bob", "1000.0000 EOS", "" ]' -p eosio

11.alice 給 dice 設定轉賬許可權

cleos set account permission alice active '{"threshold": 1,"keys": [{"key": "EOS7EjVuYKxPRFECDkzsMtD57ootfQUMGQKrtmdmS3GPvTJTcwfSi","weight": 1}],"accounts": [{"permission":{"actor":"dice","permission":"eosio.code"},"weight":1}]}' owner -p alice
執行結果:
executed transaction: 86fde62595343963366db70d9f9f70edab12928437d622d0f9246e00a62687b1  184 bytes  327 us
    eosio <= eosio::updateauth            {"account":"alice","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[{"key":"EOS7...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

12.給bob賦予轉賬許可權

cleos set account permission bob active '{"threshold": 1,"keys": [{"key": "EOS7EjVuYKxPRFECDkzsMtD57ootfQUMGQKrtmdmS3GPvTJTcwfSi","weight": 1}],"accounts": [{"permission":{"actor":"dice","permission":"eosio.code"},"weight":1}]}' owner -p bob
執行結果:
executed transaction: dc21bcf296a9e749b4488d4188dbe42cb4f85ea7ed639dabcccaa682bdeab2df  184 bytes  183 us
 eosio <= eosio::updateauth            {"account":"bob","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[{"key":"EOS7Ej...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

13.alice 存入 100 EOS 到合約

cleos push action dice deposit '[ "alice", "100.0000 SYS" ]' -p alice

14.bob 存入 100 EOS 到合約

cleos push action dice deposit '[ "bob", "100.0000 SYS" ]' -p bob

15.alice 生成一個密匙

openssl rand  -hex 32
執行結果:
28349b1d4bcdc9905e4ef9719019e55743c84efa0c5e9a0b077f0b54fcd84905

16.alice SHA256 加密密匙

echo -n '28349b1d4bcdc9905e4ef9719019e55743c84efa0c5e9a0b077f0b54fcd84905' | xxd -r -p | sha256sum -b | awk '{print $1}'
d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883

17.alice 下注 3 EOS

cleos push action dice offerbet '[ "3.0000 EOS", "alice", "d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883" ]' -p alice

18.bob 生成一個密匙

openssl rand  -hex 32
15fe76d25e124b08feb835f12e00a879bd15666a33786e64b655891fba7d6c12

19.bob SHA256 加密密匙

echo -n '15fe76d25e124b08feb835f12e00a879bd15666a33786e64b655891fba7d6c12' | xxd -r -p | sha256sum -b | awk '{print $1}'
50ed53fcdaf27f88d51ea4e835b1055efe779bb87e6cfdff47d28c88ffb27129

20.bob 下注 3 SYS,隨後遊戲開始

cleos push action dice offerbet '[ "3.0000 EOS", "bob", "50ed53fcdaf27f88d51ea4e835b1055efe779bb87e6cfdff47d28c88ffb27129" ]' -p bob

21. 遊戲開始後,檢視 Dice 合約的表資料

cleos get table dice dice account
{
  "rows": [{
      "owner": "alice",
      "eos_balance": "97.0000 EOS",
      "open_offers": 0,
      "open_games": 1
    },{
      "owner": "bob",
      "eos_balance": "97.0000 EOS",
      "open_offers": 0,
      "open_games": 1
    }
  ],
  "more": false
}

22.cleos get table dice dice game

{
  "rows": [{
      "id": 1,
      "bet": "3.0000 EOS",
      "deadline": "1970-01-01T00:00:00",
      "player1": {
        "commitment": "d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883",
        "reveal": "0000000000000000000000000000000000000000000000000000000000000000"
      },
      "player2": {
        "commitment": "50ed53fcdaf27f88d51ea4e835b1055efe779bb87e6cfdff47d28c88ffb27129",
        "reveal": "0000000000000000000000000000000000000000000000000000000000000000"
      }
    }
  ],
  "more": false
}

23.bob 公佈密匙

cleos push action dice reveal '[ "50ed53fcdaf27f88d51ea4e835b1055efe779bb87e6cfdff47d28c88ffb27129", "15fe76d25e124b08feb835f12e00a879bd15666a33786e64b655891fba7d6c12" ]' -p bob

24.現在的表資料,game 表有個截止時間(5分鐘後)

cleos get table dice dice game
{
  "rows": [{
      "id": 1,
      "bet": "3.0000 EOS",
      "deadline": "2018-10-31T06:03:56",
      "player1": {
        "commitment": "d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883",
        "reveal": "0000000000000000000000000000000000000000000000000000000000000000"
      },
      "player2": {
        "commitment": "50ed53fcdaf27f88d51ea4e835b1055efe779bb87e6cfdff47d28c88ffb27129",
        "reveal": "15fe76d25e124b08feb835f12e00a879bd15666a33786e64b655891fba7d6c12"
      }
    }
  ],
  "more": false
}

25.alice 公佈密匙,決出勝者,遊戲結束,game 表中移除資料

cleos push action dice reveal '[ "d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883", "28349b1d4bcdc9905e4ef9719019e55743c84efa0c5e9a0b077f0b54fcd84905" ]' -p alice

26.遊戲結束後,檢視 account 表資料,賬戶餘額

cleos get table dice dice account
{
  "rows": [{
      "owner": "alice",
      "eos_balance": "103.0000 EOS",
      "open_offers": 0,
      "open_games": 0
    },{
      "owner": "bob",
      "eos_balance": "97.0000 EOS",
      "open_offers": 0,
      "open_games": 0
    }
  ],
  "more": false
}

27.alice 取出金額

此處需先 dice 合約對 eosio.token 授權,才能進行轉賬

   cleos set account permission dice active '{"threshold": 1,"keys": [{"key": "EOS7EjVuYKxPRFECDkzsMtD57ootfQUMGQKrtmdmS3GPvTJTcwfSi","weight": 1}],"accounts": [{"permission":{"actor":"dice","permission":"eosio.code"},"weight":1}]}' owner -p dice

cleos push action dice withdraw '[ "alice", "103.0000 EOS" ]' -p alice

28.檢視 alice 賬戶餘額

cleos get currency balance eosio.token alice eos
1003.0000 EOS