美文网首页区块链研习社
在EOS上做个菠菜游戏

在EOS上做个菠菜游戏

作者: Andytl的世界 | 来源:发表于2019-05-12 23:27 被阅读96次

    区块链中的随机数》中介绍了一种无需各方信任产生随机数的方法,本文中我们用这个方法做一个双方对赌的菠菜游戏,玩家1给一个随机数,玩家2也给一个随机数,通过计算两个随机数得到0-99内的一个数,如果小于50则玩家1胜利,大于50则玩家2胜利。
    代码原型来自:https://learneos.dev/Learn_EOS_Randomness_preview.pdf,做了些修改,让智能合约randprotocol可以跑起来。randprotocol.cpp的源代码如下:

    #include <eosiolib/eosio.hpp>
    #include <stdlib.h>
    #include <math.h>
    
    
    using namespace eosio;
    using namespace std;
    
    
    CONTRACT randprotocol : public eosio::contract
    {
        public:
            randprotocol(name receiver, name code, datastream<const char *> ds) :
                contract(receiver, code, ds), games(receiver, receiver.value) {}
            //字符串形式的十六进制数转换为整数的方法
            uint64_t hex_to_uint64(const string &hex)
                {
                    
                    char *hexstr;//用指针hexstr遍历字符串中每个代表十六进制数的字符
                    int length = 0;//用length记录字符串长度
                    const int base = 16;     // 十六进制数的基底是16
                    uint64_t decnum = 0; //记录转换的整数
                    int i;//循环遍量
    
                    // 遍历整个hex字符串,统计字符串长度
                    for (hexstr = (char*)(&hex[0]); *hexstr != '\0'; hexstr++) {
                        length++;
                    }
                    // 计算hex字符串代表的整数值,大概思路是,用指针从高位到低位指向hex中每个字符,并将字符代表的ASCII码转换位数字,如"a"转换为10,再累加计算出字符串对应的整数值。
                    hexstr = (char*)(&hex[0]);
                    for (i = 0; i < length; i++, hexstr++) {
                    if (*hexstr >= 48 && *hexstr <= 57) {  // *hexstr 属于 0-9
                      decnum += uint64_t((((int)(*hexstr)) - 48) * pow(base, length - i - 1));
                    }
                    else if ((*hexstr >= 65 && *hexstr <= 70))  {  // *hexstr 属于 A-F
                      decnum += uint64_t((((int)(*hexstr)) - 55) * pow(base, length - i - 1));
                    }
                    else if (*hexstr >= 97 && *hexstr <= 102) {  //  *hexstr 属于 a-f
                      decnum += uint64_t((((int)(*hexstr)) - 87) * pow(base, length - i - 1));
                    }
                    else {
                        break;
                    }
                    }
                    return decnum;
                }
                   //定义智能合约中的结构体,用于记录数据
            struct [[eosio::table]] game_s
            {
                name player1;
                name player2;
                checksum256 p1_commitment;
                uint64_t p2_rand;
    
                auto primary_key() const { return player1.value; }
                EOSLIB_SERIALIZE(game_s, (player1)(player2)(p1_commitment)(p2_rand))
            };
    
            typedef eosio::multi_index<"games"_n, game_s> games_t;
            games_t games;
                   //player1首先发送给智能合约一个随机数的哈希值,也就是创建一个“承诺交易”
            ACTION create(name player1, const eosio::checksum256 &commitment)
            {
                require_auth(player1);
                auto itr = games.find(player1.value);
                eosio::check(itr == games.end(), "finish existing game first");
    
                games.emplace(player1, [&](auto &g) {
                    g.player1 = player1;
                    g.p1_commitment = commitment;
                });
    
            }
                  //player2响应player1的交易,并上传自己的随机数
            ACTION respond(name player2, name game_host, const string &randomness_as_hex)
    
            {
                require_auth(player2);
                auto itr = games.find(game_host.value);
                eosio::check(itr != games.end(), "game does not exist");
                uint64_t randomness = hex_to_uint64(randomness_as_hex);
    
                games.modify(itr, ""_n, [&](auto &g) {
                    g.player2 = player2;
                    g.p2_rand = randomness;
            });
    
            }
                   //player1揭露自己的随机数,并验证是否位承诺交易的随机数。得到两个人的随机数后,智能合约计算出一个在[0,100)范围内的随机数,如果小于50则player1胜利,大于50则player2胜利
            ACTION reveal(name player1, const string &p1_rand_as_hex)
            {
                require_auth(player1);
                auto itr = games.find(player1.value);
                eosio::check(itr != games.end(), "game does not exist");
                eosio::check(itr->player2.value > 0, "no other player responded yet");
    
                // checks if sha256(p1_rand_as_hex, bytes_size) == third argument
                assert_sha256(
                    (char *)p1_rand_as_hex.c_str(),
                    p1_rand_as_hex.size(),
                    itr->p1_commitment);
                uint64_t randomness = hex_to_uint64(p1_rand_as_hex) ^ itr->p2_rand;
                randomness = randomness % 100;
                eosio::print(("Rolled " + to_string(randomness) + ". ").c_str());
                if (randomness < 50)
                {
                    eosio::print("Player 1 wins!");
                }
                else
                {
                    eosio::print("Player 2 wins!");
                }
    
                games.erase(itr);
    
            }
    
    };
    
    

    发布智能合约randprotocol的过程与《手把手教你发行EOS代币》很类似。也可以把上面代码拷贝到在线eos智能合约开发平台Beosin中,几分钟就能编译、部署、执行智能合约,非常方便。只不过Beosin中的debug功能还没完善,在线调试代码很麻烦。

    在本地环境中可以验证合约执行情况,如下:

    # 计算一个随机数
    openssl rand -hex 8
    # outputs 021cb69650e3dd84
    
    # 计算随机数的哈希值
    echo -n "021cb69650e3dd84" | openssl dgst -sha256
    # outputs eb162b76b7830c61e22c3379f83bafc212d408698c9bbeb3923ffb594a3918bd
    
    # player1发起承诺交易
    cleos push action rand create '{"player1": "test1", "commitment": "eb162b76b7830c..."}' -p test1
    
    # player2 产生随机数并发起响应
    openssl rand -hex 8
    # outputs 981b3e64607e49c4
    cleos push action rand respond '{"player2": "test2", "game_host": "test1",
    "randomness_as_hex": "981b3e64607e49c4"}' -p test2
    
    # player1 揭露随机数并计算出结果
    cleos push action rand reveal '{"player1": "test1", "p1_rand_as_hex": "021cb69650e3dd84"}' -p test1
    
    # >> Rolled 76. Player 2 wins!
    

    也可以参考上述代码参数,在Beosin环境中执行智能合约,以验证智能合约。一个简单的菠菜游戏就诞生了,作为一个dapp,它还缺乏前端交互界面,后端分配代币机制,以后补充。

    相关文章

      网友评论

        本文标题:在EOS上做个菠菜游戏

        本文链接:https://www.haomeiwen.com/subject/rjahaqtx.html