EOS dice移到1.8版本的修改彙總
1. CORE_SYMBOL 被去掉了,須要本身在文件中聲明
eg:api
1 uint64_t string_to_symbol_c(uint8_t precision, const char* str) { 2 uint32_t len = 0; 3 while (str[len]) ++len; 4 5 uint64_t result = 0; 6 // No validation is done at compile time 7 for (uint32_t i = 0; i < len; ++i) { 8 result |= (uint64_t(str[i]) << (8*(1+i))); 9 } 10 11 result |= uint64_t(precision); 12 return result; 13 } 14 15 #define CORE_SYMBOL string_to_symbol_c(4,"SYS")
2. account_name 替換成了 name 結構
3. 合約contract的聲明改爲了下面結構
contract( name receiver, name code, datastream<const char*> ds )
dice合約變爲:dice(name s, name code, eosio::datastream<const char*> ds):eosio::contract(s,code,ds)
4. 由於account_name變爲了name結構,多索引結構的初始化改成:
offers(_self, _self.value),
games(_self, _self.value),
global_dices(_self, _self.value),
accounts(_self, _self.value)
5. 宏N變爲了_n
eg:N(commitment) 改成 "commitment"_n
6. checksum256 改爲 capi_checksum256
7. key256 改爲 fixed_bytes<32>
8. find函數後面跟的name類型,須要添加.value,以供查找
9. modify函數三個參數中間的0,改爲_self帳戶或者相應的帳戶
10. EOSIO_ABI 改爲 EOSIO_DISPATCH
11. 添加相應的頭文件,修改成新的合約格式 [[eosio::action]],[[eosio::contract("dice")]],[[eosio::table]]等
12. 該合約不支持除了EOS的其餘資產,所以本身作了一點修改以支持測試的自定義資產,供本身測試
函數
完整修改代碼以下:測試
1 /** 2 * @file 3 * @copyright defined in eos/LICENSE.txt 4 */ 5 #include <utility> 6 #include <vector> 7 #include <string> 8 #include <eosiolib/eosio.hpp> 9 #include <eosiolib/time.hpp> 10 #include <eosiolib/asset.hpp> 11 #include <eosiolib/contract.hpp> 12 #include <eosiolib/crypto.h> 13 #include <eosiolib/fixed_bytes.hpp> 14 #include <eosiolib/symbol.hpp> 15 16 using eosio::fixed_bytes; 17 using eosio::indexed_by; 18 using eosio::const_mem_fun; 19 using eosio::asset; 20 using eosio::permission_level; 21 using eosio::action; 22 using eosio::print; 23 using eosio::name; 24 using eosio::symbol; 25 26 uint64_t string_to_symbol_c(uint8_t precision, const char* str) { 27 uint32_t len = 0; 28 while (str[len]) ++len; 29 30 uint64_t result = 0; 31 // No validation is done at compile time 32 for (uint32_t i = 0; i < len; ++i) { 33 result |= (uint64_t(str[i]) << (8*(1+i))); 34 } 35 36 result |= uint64_t(precision); 37 return result; 38 } 39 40 #define CORE_SYMBOL string_to_symbol_c(4,"SYS") 41 42 43 class [[eosio::contract("dice")]] dice : public eosio::contract { 44 public: 45 using contract::contract; 46 47 const uint32_t FIVE_MINUTES = 5*60; 48 49 dice(name s, name code, eosio::datastream<const char*> ds):eosio::contract(s,code,ds), 50 offers(_self, _self.value), 51 games(_self, _self.value), 52 global_dices(_self, _self.value), 53 accounts(_self, _self.value) 54 {} 55 56 [[eosio::action]] 57 void offerbet(const asset& bet, const name player, const capi_checksum256& commitment) { 58 59 //eosio_assert( bet.symbol == symbol(CORE_SYMBOL), "only core token allowed" ); 60 eosio_assert( bet.is_valid(), "invalid bet" ); 61 eosio_assert( bet.amount > 0, "must bet positive quantity" ); 62 63 eosio_assert( !has_offer( commitment ), "offer with this commitment already exist" ); 64 require_auth( player ); 65 66 auto cur_player_itr = accounts.find( player.value ); 67 eosio_assert(cur_player_itr != accounts.end(), "unknown account"); 68 69 // Store new offer 70 auto new_offer_itr = offers.emplace(_self, [&](auto& offer){ 71 offer.id = offers.available_primary_key(); 72 offer.bet = bet; 73 offer.owner = player; 74 offer.commitment = commitment; 75 offer.gameid = 0; 76 }); 77 78 // Try to find a matching bet 79 auto idx = offers.template get_index<"bet"_n>(); 80 auto matched_offer_itr = idx.lower_bound( (uint64_t)new_offer_itr->bet.amount ); 81 82 if( matched_offer_itr == idx.end() 83 || matched_offer_itr->bet != new_offer_itr->bet 84 || matched_offer_itr->owner == new_offer_itr->owner ) { 85 86 // No matching bet found, update player's account 87 accounts.modify( cur_player_itr, player, [&](auto& acnt) { 88 //eosio_assert( acnt.eos_balance >= bet, "insufficient balance" ); 89 //acnt.eos_balance -= bet; 90 for(auto iter = acnt.eos_balance.begin(); iter != acnt.eos_balance.end(); iter++){ 91 if(iter->symbol == bet.symbol){ 92 eosio_assert( (*iter) >= bet, "insufficient balance" ); 93 (*iter) -= bet; 94 print( "offerbet1 : ", asset{bet} ); 95 break; 96 } 97 } 98 acnt.open_offers++; 99 }); 100 101 } else { 102 // Create global game counter if not exists 103 auto gdice_itr = global_dices.begin(); 104 if( gdice_itr == global_dices.end() ) { 105 gdice_itr = global_dices.emplace(_self, [&](auto& gdice){ 106 gdice.nextgameid=0; 107 }); 108 } 109 110 // Increment global game counter 111 global_dices.modify(gdice_itr, _self, [&](auto& gdice){ 112 gdice.nextgameid++; 113 }); 114 115 // Create a new game 116 auto game_itr = games.emplace(_self, [&](auto& new_game){ 117 new_game.id = gdice_itr->nextgameid; 118 new_game.bet = new_offer_itr->bet; 119 new_game.deadline = eosio::time_point_sec(0); 120 121 new_game.player1.commitment = matched_offer_itr->commitment; 122 memset(&new_game.player1.reveal, 0, sizeof(capi_checksum256)); 123 124 new_game.player2.commitment = new_offer_itr->commitment; 125 memset(&new_game.player2.reveal, 0, sizeof(capi_checksum256)); 126 }); 127 128 // Update player's offers 129 idx.modify(matched_offer_itr, _self, [&](auto& offer){ 130 offer.bet.amount = 0; 131 offer.gameid = game_itr->id; 132 }); 133 134 offers.modify(new_offer_itr, _self, [&](auto& offer){ 135 offer.bet.amount = 0; 136 offer.gameid = game_itr->id; 137 }); 138 139 // Update player's accounts 140 accounts.modify( accounts.find( matched_offer_itr->owner.value ), matched_offer_itr->owner, [&](auto& acnt) { 141 acnt.open_offers--; 142 acnt.open_games++; 143 }); 144 145 accounts.modify( cur_player_itr, player, [&](auto& acnt) { 146 //eosio_assert( acnt.eos_balance >= bet, "insufficient balance" ); 147 // acnt.eos_balance -= bet; 148 for(auto iter = acnt.eos_balance.begin(); iter != acnt.eos_balance.end(); iter++){ 149 if(iter->symbol == bet.symbol){ 150 eosio_assert( (*iter) >= bet, "insufficient balance" ); 151 (*iter) -= bet; 152 print( "offerbet2 : ", asset{bet} ); 153 break; 154 } 155 } 156 acnt.open_games++; 157 }); 158 } 159 } 160 161 [[eosio::action]] 162 void canceloffer( const capi_checksum256& commitment ) { 163 164 auto idx = offers.template get_index<"commitment"_n>(); 165 auto offer_itr = idx.find( offer::get_commitment(commitment) ); 166 167 eosio_assert( offer_itr != idx.end(), "offer does not exists" ); 168 eosio_assert( offer_itr->gameid == 0, "unable to cancel offer" ); 169 require_auth( offer_itr->owner ); 170 171 auto acnt_itr = accounts.find(offer_itr->owner.value); 172 accounts.modify(acnt_itr, offer_itr->owner, [&](auto& acnt){ 173 acnt.open_offers--; 174 // acnt.eos_balance += offer_itr->bet; 175 176 for(auto iter = acnt.eos_balance.begin(); iter != acnt.eos_balance.end(); iter++){ 177 if(iter->symbol == offer_itr->bet.symbol){ 178 (*iter) += offer_itr->bet; 179 print( "canceloffer : ", asset{offer_itr->bet} ); 180 break; 181 } 182 } 183 }); 184 185 idx.erase(offer_itr); 186 } 187 188 [[eosio::action]] 189 void reveal( const capi_checksum256& commitment, const capi_checksum256& source ) { 190 191 assert_sha256( (char *)&source, sizeof(source), (const capi_checksum256 *)&commitment ); 192 193 auto idx = offers.template get_index<"commitment"_n>(); 194 auto curr_revealer_offer = idx.find( offer::get_commitment(commitment) ); 195 196 eosio_assert(curr_revealer_offer != idx.end(), "offer not found"); 197 eosio_assert(curr_revealer_offer->gameid > 0, "unable to reveal"); 198 199 auto game_itr = games.find( curr_revealer_offer->gameid ); 200 201 player curr_reveal = game_itr->player1; 202 player prev_reveal = game_itr->player2; 203 204 if( !is_equal(curr_reveal.commitment, commitment) ) { 205 std::swap(curr_reveal, prev_reveal); 206 } 207 208 eosio_assert( is_zero(curr_reveal.reveal) == true, "player already revealed"); 209 210 if( !is_zero(prev_reveal.reveal) ) { 211 212 capi_checksum256 result; 213 sha256( (char *)&game_itr->player1, sizeof(player)*2, &result); 214 215 auto prev_revealer_offer = idx.find( offer::get_commitment(prev_reveal.commitment) ); 216 217 int winner = result.hash[1] < result.hash[0] ? 0 : 1; 218 219 if( winner ) { 220 pay_and_clean(*game_itr, *curr_revealer_offer, *prev_revealer_offer); 221 } else { 222 pay_and_clean(*game_itr, *prev_revealer_offer, *curr_revealer_offer); 223 } 224 225 } else { 226 games.modify(game_itr, _self, [&](auto& game){ 227 228 if( is_equal(curr_reveal.commitment, game.player1.commitment) ) 229 game.player1.reveal = source; 230 else 231 game.player2.reveal = source; 232 233 game.deadline = eosio::time_point_sec(now() + FIVE_MINUTES); 234 }); 235 } 236 } 237 238 [[eosio::action]] 239 void claimexpired( const uint64_t gameid ) { 240 241 auto game_itr = games.find(gameid); 242 243 eosio_assert(game_itr != games.end(), "game not found"); 244 eosio_assert(game_itr->deadline != eosio::time_point_sec(0) && eosio::time_point_sec(now()) > game_itr->deadline, "game not expired"); 245 246 auto idx = offers.template get_index<"commitment"_n>(); 247 auto player1_offer = idx.find( offer::get_commitment(game_itr->player1.commitment) ); 248 auto player2_offer = idx.find( offer::get_commitment(game_itr->player2.commitment) ); 249 250 if( !is_zero(game_itr->player1.reveal) ) { 251 eosio_assert( is_zero(game_itr->player2.reveal), "game error"); 252 pay_and_clean(*game_itr, *player1_offer, *player2_offer); 253 } else { 254 eosio_assert( is_zero(game_itr->player1.reveal), "game error"); 255 pay_and_clean(*game_itr, *player2_offer, *player1_offer); 256 } 257 258 } 259 260 [[eosio::action]] 261 void deposit( const name from, const asset& quantity ) { 262 263 eosio_assert( quantity.is_valid(), "invalid quantity" ); 264 eosio_assert( quantity.amount > 0, "must deposit positive quantity" ); 265 266 auto itr = accounts.find(from.value); 267 if( itr == accounts.end() ) { 268 itr = accounts.emplace(_self, [&](auto& acnt){ 269 acnt.owner = from; 270 }); 271 } 272 273 action( 274 permission_level{ from, "active"_n }, 275 "eosio.token"_n, "transfer"_n, 276 std::make_tuple(from, _self, quantity, std::string("")) 277 ).send(); 278 279 accounts.modify( itr, from, [&]( auto& acnt ) { 280 //acnt.eos_balance += quantity; 281 bool isfound = false; 282 for(auto iter = acnt.eos_balance.begin(); iter != acnt.eos_balance.end(); iter++){ 283 if(iter->symbol == quantity.symbol){ 284 (*iter) += quantity; 285 isfound = true; 286 print( "deposit more : ", asset{quantity} ); 287 break; 288 } 289 } 290 if(!isfound){ 291 acnt.eos_balance.emplace_back(quantity); 292 print( "deposit add : ", asset{quantity} ); 293 } 294 }); 295 296 } 297 298 [[eosio::action]] 299 void withdraw( const name to, const asset& quantity ) { 300 require_auth( to ); 301 302 eosio_assert( quantity.is_valid(), "invalid quantity" ); 303 eosio_assert( quantity.amount > 0, "must withdraw positive quantity" ); 304 305 auto itr = accounts.find( to.value ); 306 eosio_assert(itr != accounts.end(), "unknown account"); 307 308 accounts.modify( itr, to, [&]( auto& acnt ) { 309 // eosio_assert( acnt.eos_balance >= quantity, "insufficient balance" ); 310 // acnt.eos_balance -= quantity; 311 312 for(auto iter = acnt.eos_balance.begin(); iter != acnt.eos_balance.end(); iter++){ 313 if(iter->symbol == quantity.symbol){ 314 eosio_assert( (*iter) >= quantity, "insufficient balance" ); 315 (*iter) -= quantity; 316 print( "withdraw : ", asset{quantity} ); 317 break; 318 } 319 } 320 }); 321 322 action( 323 permission_level{ _self, "active"_n }, 324 "eosio.token"_n, "transfer"_n, 325 std::make_tuple(_self, to, quantity, std::string("")) 326 ).send(); 327 328 if( itr->is_empty() ) { 329 accounts.erase(itr); 330 } 331 } 332 333 private: 334 //@abi table offer i64 335 struct [[eosio::table]] offer { 336 uint64_t id; 337 name owner; 338 asset bet; 339 capi_checksum256 commitment; 340 uint64_t gameid = 0; 341 342 uint64_t primary_key()const { return id; } 343 344 uint64_t by_bet()const { return (uint64_t)bet.amount; } 345 346 fixed_bytes<32> by_commitment()const { return get_commitment(commitment); } 347 348 static fixed_bytes<32> get_commitment(const capi_checksum256& commitment) { 349 const uint64_t *p64 = reinterpret_cast<const uint64_t *>(&commitment); 350 return fixed_bytes<32>::make_from_word_sequence<uint64_t>(p64[0], p64[1], p64[2], p64[3]); 351 } 352 353 EOSLIB_SERIALIZE( offer, (id)(owner)(bet)(commitment)(gameid) ) 354 }; 355 356 // typedef eosio::multi_index< N(offer), offer, 357 // indexed_by< N(bet), const_mem_fun<offer, uint64_t, &offer::by_bet > >, 358 // indexed_by< N(commitment), const_mem_fun<offer, fixed_bytes<32>, &offer::by_commitment> > 359 // > offer_index; 360 361 typedef eosio::multi_index< "offers"_n, offer, 362 indexed_by< "bet"_n, const_mem_fun<offer, uint64_t, &offer::by_bet > >, 363 indexed_by< "commitment"_n, const_mem_fun<offer, fixed_bytes<32>, &offer::by_commitment> > 364 > offer_index_table; 365 366 367 368 struct [[eosio::table]] player { 369 capi_checksum256 commitment; 370 capi_checksum256 reveal; 371 372 EOSLIB_SERIALIZE( player, (commitment)(reveal) ) 373 }; 374 375 //@abi table game i64 376 struct [[eosio::table]] game { 377 uint64_t id; 378 asset bet; 379 eosio::time_point_sec deadline; 380 player player1; 381 player player2; 382 383 uint64_t primary_key()const { return id; } 384 385 EOSLIB_SERIALIZE( game, (id)(bet)(deadline)(player1)(player2) ) 386 }; 387 388 // typedef eosio::multi_index< N(game), game> game_index; 389 typedef eosio::multi_index< "games"_n, game> game_index_table; 390 391 //@abi table global i64 392 struct [[eosio::table]] global_dice { 393 uint64_t id = 0; 394 uint64_t nextgameid = 0; 395 396 uint64_t primary_key()const { return id; } 397 398 EOSLIB_SERIALIZE( global_dice, (id)(nextgameid) ) 399 }; 400 401 // typedef eosio::multi_index< N(global), global_dice> global_dice_index; 402 typedef eosio::multi_index< "globals"_n, global_dice> global_dice_index_table; 403 404 //@abi table account i64 405 struct [[eosio::table]] account { 406 account( name o = name() ):owner(o){} 407 408 name owner; 409 // asset eos_balance; 410 std::vector<asset> eos_balance; 411 uint32_t open_offers = 0; 412 uint32_t open_games = 0; 413 414 // bool is_empty()const { return !( eos_balance.amount | open_offers | open_games ); } 415 bool is_empty()const { return !( !eos_balance.empty() | open_offers | open_games ); } 416 417 uint64_t primary_key()const { return owner.value; } 418 419 EOSLIB_SERIALIZE( account, (owner)(eos_balance)(open_offers)(open_games) ) 420 }; 421 422 // typedef eosio::multi_index< N(account), account> account_index; 423 typedef eosio::multi_index< "accounts"_n, account> account_index_table; 424 425 offer_index_table offers; 426 game_index_table games; 427 global_dice_index_table global_dices; 428 account_index_table accounts; 429 430 bool has_offer( const capi_checksum256& commitment )const { 431 auto idx = offers.template get_index<"commitment"_n>(); 432 auto itr = idx.find( offer::get_commitment(commitment) ); 433 return itr != idx.end(); 434 } 435 436 bool is_equal(const capi_checksum256& a, const capi_checksum256& b)const { 437 return memcmp((void *)&a, (const void *)&b, sizeof(capi_checksum256)) == 0; 438 } 439 440 bool is_zero(const capi_checksum256& a)const { 441 const uint64_t *p64 = reinterpret_cast<const uint64_t*>(&a); 442 return p64[0] == 0 && p64[1] == 0 && p64[2] == 0 && p64[3] == 0; 443 } 444 445 void pay_and_clean(const game& g, const offer& winner_offer, 446 const offer& loser_offer) { 447 448 // Update winner account balance and game count 449 auto winner_account = accounts.find(winner_offer.owner.value); 450 accounts.modify( winner_account, winner_offer.owner, [&]( auto& acnt ) { 451 for(auto iter = acnt.eos_balance.begin(); iter != acnt.eos_balance.end(); iter++){ 452 if(iter->symbol == g.bet.symbol){ 453 (*iter) += 2*g.bet; 454 print( "pay_and_clean : ", asset{2*g.bet} ); 455 break; 456 } 457 } 458 // acnt.eos_balance += 2*g.bet; 459 acnt.open_games--; 460 }); 461 462 // Update losser account game count 463 auto loser_account = accounts.find(loser_offer.owner.value); 464 accounts.modify( loser_account, loser_offer.owner, [&]( auto& acnt ) { 465 acnt.open_games--; 466 }); 467 468 if( loser_account->is_empty() ) { 469 accounts.erase(loser_account); 470 } 471 472 games.erase(g); 473 offers.erase(winner_offer); 474 offers.erase(loser_offer); 475 } 476 }; 477 478 EOSIO_DISPATCH( dice, (offerbet)(canceloffer)(reveal)(claimexpired)(deposit)(withdraw) )