可公开的eos竞猜游戏随机算法(四)

版权声明:转载请说明出处 https://blog.csdn.net/weixin_39842528/article/details/86719411
#include "eosdacrandom.hpp"
    #include <eosiolib/system.h>
    #include <eosiolib/stdlib.hpp>
    #include <eosiolib/action.hpp>
    #include <eosiolib/symbol.hpp>
    #include "../eosdactoken/eosdactoken.hpp"

    using namespace eosio;

    eosdacrandom::eosdacrandom(account_name name)
            : contract(name),
              _seeds(_self, name),
              _geters(_self, name)
    {
    }

    eosdacrandom::~eosdacrandom()
    {
    }

    void eosdacrandom::setsize(uint64_t size)
    {
        require_auth(_self);

        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        if (existing != config.end()) {
            if (existing->hash_count == existing->target_size) {
                if (existing->hash_count != existing->seed_match) {
                    eosio_assert(false, "do not set size during sendseed period");
                }
            }

            config.modify(existing, _self, [&](auto& c){
                c.target_size = size;
            });
        } else {
            config.emplace(_self, [&](auto& c){
                c.owner = _self;
                c.target_size = size;
            });
        }
    }

    void eosdacrandom::sendseed(name owner, int64_t seed, string sym)
    {
        eosio_assert(is_account(owner), "Invalid account");
        symbol_type symbol(string_to_symbol(4, sym.c_str()));
        eosio::asset fromBalance = eosdactoken(N(eosdactoken)).get_balance(owner, symbol.name());
        eosio_assert(fromBalance.amount > 0, "account has not enough OCT to do it");

        eosio::asset selfBalance = eosdactoken(N(eosdactoken)).get_balance(_self, symbol.name());
        eosio_assert(selfBalance.amount > 0, "contract account has not enough OCT to do it");

        require_auth(owner);

        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        const auto& cfg = *existing;

        const auto& sd = _seeds.find(owner);
        if (cfg.hash_count < cfg.target_size) {
            if (sd != _seeds.end()) {
                _seeds.erase(sd);
                config.modify(cfg, _self, [&](auto& c){
                    c.hash_count --;
                });
            }
            eosio_assert(false, "hash size not fulled");
        }

        string h = cal_sha256_str(seed);
        eosio_assert(sd->seed != seed, "you have already send seed");
        if (sd->hash != h) {
            //SEND_INLINE_ACTION( eosdacvote, vote, {_self,N(active)}, {_self, owner, selfBalance, false} );
            for (auto itr = _seeds.cbegin(); itr != _seeds.cend(); ) {
                itr = _seeds.erase(itr);
            }
            config.modify(cfg, _self, [&](auto& c){
                c.hash_count = 0;
            });
            return;
        }

        _seeds.modify(sd, _self, [&](auto& a){
            a.seed = seed;
        });

        config.modify(cfg, _self, [&](auto& c){
            c.seed_match = c.seed_match + 1;
            print(c.seed_match);
        });

        // if all seeds match
        if (seedsmatch()) {
            dispatch_request(owner);
        }
    }

    void eosdacrandom::sendhash(name owner, string hash, string sym)
    {
        eosio_assert(is_account(owner), "Invalid account");

        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        const auto& cfg = *existing;

        eosio_assert(cfg.hash_count < cfg.target_size, "seeds is full");

        symbol_type symbol(string_to_symbol(4, sym.c_str()));
        eosio::asset fromBalance = eosdactoken(N(eosdactoken)).get_balance(owner, symbol.name());
        eosio_assert(fromBalance.amount > 0, "account has not enough OCT to do it");

        require_auth(owner);

        auto s = _seeds.find(owner);
        if (s == _seeds.end()) {
            _seeds.emplace(_self, [&](auto& a){
                a.owner = owner;
                a.hash = hash;
            });

            config.modify(cfg, _self, [&](auto& c){
                c.hash_count++;
            });
        } else {
            _seeds.modify(s, _self, [&](auto& a){
                a.hash = hash;
            });
        }
    }

    void eosdacrandom::regrequest(name owner, uint64_t index)
    {
        eosio_assert(is_account(owner), "Invalid account");

        uint64_t cur = current_time();
        auto it = _geters.find(owner);
        request_info req {index, cur};
        if (it == _geters.end()) {
            _geters.emplace(_self, [&](auto& a){
                a.owner = owner;
                a.requestinfo.push_back(req);
            });
        } else {
            _geters.modify(it, _self, [&](auto& a){
                bool same_idx = false;
                for (auto ri = a.requestinfo.begin(); ri != a.requestinfo.end(); ++ri) {
                    if (ri->index == index) {    // if index equals former index.
                        *ri = req;
                        same_idx = true;
                        break;
                    }
                }

                if (!same_idx) {
                    a.requestinfo.push_back(req);
                }
            });
        }
    }

    int64_t eosdacrandom::random()
    {
        // use _seeds to generate random number
        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        eosio_assert(existing->hash_count == existing->target_size, "seed is not full");

        // how to generate random number?
        int64_t  seed = 0;
        for (auto it = _seeds.cbegin(); it != _seeds.cend();) {
            seed += it->seed;
            it = _seeds.erase(it);
        }

        config.modify(existing, _self, [&](auto& c){
            c.hash_count = 0;
            c.seed_match = 0;
        });

        checksum256 cs = cal_sha256(seed);
        return (((int64_t)cs.hash[0] << 56 ) & 0xFF00000000000000U)
            |  (((int64_t)cs.hash[1] << 48 ) & 0x00FF000000000000U)
            |  (((int64_t)cs.hash[2] << 40 ) & 0x0000FF0000000000U)
            |  (((int64_t)cs.hash[3] << 32 ) & 0x000000FF00000000U)
            |  ((cs.hash[4] << 24 ) & 0x00000000FF000000U)
            |  ((cs.hash[5] << 16 ) & 0x0000000000FF0000U)
            |  ((cs.hash[6] << 8 ) & 0x000000000000FF00U)
            |  (cs.hash[7] & 0x00000000000000FFU);
    }

    bool eosdacrandom::seedsmatch()
    {
        seedconfig_table config(_self, _self);
        auto existing = config.find(_self);
        eosio_assert(existing != config.end(), "target size must set first");
        const auto& cfg = *existing;

        if (cfg.hash_count != cfg.target_size) {
            return false;
        }

        if (cfg.hash_count == cfg.seed_match) {
            return true;
        }

        return false;
    }

    checksum256 eosdacrandom::cal_sha256(int64_t word)
    {
        checksum256 cs = { 0 };
        char d[255] = { 0 };
        snprintf(d, sizeof(d) - 1, "%lld", word);
        sha256(d, strlen(d), &cs);

        return cs;
    }

    string eosdacrandom::cal_sha256_str(int64_t word)
    {
        string h;
        checksum256 cs = cal_sha256(word);
        for (int i = 0; i < sizeof(cs.hash); ++i) {
            char hex[3] = { 0 };
            snprintf(hex, sizeof(hex), "%02x", static_cast<unsigned char>(cs.hash[i]));
            h += hex;
        }

        return h;
    }

    void eosdacrandom::dispatch_request(name owner)
    {
        print("all seeds matched.");
        uint64_t cur = current_time();
        int64_t num = random();
        static int expiraion = 3000; // ms
        std::vector<std::vector<request_info>> reqs;

        for (auto i = _geters.cbegin(); i != _geters.cend();) {
            std:vector<request_info> tmp(i->requestinfo);
            for (auto j = tmp.begin(); j != tmp.end();) {
                if (cur - j->timestamp >= expiraion) {
                    dispatch_inline(i->owner, string_to_name("getrandom"),
                                    {permission_level(_self, N(active))},
                                    std::make_tuple(j->index, num));
                    j = tmp.erase(j);
                } else {
                    ++j;
                }
            }

            if (tmp.size()) {
                reqs.push_back(tmp);
            }

            i = _geters.erase(i);
        }

        if (reqs.size()) {
            for (auto r = reqs.cbegin(); r != reqs.cend(); ++r) {
                _geters.emplace(_self, [&](auto& a){
                    a.owner = owner;
                    a.requestinfo = *r;
                });
            }
        }
    }

    EOSIO_ABI( eosdacrandom, (setsize) (sendseed) (sendhash) (regrequest) )

谨慎使用 

猜你喜欢

转载自blog.csdn.net/weixin_39842528/article/details/86719411