Using steemmonsters python library for winning Gold Card in contest

in utopian-io •  6 years ago  (edited)

Repository

https://gist.github.com/spiiin/d6b1ec3dca17fbbedf6c03856cb48634

preview_1.png

What Will I Learn?

In brief, write details of what the user is going to learn in a bullet list.

  • You will learn how to use steemmonster library for retrive information about cards
  • You will learn how to use some functions from python itertools/hashlib standard libraries
  • And you will learn that a problem may have a non-standard solution

Requirements

  • Basic understand of python

Difficulty

  • Basic

Tutorial Contents

You must know about Steem Monsters, a decentralized, digital collectible trading card game built on the Steem blockchain. I buy started pack a long time ago but started to play just several days ago. There is much information about this game and some players creating contests with cards as prizes.

I think contests and prizes are cool. For example, there is one of the contest from @teller-of-tales (it's ended now, I waited for it to post the tutorial and not ruin contest).

The author wants to create a lottery - he chooses three random gold cards from his collection, and encrypt card names to fix his choice to the participants. I think, that a lottery is cool, but a programming puzzle will be even better, so I try to check if I can collect some info about cards.

At first, I need to collect all card names. There are currently 97 cards in game (74 beta, 4 promo, and 19 rewards cards)
all_cards1.png

It will take a long time to do so manually - card names only printed on cards as images in Steem Monsters' Market section, so it even not can be copied as text.

I started to search card list, but there is no available. I only found this article, but it is incomplete - only 11 water cards listed there. Next I found nice steemmonsters python library from @holger80.
It can be installed with standard python pip installer:

pip install steemmonsters

Library has shell-like interface, but we will use it as python module for writing our script.

We can get details for all cards with this script:

#import stemmonsters library
import steemmonsters.api
#create api class
api = steemmonsters.api.Api()
#request to api - get info about cards
cards_details = api.get_card_details()

#debug print of card info
for cd in cards_details:
        print(cd)

Example of output (python dictionary):

{'id': 1, 'name': 'Goblin Shaman', 'color': 'Red', 'type': 'Monster', 'sub_type': None, 'rarity': 1, 'drop_rate': 80, 'stats': {'mana': [3, 3, 3, 3, 3, 3, 3, 3, 3, 3], 'attack': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'ranged': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'magic': [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 'armor': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'health': [4, 4, 3, 4, 3, 3, 3, 4, 5, 6], 'speed': [2, 3, 2, 2, 2, 3, 4, 4, 4, 4], 'abilities': [['Weaken'], [], [], [], ['Slow'], [], [], [], [], []]}, 'is_starter': False, 'editions': '0,1', 'created_block_num': None, 'last_update_tx': None}

The name field is exactly what are we want.

Next, as we can read in description of the contest, author mention, that he encrypt one rare card and two common. So, we can filter common and rare card names:

#filter for common and rare cards  
common = [(c.get("name")) for c in cards_details if c.get("rarity")==1]
rare = [(c.get("name")) for c in cards_details if c.get("rarity")==2]
print("Card names recieved. Total: %d common cards and %d rare cards)"%(len(common), len(rare)))

This lines will print:

Card names recieved. Total: 33 common cards and 29 rare cards

At this point, I look on hash string, posted by author:
hash_1.png
And think: if it is sha256 hash of the string "Card Name1, Card Name2, Card Name3" how many combinations I need to check for found string, that will match to hash?

sha256 is standard function for hashing, it used in bitcoin, steem and other crypto key-pairs generation.

It is not so many for bruteforce with computer.
Card Name1 can be replaced with 62 card names (any common and rare card).
Card Name2 can be replaced with 61 card names (any, except of Card Name1, it must be different card)
Card Name3 can be replaced with 60 card names (any, except of Card Name1 and Card Name2).
So, total we have 62 x 61 x 60 = 226920 permutations.

We can implement brute force search for all the permutations with this python code:

from itertools import permutations
import hashlib

#fill list of card names
cards_names = common + rare

#convert string to sha245 and check if hash is equal to answer
def checkHash(myStr):
    m = hashlib.sha256()
    m.update(myStr.encode('utf-8'))
    return m.hexdigest() == "8iu7O23u9SRnkdjckjh29cZ3E9pOpCXJhwfdQjCM3bohrSfbo9541122GnXI9w8J"
    
#generate all permutations for card_names    
all_permuations = permutations(cards_names, 3)

for i, p in enumerate(all_permuations):
    #join list elements to string with ", " as separator
    s = ", ".join(p)
    #print debug results for every 1000th value to view progress
    if i % 1000 == 0:
       print(i)
       print(s)
    #if we found answer, print it and break search
    if (checkHash(s)):
        print(s)
        break

It needs less than 1 second to check all variants.

But, it not found answer :(
I tried other variants:

CardName1, CardName2, CardName3 (with no spaces in card names)
Card Name1 Card Name 2 Card Name3 (with spaces and other symbols as word separator)
CARD NAME1, CARD NAME2, CARD NAME3 (with upper and lowercase...)
Card Name1\nCard Name2\nCard Name3 (with new lines in windows and unix style...)
and others

When you solving real tasks, not challenge, it's normal to not found obvious solution.
It's possible, that author of the contests missprint on card name, or just used "salt" - some additional string, that will change all hash. For example, hash of string
"My cards are: Card Name1, Card Name2, Card Name 3" will be totally different.

Next, I re-read the post and see this:
ans_3.png
It's nick of author in steem-monsters discord channel.
I sent message to him with a hint's request, but he didn't answer me.

Looking ahead, author encrypt string without error, but he used not SHA256, but AES encryption algorithm with additional protection key, so brute force wouldn't work anyway.

But nickname of the author on discord (@nomadic-maverick) also is his steem/steem monsters nickname! IT IS A HINT! All cards stored in blockchain and we can see, what cards someone has.

Gold cards are really rare, so player can't has many of them (and it's extra cool for the author of the contest to give away as many as 3 cards!)

And the last piece of code to print all common and rare gold cards for certain player:

#print card name and it's rarity
def getCardInfo(p):
    #search, if card_detail_id for our card is found is cards_details dictionary
    for cd in cards_details:
        if cd.get("id") == p.get("card_detail_id"):
            #if card_detail_id matches, return card name and rarity
            return (cd.get("name"), cd.get("rarity"))
        
#read full card collection for user
pd = api.get_collection("nomadic-maverick")
for p in pd.get("cards"):
    #if we found gold card, print it's name and rarity
    if p.get("gold") == True:
        print(getCardInfo(p))

Output:

('Rexxie', 1)
('Silvershield Warrior', 1)
('Minotaur Warrior', 1)
('Clay Golem', 2)
('Silvershield Knight', 1)
('Highland Archer', 1)
('Divine Healer', 1)
('Rusty Android', 1)
('Rusty Android', 1)
('Grumpy Dwarf', 1)
('Flame Imp', 2)

I didn't format output, first element it tuple is card name, and second element is rarity code - 1 is common card, and 2 is rare card. It's only 3 rare cards in player's collection, so now you have 33% chance to win (or even 66% if you resteem contest's post).
I used my test account @polugram (created with help of @emrebeyler for my friend and not used before) for check my guess, and win this card!
medusa1.png

Later I found other way to check collection of cards for other player - steempeak app already provide interface for it:
https://monsters.steempeak.com/@nomadic-maverick/collection

Proof of Work Done

https://gist.github.com/spiiin/d6b1ec3dca17fbbedf6c03856cb48634
Gold Medusa in my collection:
https://monsters.steempeak.com/@pinkwonder/collection
update:
Card goes to @steemtamer
https://monsters.steempeak.com/@monsterstamer/collection
because I have no water summoner yet =)

You can contact me on discord:
spiiin#1717

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Thank you for your contribution.

  • I liked you waiting till the contest is over and not ruining it for anyone.
  • Trying to come up with ways to guess and find hidden info and testing a system's security is nice, as long as not used with malicious intentions.
  • Your text has a lot of English and grammar mistakes, please consider improving on those
  • You also left out many of the original questions in the template. Those are considered as guidance and should not be kept in the content

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Chat with us on Discord.

[utopian-moderator]

Thanks for the review. It's my worst contribution, and I want to improve the quality of next contribution.

Your text has a lot of English and grammar mistakes, please consider improving on those

I know that my English is poor. Can you give me feedback - is the meaning of the text is clear? I.e. do I need just a proofreader or translator?

well whichever is more available to you, a proof reader or a translator, as long as they are qualified with quality English.

Thank you for your review, @mcfarhat! Keep up the good work!

Congratulations @pinkwonder! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You published more than 30 posts. Your next target is to reach 40 posts.

Click here to view your Board
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Support SteemitBoard's project! Vote for its witness and get one more award!

Hi @pinkwonder!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @pinkwonder!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Congratulations! This post has been upvoted from the communal account, @minnowsupport, by spiiin from the Minnow Support Project. It's a witness project run by aggroed, ausbitbank, teamsteem, someguy123, neoxian, followbtcnews, and netuoso. The goal is to help Steemit grow by supporting Minnows. Please find us at the Peace, Abundance, and Liberty Network (PALnet) Discord Channel. It's a completely public and open space to all members of the Steemit community who voluntarily choose to be there.

If you would like to delegate to the Minnow Support Project you can do so by clicking on the following links: 50SP, 100SP, 250SP, 500SP, 1000SP, 5000SP.
Be sure to leave at least 50SP undelegated on your account.