├── .gitignore ├── README.md ├── README_EN.md ├── library.hpp ├── sicbo.abi ├── sicbo.cpp └── sicbo.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 骰宝 2 | 3 | ## 概述 4 | 骰宝是由各閒家向庄家下注的游戏。每次下注前,庄家先把三颗骰子放在有盖的器皿内摇晃,待閒家们下注完毕,庄家便打开器皿并派彩。最常见的玩法是买骰子点数的大小(总点数为3至10称作小,11至18为大,围股庄家通杀) 5 | 6 | ## 公平 7 | 游戏採用EOS区块链技术,由庄家生成三个随机数,并採用哈希算法开奖与派彩,所有人都能在每局结束后验证本局游戏的公平性。由于区块链技术与哈希算法两者任何人都不可逆转,所以能保证游戏结果不为任何人所控制。 8 | 9 | ## 算法 10 | ### 简述 11 | 庄家开盘前会生成一串随机数(32字节)并保密,同时公开展示该数的哈希值作为签名。签名本局游戏中不会变,以保证庄家不会作弊,随后玩家开始下注。开奖时庄家提供该随机数给游戏,游戏通过签名验证该随机数,并使用随机数生成三个骰子,然后自动派奖。玩家可以事后验证该随机数与签名公正性。 12 | 13 | ### 伪代码 14 | 15 | ``` 16 | if (签名 == sha256(随机数[32])) { 17 | 骰子1 = (随机数[0] + 随机数[1] + 随机数[2] + 随机数[3] + 随机数[4] + 随机数[5]) % 6 + 1 18 | 骰子2 = (随机数[6] + 随机数[7] + 随机数[8] + 随机数[9] + 随机数[10]+ 随机数[11])% 6 + 1 19 | 骰子3 = (随机数[12]+ 随机数[13]+ 随机数[14]+ 随机数[15]+ 随机数[16]+ 随机数[17])% 6 + 1 20 | } else { 21 | 验证不过,游戏出错 22 | } 23 | ``` 24 | 25 | ### 示例 26 | 27 | 玩家理解算法需要一些C语言的基础知识,数值均为十六进制。 28 | 29 | 在游戏开奖前,玩家可以获取庄家事先展示的签名,本局假设签名为: 30 | 763f42ad937c1a268a17dfbdbb3b8e8bce12bc7cef5ac94f3ab3110ee78f52ca 31 | 在游戏结束后,庄家会展示该签名所对应的哈希原值(随机数),原值如下: 32 | c6793186e4a0c748118a5070faf7a4ffdd07ea9d07d9f6ca25c4d59b88c6e58a 33 | 套用上方公式可以计算得出 34 | 35 | ``` 36 | commitment = 763f42ad937c1a268a17dfbdbb3b8e8bce12bc7cef5ac94f3ab3110ee78f52ca 37 | source = c6793186e4a0c748118a5070faf7a4ffdd07ea9d07d9f6ca25c4d59b88c6e58a 38 | if (commitment == sha256(source)) { 39 | 3 = (c6 + 79 + 31 + 86 + e4 + a0) % 6 + 1 40 | 1 = (c7 + 48 + 11 + 8a + 50 + 70) % 6 + 1 41 | 5 = (fa + f7 + a4 + ff + dd + 07) % 6 + 1 42 | } 43 | ``` 44 | 3, 1, 5便是本次开奖结果 45 | 46 | ### 第三方验证 47 | 查询一些公示信息可以通过任何第三方网站,比如:[https://bloks.io/](https://bloks.io/) 48 | 49 | 签名,开奖前就能查询: 50 | search - > 庄家名 -> Account Transactions -> Contract -> Tables -> Step 2 - Select Table -> game -> Load Table -> 当前游戏编号 -> commitment 51 | 原值,开奖后庄家公开: 52 | search - > 庄家名 -> Account Transactions -> Contract -> Tables -> Step 2 - Select Table -> game -> Load Table -> 当前游戏编号 -> source 53 | 54 | 计算sha256,这裡以linux操作系统为例。注意,sha256的计算这裡是整形数值,而不是字符串: 55 | 56 | ```bash 57 | >> echo -n 'c6793186e4a0c748118a5070faf7a4ffdd07ea9d07d9f6ca25c4d59b88c6e58a' | xxd -r -p | sha256sum -b | awk '{print $1}' 58 | 59 | >> 763f42ad937c1a268a17dfbdbb3b8e8bce12bc7cef5ac94f3ab3110ee78f52ca 60 | ``` 61 | 62 | 63 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # Sicbo 2 | 3 | ## Overview 4 | 5 | Sicbo is a game that every player makes a bet on the banker. Before each bet, the banker placed three dice in a covered vessel and shook them. After players had finished the bet, the banker opened the vessel and dispatched the lottery. The most common game is the size of the number of dice to guess (the sum of dice is 3 to 10 called small, 11 to 18 for large, lose if any triple appears.) 6 | 7 | 8 | 9 | ## Fairness 10 | 11 | The game uses EOS block chain technology, produces three random number by the banker, and uses the hash algorithm to open the lottery, everyone can verify the fairness of the game at the end of each game. Since neither block chain nor hash algorithm can be reversed by anyone, the result of the game can be guaranteed to be out of anyone's control. 12 | 13 | ## Algorithm 14 | ## Introduction 15 | A random number (32 bytes) is generated and kept secret before the reveal of the bet, and the hash value of the number is publicly displayed as a signature. The signature will not change in this game to ensure that the banker can not cheat, and then the player begins to bet. When the bet is reveal, the seller provides the random number to the game. The game verifies the random number by signature, generates three dice with the random number, and then automatically distributes the lottery. The player can verify the randomness and the fairness of the signature afterwards. 16 | 17 | ### Pseudo-code 18 | 19 | ``` 20 | If (signature = = sha256 (random[32]) { 21 | Stock 1 = (random[0] + random[1] + random[2] + random[3] + random[4] + random[5]) % 6 + 1 22 | Stock 2 = (random[6] + random[7] + random[8] + random[9] + random[10] + random[11]) % 6 + 1 23 | Stock 3 = (random[12] + random[13] + random[14] + random[15] + random[16] + random[17]) % 6 + 1 24 | } else { 25 | Verify, however, the game is wrong. 26 | } 27 | 28 | ``` 29 | 30 | ### Example 31 | Player understanding algorithm needs some basic knowledge of C language, and the values are all hexadecimal. 32 | Before the game is reveal, players can get the signature that the banker shown. 33 | `763f42ad937c1a268a17dfbdbb3b8e8bce12bc7cef5ac94f3ab3110ee78f52ca` 34 | At the end of the game, the banker reveal the hash value (random number) corresponding to the signature, which is as follows: 35 | `C6793186e4a0c748118a5070faf7a4ffdd07ea9d07d9f6ca25c4d59b88c6e58a` 36 | The above formula can be applied to calculate. 37 | 38 | ``` 39 | Commitment = 763f42ad937c1a268a17dfbdbb3b8e8bce12bc7cef5ac94f3ab3110ee78f52ca 40 | Source = c6793186e4a0c748118a5070faf7a4ffdd07ea9d07d9f6ca25c4d59b88c6e58a 41 | If (commitment = = sha256 (source)) { 42 | 3 = (C6 + 79 + 31 + 86 + E4 + A0)% 6 + 1 43 | 1 = (C7 + 48 + 11 + 8A + 50 + 70)% 6 + 1 44 | 5 = (FA + F7 + A4 + FF + DD + 07)% 6 + 1 45 | } 46 | 47 | ``` 48 | 3, 1, 5 is the result of the lottery. 49 | 50 | ### Third party verification 51 | 52 | A few public information can be passed on any third party website, such as: 53 | [https://bloks.io/](https://bloks.io/). 54 | 55 | The signature can be inquired before the lottery. 56 | 57 | Search - banker name - > Account Transactions - > Contract - > Tables - > Step 2 - Select Table - > game - > Load Table - > current game number - > commitment 58 | 59 | The original price is open after the lottery. 60 | 61 | Search - banker name - > Account Transactions - > Contract - > Tables - > Step 2 - Select Table - > game - > Load Table - > current game number - > source 62 | 63 | Calculate sha256, take the Linux operating system as an example. Note that the calculation of sha256 is a plastic number instead of a string. 64 | 65 | ```bash 66 | >> echo -n 'c6793186e4a0c748118a5070faf7a4ffdd07ea9d07d9f6ca25c4d59b88c6e58a'x xd-r-p | sha256sum-b | awk'{print $1}'; 67 | 68 | >> 763f42ad937c1a268a17dfbdbb3b8e8bce12bc7cef5ac94f3ab3110ee78f52ca 69 | ``` -------------------------------------------------------------------------------- /library.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef DEBUG 4 | 5 | #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) 6 | 7 | #define logger_info(...) \ 8 | { \ 9 | int time = now(); \ 10 | int hour = (time/3600)%24; \ 11 | time = time%3600; \ 12 | int min = time/60; \ 13 | time = time%60; \ 14 | int sec = time; \ 15 | print(hour, ":", min, ":", sec); \ 16 | print(" ", __FILENAME__, ":", __LINE__, " (Func:", __FUNCTION__, ") "); \ 17 | print(__VA_ARGS__, " ||| "); \ 18 | } 19 | #else 20 | 21 | #define logger_info(...){} 22 | 23 | #endif 24 | 25 | 26 | 27 | bool isdecnum(const std::string data) 28 | { 29 | for(size_t i=0; i= 201809140001, "id is too small"); 7 | eosio_assert(id <= 301809140001, "id is too big"); 8 | 9 | // 需要合约账号的权限 10 | require_auth( _self ); 11 | 12 | // 判断最后一个游戏 是否 在进行中 13 | if (games.begin() != games.end()) { 14 | auto game_ritr = games.rbegin(); 15 | logger_info("game_ritr->id:", game_ritr->id); 16 | eosio_assert(game_ritr->game_state != 0, "some game is going"); 17 | eosio_assert(game_ritr->id < id, "has game_id bigger than id"); 18 | } 19 | 20 | // 创建一个新游戏对象 21 | games.emplace(_self, [&](auto& new_game){ 22 | // 这里要注意类型,要有一个数字是uint_64的类型才行 23 | new_game.id = id; 24 | new_game.create_time = eosio::time_point_sec(now()); 25 | new_game.update_time = eosio::time_point_sec(now()); 26 | new_game.ttl = 80; 27 | new_game.commitment = commitment; 28 | logger_info("new_game.id:", new_game.id); 29 | }); 30 | } 31 | 32 | // 开奖接口 33 | void sicbo::reveal(const uint64_t gameid, const checksum256& source) { 34 | eosio_assert(gameid > 0, "gameid is not valid"); 35 | logger_info("gameid:", gameid) 36 | // 需要合约账号的权限 37 | require_auth( _self ); 38 | // 判断gameid是否存在 39 | auto game = games.get(gameid); 40 | eosio_assert(gameid == game.id, "gameid is not valid"); 41 | // 判断游戏是否在进行中 42 | eosio_assert(0 == game.game_state, "game_state is not valid"); 43 | 44 | logger_info("assert_sha256 start") 45 | // 判断签名是否一致 46 | char *c_src = (char *) &source; 47 | assert_sha256(c_src, sizeof(source), &game.commitment); 48 | logger_info("assert_sha256 success") 49 | 50 | // ++++++++++ 开奖逻辑 ++++++++++++++++ 51 | // 生成随机数 52 | int num1 = (int)(source.hash[0] + source.hash[1] + source.hash[2] + source.hash[3] + source.hash[4] + source.hash[5]) % 6 + 1; 53 | int num2 = (int)(source.hash[6] + source.hash[7] + source.hash[8] + source.hash[9] + source.hash[10] + source.hash[11]) % 6 + 1; 54 | int num3 = (int)(source.hash[12] + source.hash[13] + source.hash[14] + source.hash[15] + source.hash[16] + source.hash[17]) % 6 + 1; 55 | logger_info("1th: ", num1, ", 2th: ", num2, ", 3th: ", num3) 56 | 57 | // 修改游戏表 58 | games.modify(game, 0, [&](auto& game2) { 59 | game2.num1 = num1; 60 | game2.num2 = num2; 61 | game2.num3 = num3; 62 | game2.source = source; 63 | game2.game_state = 1; 64 | game2.update_time = eosio::time_point_sec(now()); 65 | }); 66 | 67 | // 计算中奖结果 68 | MAP_RESULT result = this->_getWinsMap(num1, num2, num3); 69 | 70 | // 修改下注表 71 | auto idx = offers.template get_index(); 72 | logger_info("find gameid:", gameid) 73 | auto offer_iter = idx.find(gameid); 74 | 75 | // 遍历所有的数据,修改赌注结果 76 | int i = 0; 77 | while (offer_iter != idx.end()) { 78 | if (offer_iter->result != 0) { 79 | offer_iter++; 80 | continue; 81 | } 82 | 83 | // 修改赌注结果 84 | offers.modify(*offer_iter, 0, [&](auto& offer){ 85 | if (result[offer_iter->offer_type]) { 86 | // 胜利 87 | offer.result = 1; 88 | } else { 89 | // 失败 90 | offer.result = 2; 91 | } 92 | offer.update_time = eosio::time_point_sec(now()); 93 | }); 94 | offer_iter++; 95 | } 96 | 97 | // 设置开奖完毕 98 | games.modify(game, 0, [&](auto& game2) { 99 | game2.game_state = 2; 100 | game2.update_time = eosio::time_point_sec(now()); 101 | }); 102 | } 103 | 104 | // 通过结果计算所有下注类型是否胜利 105 | MAP_RESULT sicbo::_getWinsMap(const uint8_t num1, const uint8_t num2, const uint8_t num3) { 106 | MAP_RESULT map; 107 | int sum = num1 + num2 + num3; 108 | 109 | if (num1 == num2 && num1 == num3) { 110 | // 判断围骰的情况 111 | map[num1 * 100 + num2 * 10 + num3] = true; 112 | // 只要是三个数就算 113 | map[three_n] = true; 114 | } else { 115 | // 判断大小 116 | if (sum >= 4 && sum <= 10) { 117 | map[small] = true; 118 | } else if (sum >= 11 && sum <= 17) { 119 | map[big] = true; 120 | } 121 | 122 | // 判断单双 123 | if (sum % 2) { 124 | map[odd] = true; 125 | } else { 126 | map[even] = true; 127 | } 128 | } 129 | 130 | // 判断点数总和 131 | if (sum >= 4 && sum <= 17) { 132 | map[sum] = true; 133 | } 134 | 135 | // 设置单骰 136 | map[num1 * 100] = true; 137 | map[num2 * 100] = true; 138 | map[num3 * 100] = true; 139 | 140 | // 设置双骰子 141 | int double_num = 0; 142 | if (num1 == num2) { 143 | double_num = num1; 144 | } else if (num2 == num3) { 145 | double_num = num2; 146 | } else if (num1 == num3) { 147 | double_num = num1; 148 | } 149 | 150 | if (double_num > 0) { 151 | map[double_num * 100 + double_num * 10] = true; 152 | } 153 | 154 | return map; 155 | } 156 | 157 | 158 | asset sicbo::str2eos(const std::string eosnum) 159 | { 160 | asset result; 161 | 162 | result.amount = atoi(eosnum.c_str()); 163 | result.symbol = S(4, EOS); 164 | 165 | return result; 166 | } 167 | 168 | void sicbo::require_offertype(int sicboplay) 169 | { 170 | switch(sicboplay) 171 | { 172 | case small: 173 | case big: 174 | case odd: 175 | case even: 176 | case sum_4: 177 | case sum_5: 178 | case sum_6: 179 | case sum_7: 180 | case sum_8: 181 | case sum_9: 182 | case sum_10: 183 | case sum_11: 184 | case sum_12: 185 | case sum_13: 186 | case sum_14: 187 | case sum_15: 188 | case sum_16: 189 | case sum_17: 190 | case single_1: 191 | case single_2: 192 | case single_3: 193 | case single_4: 194 | case single_5: 195 | case single_6: 196 | case double_1: 197 | case double_2: 198 | case double_3: 199 | case double_4: 200 | case double_5: 201 | case double_6: 202 | case three_1: 203 | case three_2: 204 | case three_3: 205 | case three_4: 206 | case three_5: 207 | case three_6: 208 | case three_n: 209 | break; 210 | default: 211 | eosio_assert(0, "offertype error"); 212 | } 213 | 214 | return; 215 | } 216 | 217 | BET_RESULT sicbo::_split_extra(const std::string strlist, uint64_t* gameidptr) 218 | { 219 | std::string data = strlist; 220 | 221 | eosio_assert(data.length(), "offerbet is null"); 222 | 223 | #define SPLITONE(x) \ 224 | (x).substr(0, (x).find("|")); \ 225 | (x) = (x).erase(0, (x).find("|")+1); 226 | 227 | if (gameidptr) 228 | { 229 | *gameidptr = 0; 230 | 231 | if (data.find("|") != std::string::npos) 232 | { 233 | auto gameidstr = SPLITONE(data); 234 | eosio_assert(isdecnum(gameidstr), "gameid isn't decimal num"); 235 | 236 | *gameidptr = atoll(gameidstr.c_str()); 237 | } 238 | } 239 | 240 | BET_RESULT map; 241 | 242 | while(data.find("|") != std::string::npos) 243 | { 244 | auto eos = SPLITONE(data); 245 | auto play = SPLITONE(data); 246 | 247 | eosio_assert(play.length(), "betlist format error"); 248 | eosio_assert(isdecnum(eos), "eos isn't decimal num"); 249 | eosio_assert(isdecnum(play), "play isn't decimal num"); 250 | 251 | int key = atoi(play.c_str()); 252 | 253 | require_offertype(key); 254 | 255 | if (map.find(key) != map.end()) { 256 | map[key] += str2eos(eos); 257 | } else { 258 | map[key] = str2eos(eos); 259 | } 260 | } 261 | 262 | #undef SPLITONE 263 | 264 | return map; 265 | } 266 | 267 | -------------------------------------------------------------------------------- /sicbo.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using eosio::key256; 12 | using eosio::indexed_by; 13 | using eosio::const_mem_fun; 14 | using eosio::asset; 15 | using eosio::permission_level; 16 | using eosio::action; 17 | using eosio::print; 18 | using eosio::name; 19 | 20 | #define DEBUG 21 | typedef std::map MAP_RESULT; 22 | typedef std::map BET_RESULT; 23 | 24 | // 下注类型 25 | enum enum_offer_type { 26 | small = 0, 27 | big = 1, 28 | odd = 3, 29 | even = 2, 30 | 31 | sum_4 = 4, 32 | sum_5 = 5, 33 | sum_6 = 6, 34 | sum_7 = 7, 35 | sum_8 = 8, 36 | sum_9 = 9, 37 | sum_10 = 10, 38 | sum_11 = 11, 39 | sum_12 = 12, 40 | sum_13 = 13, 41 | sum_14 = 14, 42 | sum_15 = 15, 43 | sum_16 = 16, 44 | sum_17 = 17, 45 | 46 | single_1 = 100, 47 | single_2 = 200, 48 | single_3 = 300, 49 | single_4 = 400, 50 | single_5 = 500, 51 | single_6 = 600, 52 | 53 | double_1 = 110, 54 | double_2 = 220, 55 | double_3 = 330, 56 | double_4 = 440, 57 | double_5 = 550, 58 | double_6 = 660, 59 | 60 | three_1 = 111, 61 | three_2 = 222, 62 | three_3 = 333, 63 | three_4 = 444, 64 | three_5 = 555, 65 | three_6 = 666, 66 | three_n = 777, // 只要是三个数就算 67 | }; 68 | 69 | 70 | class sicbo : public eosio::contract { 71 | public: 72 | sicbo(account_name self):eosio::contract(self), 73 | offers(_self, _self), 74 | games(_self, _self) 75 | {} 76 | 77 | //@abi action 78 | void creategame(const uint64_t id, const checksum256& commitment); 79 | //@abi action 80 | void offerbet(const asset bet, const account_name player, const uint64_t gameid, const std::string& betlist); 81 | //@abi action 82 | void reveal(const uint64_t gameid, const checksum256& source); 83 | //@abi action 84 | void balance(const uint64_t gameid, const account_name player); 85 | //@abi action 86 | void cleargame(const uint64_t gameid); 87 | //@abi action 88 | void clearoffer(const uint64_t gameid); 89 | //@abi action 90 | void closegame(const uint64_t gameid); 91 | void transfer(account_name from, account_name to, const asset& quantity, const std::string& memo);//注意没有action 92 | 93 | private: 94 | // 赔率类型 95 | std::map wins_map = { 96 | { small, 2 }, 97 | { big, 2 }, 98 | { odd, 2 }, 99 | { even, 2 }, 100 | 101 | { sum_4, 60 }, 102 | { sum_5, 30 }, 103 | { sum_6, 17 }, 104 | { sum_7, 12 }, 105 | { sum_8, 8 }, 106 | { sum_9, 6 }, 107 | { sum_10, 6 }, 108 | { sum_11, 6 }, 109 | { sum_12, 6 }, 110 | { sum_13, 8 }, 111 | { sum_14, 12 }, 112 | { sum_15, 17 }, 113 | { sum_16, 30 }, 114 | { sum_17, 60 }, 115 | 116 | { single_1, 2 }, 117 | { single_2, 2 }, 118 | { single_3, 2 }, 119 | { single_4, 2 }, 120 | { single_5, 2 }, 121 | { single_6, 2 }, 122 | 123 | { double_1, 10 }, 124 | { double_2, 10 }, 125 | { double_3, 10 }, 126 | { double_4, 10 }, 127 | { double_5, 10 }, 128 | { double_6, 10 }, 129 | 130 | { three_1, 185 }, 131 | { three_2, 185 }, 132 | { three_3, 185 }, 133 | { three_4, 185 }, 134 | { three_5, 185 }, 135 | { three_6, 185 }, 136 | { three_n, 30 } 137 | }; 138 | 139 | //@abi table game i64 赌局表 140 | struct game { 141 | uint64_t id; // 赌局id,如:201809130001 142 | uint32_t ttl = 120; // 倒计时时间,默认2分钟 143 | uint8_t game_state = 0; // 状态:0:进行中, 1:开奖中, 2:已结束 144 | checksum256 source;// 开奖种子 145 | checksum256 commitment; // 随机数加密串 146 | uint8_t num1 = 0; // 第1个骰子数字 147 | uint8_t num2 = 0; // 第2个骰子数字 148 | uint8_t num3 = 0; // 第3个骰子数字 149 | eosio::time_point_sec create_time; // 创建时间 150 | eosio::time_point_sec update_time; // 更新时间 151 | uint64_t primary_key() const { return id; } 152 | EOSLIB_SERIALIZE( game, (id)(ttl)(game_state)(source)(commitment)(num1)(num2)(num3)(create_time)(update_time) ) 153 | }; 154 | 155 | //@abi table offer i64 赌注明细表 156 | struct offer { 157 | uint64_t id; // 下注id 158 | account_name player; // 用户名 159 | asset bet; // 赌注 160 | uint64_t gameid; // 赌局id,如:201809130001 161 | uint32_t offer_type; // 下注类型:1:大, 2:小 162 | uint8_t bet_odds = 2; // 下注赔率,默认:x2 163 | uint8_t result = 0; // 赌注结果:0:未开奖, 1:胜利, 2:失败 164 | uint8_t tranffer_state = 0; // 转账状态:0:未转账, 1:转账中, 2:转账成功, 3:转账失败 165 | eosio::time_point_sec create_time; // 创建时间 166 | eosio::time_point_sec update_time; // 更新时间 167 | 168 | uint64_t primary_key() const { return id; } 169 | uint64_t by_gameid() const { return gameid; } // 可以通过赌局id查询数据 170 | account_name by_account_name() const { return player; } // 可以通过用户名查询数据 171 | EOSLIB_SERIALIZE( offer, (id)(player)(bet)(gameid)(offer_type)(bet_odds)(result)(tranffer_state)(create_time)(update_time) ) 172 | }; 173 | 174 | // 创建一个多索引容器的游戏列表 175 | typedef eosio::multi_index< N(game), game> game_index; 176 | 177 | // // 创建一个多索引容器的赌注列表 178 | typedef eosio::multi_index< N(offer), offer, 179 | indexed_by< N(gameid), const_mem_fun >, 180 | indexed_by< N(player), const_mem_fun > 181 | > offer_index; 182 | // typedef eosio::multi_index< N(offer), offer> offer_index; 183 | 184 | 185 | game_index games; 186 | offer_index offers; 187 | 188 | // 通过结果计算所有下注类型是否胜利 189 | MAP_RESULT _getWinsMap(const uint8_t num1, const uint8_t num2, const uint8_t num3); 190 | // bool _changeState(auto offer_iter, const int tranffer_state); 191 | 192 | // 分割与验证多注 193 | BET_RESULT _split_extra(const std::string data, uint64_t* gameidptr=nullptr); //0: offerbet, 1: transfer 194 | asset str2eos(const std::string eosnum); 195 | void require_offertype(int sicboplay); 196 | }; 197 | 198 | //注意没有offerbet 199 | #define EOSIO_ABI_EX( TYPE, MEMBERS ) \ 200 | extern "C" { \ 201 | void apply(uint64_t receiver, uint64_t code, uint64_t action) { \ 202 | if (action == N(onerror)) { \ 203 | eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \ 204 | } \ 205 | auto self = receiver; \ 206 | if ((code==N(eosio.token) && action==N(transfer)) || (code==self && (action==N(creategame) || action==N(reveal) || action==N(balance) || action==N(cleargame) || action==N(clearoffer) || action==N(closegame))) ) { \ 207 | TYPE thiscontract( self ); \ 208 | switch( action ) { \ 209 | EOSIO_API( TYPE, MEMBERS ) \ 210 | } \ 211 | } \ 212 | } \ 213 | } 214 | 215 | EOSIO_ABI_EX(sicbo, (creategame)(reveal)(balance)(cleargame)(clearoffer)(closegame)(transfer)) 216 | --------------------------------------------------------------------------------