我對這個技術(shù)也有" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運營 > 基于EOS生態(tài)的一元奪寶游戲開發(fā)

基于EOS生態(tài)的一元奪寶游戲開發(fā)

時間:2023-06-21 17:30:02 | 來源:網(wǎng)站運營

時間:2023-06-21 17:30:02 來源:網(wǎng)站運營

基于EOS生態(tài)的一元奪寶游戲開發(fā):

距離EOS主網(wǎng)上線已經(jīng)有一段時間了。EOS一直被期待可以成為下一代區(qū)塊鏈技術(shù),因為他解決了ETH 吞吐量低的問題,自從主網(wǎng)上線,也出現(xiàn)了蠻多的基于EOS DAPP(分布式應用)。

我對這個技術(shù)也有點興趣,所以決定用設(shè)計開發(fā)一個EOS奪寶游戲來驗證下。簡單而言可以理解成一元奪寶的EOS版,若干用戶每個人投一個EOS,當獎池到達N個EOS的時候,就開獎,把N個EOS返回給中獎用戶。

相比于傳統(tǒng)技術(shù)的一元奪寶,EOS奪寶最大的優(yōu)勢在于公平公正,傳統(tǒng)的一元奪寶代碼都運行在某公司的服務器上,代碼是否有吃用戶錢的邏輯誰也不知道。但是智能合約代碼是部署在區(qū)塊鏈上,運行的代碼,代碼運行的結(jié)果都可以被所有用戶查詢到的,公開透明從而保證了游戲(賭博)的公平性。同時相比于ETH,EOS網(wǎng)絡擁有高吞吐量,用戶不會感受到網(wǎng)絡擁堵,滿足高并發(fā)下對性能的要求。

備注:一元奪寶已經(jīng)被定義為違法,該項目只供學習參考,另外EOS安全相關(guān)知識需要認真理解,實踐過程中發(fā)生二次丟幣事件。

整體架構(gòu)

從產(chǎn)品形態(tài)上,它需要一個網(wǎng)頁入口,這個入口會展示當前有多少人參與游戲,距離開獎還有多少個EOS,歷史參與游戲的用戶名單,歷史獲得獎品的用戶名單等信息。它是一個 web application,它需要和 EOS 區(qū)塊鏈數(shù)據(jù)交互,可以直接從鏈上獲取數(shù)據(jù)以保證游戲的公開公正。

為了方便理解,簡單線框圖 demo 如下:

要提供一個方式讓用戶參與游戲,因為這個 web application 不具備錢包的屬性,所以不能直接轉(zhuǎn)賬,轉(zhuǎn)賬還是依賴用戶從錢包發(fā)起。

當前創(chuàng)建EOS賬戶還是比較麻煩,不過網(wǎng)絡上還是能找到蠻多途徑。假設(shè)你已經(jīng)有EOS賬戶,并將它倒入到 imtoken 等支持EOS的錢包。

參與的用戶(player)通過 imtoken 發(fā)起一筆轉(zhuǎn)賬到合約發(fā)布者賬戶(owner)。合約發(fā)布者發(fā)布的智能合約會監(jiān)聽轉(zhuǎn)賬請求,記錄下轉(zhuǎn)賬人,如果獎池滿足條件,則觸發(fā)開獎邏輯。

整體架構(gòu)如下圖:

開發(fā)環(huán)境準備

開發(fā)環(huán)境的準備可以參考官方文檔,

這里會列舉一些重點說明一下。開發(fā)環(huán)境整體分兩個部分,運行EOS節(jié)點和準備智能合約編譯環(huán)境。

運行 EOS 節(jié)點

一般有兩種方式運行EOS節(jié)點,本地編譯和docker運行,這里推薦使用docker運行,因為真的很省心,編譯可能遇到各種問題,并且時間很長。docker運行只要 pull下來 image,運行就好了。具體命令如下:

docker pull eosio/eosdocker run --name eosio / --publish 7777:7777 / --publish 127.0.0.1:5555:5555 / --volume /root/contracts:/root/contracts / --detach / eosio/eos / /bin/bash -c / "keosd --http-server-address=0.0.0.0:5555 & exec nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::history_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_plugin --plugin eosio::history_api_plugin --plugin eosio::http_plugin -d /mnt/dev/data --config-dir /mnt/dev/config --http-server-address=0.0.0.0:7777 --access-control-allow-origin=* --contracts-console --http-validate-host=false --filter-on='*'"智能合約編譯環(huán)境(EOSIO-CPP)

不同EOS智能合約使用 C++ 編寫,當我們設(shè)計好完成智能合約代碼后,需要編譯成abi文件,然后發(fā)布到網(wǎng)絡上。具體流程可以參考如下文檔

但是,也是有一些坑的,主要是 C++ 版本的問題,默認情況下 centos 系統(tǒng)自帶的版本 gcc版本太低了,我升級到 7.3.0 后,編譯出現(xiàn)的問題消失。

智能合約編寫

智能合約主要解決幾個問題,首先是要監(jiān)聽到轉(zhuǎn)賬,然后記錄參與用戶,在滿足條件的時候給用戶開獎。核心代碼如下,可以一一講解:

class duobao: public eosio::contract{public: duobao(account_name self) :contract(self), bets(_self, _self), winners(_self, _self) { } using contract::contract; static constexpr int64_t unit_count = 10; static constexpr int64_t min_count = 1 * unit_count; static constexpr int64_t max_count = 20 * unit_count; static constexpr float win_ratio = 0.9; uint64_t random_generate(uint64_t range) { checksum256 result; auto mixedBlock = tapos_block_prefix() * tapos_block_num(); const char *mixedChar = reinterpret_cast<const char *>(&mixedBlock); sha256( (char *)mixedChar, sizeof(mixedChar), &result); const char *p64 = reinterpret_cast<const char *>(&result); int64_t sum = 0; for(int i = 0; i<6; i++) { sum += (int64_t)p64[i]; } return (abs(sum) % (range)); } void buy(account_name from, account_name to, asset quantity, string memo) { if ((from == _self) || (to != _self)) { return; } eosio_assert(quantity.symbol == CORE_SYMBOL, "Must by paid by EOS"); eosio_assert(quantity.amount % min_count == 0, "Bet Must Be divided by 1 EOS"); eosio_assert(quantity.amount >= min_count, "Bet Must be greater than 1 EOS"); auto new_offer_itr = bets.emplace(_self, [&](auto& betting){ betting.id = bets.available_primary_key(); betting.bet = quantity; betting.owner = from; betting.memo = memo; }); uint64_t total = query_total(); if( total >= max_count ){ doOpen(total); } } uint64_t query_total(){ uint64_t sum = 0; for( const auto& item : bets ) { sum += item.bet.amount; } return sum; } void doOpen(uint64_t total) { uint64_t towin = random_generate(total / unit_count) * unit_count, inc = 0; for( const auto& item : bets ) { // the winner if( (towin >= inc) && (towin < (inc + item.bet.amount)) ) { auto new_offer_itr = winners.emplace(_self, [&](auto& winner){ winner.id = winners.available_primary_key(); winner.owner = item.owner; winner.bet = item.bet; winner.total = total; winner.res = towin; }); action( permission_level{_self, N(active)}, N(eosio.token), N(transfer), std::make_tuple(_self, item.owner, asset(total * win_ratio), item.memo) ).send(); break; } inc += item.bet.amount; } for(auto itr = bets.begin(); itr != bets.end(); ){ itr = bets.erase(itr); } } // @abi action [[eosio::action]] void open( account_name user ) { require_auth( user ); doOpen(query_total() ); }private: //@abi table offer i64 struct [[eosio::table]] betting { uint64_t id; account_name owner; asset bet; string memo; uint64_t primary_key()const { return id; } uint64_t by_bet()const { return (uint64_t)bet.amount; } EOSLIB_SERIALIZE( betting, (id)(owner)(bet)(memo) ) }; //@abi table offer i64 struct [[eosio::table]] winner { uint64_t id; account_name owner; asset bet; uint64_t total; uint64_t res; uint64_t primary_key()const { return id; } EOSLIB_SERIALIZE( winner, (id)(owner)(bet)(total)(res) ) }; typedef eosio::multi_index< N(betting), betting > bet_index; typedef eosio::multi_index< N(winner), winner> account_index; bet_index bets; account_index winners;};extern "C" { void apply( uint64_t receiver, uint64_t code, uint64_t action ) { duobao thiscontract(receiver); if((code == N(eosio.token)) && (action == N(transfer))) { execute_action(&thiscontract, &duobao::buy); return; } if (code != receiver) return; switch (action) { EOSIO_API(duobao, (open)) }; eosio_exit(0); }}重點說幾個地方吧:

  1. 監(jiān)聽轉(zhuǎn)賬:
extern "C" { void apply( uint64_t receiver, uint64_t code, uint64_t action ) { duobao thiscontract(receiver); if((code == N(eosio.token)) && (action == N(transfer))) { execute_action(&thiscontract, &duobao::buy); return; } if (code != receiver) return; switch (action) { EOSIO_API(duobao, (open)) }; eosio_exit(0); }}從代碼可以看出,當執(zhí)行的合約是 eosio.token ,行為是 transfer 的時候會觸發(fā) duobao 這個智能合約的 buy 函數(shù)。eosio.token 是系統(tǒng)提供的智能合約,每個賬戶都會默認運行一些系統(tǒng)級別智能合約,eosio.token 定義了 EOS 生態(tài)中和token相關(guān)的一些行為,包括轉(zhuǎn) EOS,發(fā)行新 token等。

2. 記錄參與者

參與者數(shù)據(jù)記錄在 multi_index 中,采用一個 betting 的數(shù)據(jù)結(jié)構(gòu),來存儲。數(shù)據(jù)包括參與者賬戶,投注額度,備注等信息。

3. 隨機數(shù)生成(開獎)

我們會覺得開獎是一個簡單的過程,因為只要rand 函數(shù)調(diào)用一下,就可以生成一個隨機數(shù)作為開獎結(jié)果。但是EOS規(guī)定,智能合約的代碼執(zhí)行結(jié)果是明確的,所以 rand 函數(shù)在編譯過程中是不可識別的。智能用一些其他的方式模擬隨機數(shù)字的生成,官方提供的例子中,對這個問題有一個方案,就是用戶在提交的時候,隨意給一個備注(memo),然后通過memo的hash來決定誰是贏家。但是這個方法對用戶體驗有影響,用戶在轉(zhuǎn)賬的時候,還要加 memo 麻煩,所以這里 使用了 knight 的方案:

4. 發(fā)獎

發(fā)獎其實就是轉(zhuǎn)賬給中獎用戶~,就是這段代碼:

action(permission_level{_self, N(active)}, N(eosio.token), N(transfer), std::make_tuple(_self, item.owner, asset(total * win_ratio), item.memo) ).send();可以理解為從智能合約A調(diào)用智能合約B,本案是 duobao 智能合約調(diào)用 eosio.token 的 transfer 方法。而這個操作需要對合約授權(quán):

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


合約完整代碼在:

交互

既然我們已經(jīng)把游戲參與者數(shù)據(jù)寫到鏈上,后續(xù)肯定希望某種方式把數(shù)據(jù)從鏈中讀出來,前端需要展示,后端開發(fā)也需要查看,主要有 cleos 控制臺和 rest api 方式獲取數(shù)據(jù)。

cleos get table $accountname $accountname $tablenamecurl -XPOST "http://mainnet.eoscalgary.io/v1/chain/get_table_rows" --data '{"table":"$tablename","scope":"$accountname","code":"$accountname","limit":10,"json":true}'其中第二種方式可以用來獲取數(shù)據(jù)給前端展示使用。官方還提供了另外一套API來監(jiān)控EOS網(wǎng)絡,在如下地址:

發(fā)布

合約編寫、編譯都完成后,就是發(fā)布了。發(fā)布過程中,可能遇到 RAM 不足,CPU不足的情況,這個時候需要使用EOS購買RAM,CPU或者NET。可以使用 imtoken 錢包購買,感覺EOS還是略坑的,因為購買這些東西略貴,買了好幾百塊錢的資源才能發(fā)布一個合約,略微有些坑。

到這里一款基于EOS智能合約的奪寶游戲就完成了,感興趣的小伙伴可以試著玩玩。

關(guān)鍵詞:游戲,生態(tài)

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點擊下載Chrome瀏覽器
關(guān)閉