EOS 合约开发之 FarmEOS 随机数生成代码

yufei       5 年, 5 月 前       1581

FarmEOS 是一个基于 EOS 的玩游戏挖矿 DAPP。 这个游戏还是挺火的,它们的随机数生成代码也公布在 Github 上,地址为 https://github.com/farmeos/farmeos

现在,网站上也有一些对它的分析,比如简书上的这篇文章 FarmEOS随机数研究

小弟不才,本着对 EOS 上各种合约随机数生成的爱好,稍微改了下代码,写了一个完整的范例。

假设存在一个账号 hello,该账号下有一些 EOS 数字货币

cleos get currency balance eosio.token hello EOS
69000.0000 EOS

然后我们再看看官方开源出来的代码

uint32_t farmeos::random(account_name name, uint64_t game_id)
{

    asset pool_eos = token(EOS_CON).get_balance(_self, EOS_SYMBOL);
    auto mixd = tapos_block_prefix()*tapos_block_num() + name + game_id - current_time() + pool_eos.amount;
//    print("  mixd", mixd);

    const char *mixedChar = reinterpret_cast<const char *>(&mixd);

    checksum256 result;
    sha256((char *)mixedChar, sizeof(mixedChar), &result);

    uint64_t random_num = *(uint64_t*)(&result.hash[0]) + *(uint64_t*)(&result.hash[8]) + *(uint64_t*)(&result.hash[16]) +  *(uint64_t*)(&result.hash[24]);
//    print(" random:", random_num);

    return (uint32_t)(random_num%100 + 1);
}

这段代码,最重要的其实是下面这行

asset pool_eos = token(EOS_CON).get_balance(_self, EOS_SYMBOL);
    auto mixd = tapos_block_prefix()*tapos_block_num() + name + game_id - current_time() + pool_eos.amount;

第一行代码用户获取某个账号下 EOS 币的余额,从某些方面说,就是当前合约下的 EOS 币的余额

asset pool_eos = token(EOS_CON).get_balance(_self, EOS_SYMBOL);

而第二行,则根据当前的块哈希,块高,游戏 id,当前时间戳和当前账号下的 EOS 余额来获取一个随机数。

auto mixd = tapos_block_prefix()*tapos_block_num() + name + game_id - current_time() + pool_eos.amount;

后面的代码就很简单了,就是根据这个随机数生成一个 checksum256 的结果,然后根据这个结果获取某些位数。

范例

上面,我们分析完了 FarmEOS 的随机数生成代码,接下来我们根据这个代码写一个范例

hello.cpp

#include <eosiolib/asset.hpp>
#include <eosiolib/crypto.h>
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/transaction.hpp>

using namespace eosio;
using namespace std;



class [[eosio::contract]] hello: eosio::contract {
public:
    using eosio::contract::contract;


    [[eosio::action]] void num()
    {
        print("number:",random(_self,1));
    }

private:

    uint32_t random(name name, uint64_t game_id)
    {
        accounts fromAcc(eoscon,_self.value);
        const auto& myAcc = fromAcc.get(eossym.code().raw());


        auto mixd = tapos_block_prefix()*tapos_block_num() + name.value + game_id - current_time() + myAcc.balance.amount;
        print("  mixd", mixd);

        const char *mixedChar = reinterpret_cast<const char *>(&mixd);

        capi_checksum256 result;
        sha256((char *)mixedChar, sizeof(mixedChar), &result);

        uint64_t random_num = *(uint64_t*)(&result.hash[0]) + *(uint64_t*)(&result.hash[8]) + *(uint64_t*)(&result.hash[16]) +  *(uint64_t*)(&result.hash[24]);
        print(" random:", random_num);

        return (uint32_t)(random_num%100 + 1);
    }

    struct account {
        asset    balance;

        uint64_t primary_key()const { return balance.symbol.code().raw(); }
    };

    typedef eosio::multi_index<"accounts"_n, account> accounts;

    const symbol eossym = symbol("EOS", 4);
    const name   eoscon = name("eosio.token");

};

EOSIO_DISPATCH(hello,(num))

接着使用下面的命令来编译合约

eosio-cpp -o hello.wasm hello.cpp --abigen

然后使用下面的命令来部署合约

cleos set contract hello ../hello -p hello@active

最后,我们使用下面的命令来运行 hello 合约的 num 动作

cleos push action hello num '[]' -p hello@active

多运行几次,可以发现结果如下

cleos push action hello num '[]' -p hello@active
executed transaction: 69773b975c05d9bd672d8802f61ea6cead0c07f5c65ea0593077c83d1a59c0fc  96 bytes  2149 us
#         hello <= hello::num                   ""
>>   mixd7682472055927017715 random:1882271469984176250number:51
executed transaction: c6b1471bc3266726cef594aaba2bfad49b5dafe02e209f58f5d6953b4a7a6f66  96 bytes  291 us
#         hello <= hello::num                   ""
>>   mixd7682472054470129202 random:15705627791974369572number:73
目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.