Building A Steem Bot Part 3: The Hackiest Curator Ever and A Steemit Transaction

in #steem-python6 years ago (edited)

This is a part of a series and will work to build upon the last part. Part 1 is here and Part 2 is here. This post expects a very basic understanding of python syntax. This is going to introduce concepts of the steem-python library slowly at first to allow people to understand how to program their own stuff.


Truly Hacky Methodology

What I mean by that is that the way I have this tutorial laid out is doing to show a way to follow the voting of someone else but it is super super hacky. Like, as in, it works as it should but I would not suggest this for long term bots. Why I am going to show this to you is two-fold, first you get to see how the blockchain works a little bit. And second, it will introduce JSON (JavaScript Object Notation) to you for later tutorials.


JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

Taken from the JSON website.

So why am I going to introduce JSON to you? So the basic idea of a blockchain is to be a ledger that is formed through consensus. Basically it would have something that looks like this:

{Public key of the wallet funds are transfered from} {Public key of wallet funds are transfered to} {amount transfered} {sign}

Now remember that is in the most basic form in idea, not practice. Steem, however, holds a lot more information than just amount of steem in each wallet. It contains posts, it contains transfers, it contains votes... etc. In a very simplistic blockchain you could have it look as above but steem isn't that simple. So instead, here is what an average transaction on the steem blockchain looks like:

[
    [
    71941,
         {
            'trx_id': '425710bd604afa5fc87ecbcda98f568154dfc24f', 
            'block': 19497177,
            'trx_in_block': 45, 
            'op_in_trx': 0,
            'virtual_op': 0, 
            'timestamp': '2018-02-01T19:41:48', 
            'op': 
            [
                'vote', 
                {
                    'voter': 'jackhistoria',
                    'author': 'ned', 
                    'permlink': 're-benjojo-re-ned-re-dan-proof-of-good-governance-20180103t014600764z',
                    'weight': 10000
                }
            ]
        }
    ]
]

I will say right now, that it only looks like that because I added spaces to make it easier to read. A transaction actually usually looks like this:

[[71941, {'trx_id': '425710bd604afa5fc87ecbcda98f568154dfc24f', 'block': 19497177, 'trx_in_block': 45, 'op_in_trx': 0, 'virtual_op': 0, 'timestamp': '2018-02-01T19:41:48', 'op': ['vote', {'voter': 'jackhistoria', 'author': 'ned', 'permlink': 're-benjojo-re-ned-re-dan-proof-of-good-governance-20180103t014600764z', 'weight': 10000}]}]]

So lets break down this transaction an tell you what it is and how we can use this to make a very hacky curation bot, without importing the JSON module, then after we do it the hacky way I will import the JSON module and show you how much easier life becomes.


Breaking Down The File

So for right now we are going to completely ignore that first number because it doesn't matter at all. We are skipping to this block of information:
'trx_id': '425710bd604afa5fc87ecbcda98f568154dfc24f', 
'block': 19497177,
'trx_in_block': 45, 
'op_in_trx': 0,
'virtual_op': 0, 
'timestamp': '2018-02-01T19:41:48', 

Although boring and useless for most users, it might be interesting for some so I will include it. trx_id is transaction id and the big string of seemingly random numbers and letters is the actual id. So JSON has a notation of:

[label] : [data]

block is just what block number this transaction was in.trx_in_block is the number of transactions in that block. op_in_trx isnumber of operations in the transaction but I think it is that number minus 1, I might be wrong though. And timestamp is when it was done. Virtual op is something that I will not cover, yet.

Okay so now you have the basic idea on reading the basic notation of a JSON file I will, in a sentence, tell you what this entire thing is saying:

In the block '19497177' we have a transaction labeled '425710bd604afa5fc87ecbcda98f568154dfc24f'
 that contains the operation to vote on the post by 'ned' with the link 
're-benjojo-re-ned-re-dan-proof-of-good-governance-20180103t014600764z' at 100%. 
The voter has the username 'jackhistoria' so update account information.

Pretty simple right? Yeah. So how can we use this to follow someones vote? Simple, we download an accounts history using a build in method to the steem class: Steem().get_account_history(account='') and lets say we want to follow @ned then we can simply create a script like the following to always get his latest transaction:

from steem import Steem
from steem.post import Post
vw = float(input("Enter voting weight: "))
account = str(input("Enter Your Account: "))
key = str(input("Enter Posting Key: "))
s = Steem(keys=key)
while True:
    action = str(s.get_account_history('ned', index_from=-1, limit=0))
    if "'op': ['vote', {'voter': 'ned'," in action:
        try:
            starta = action.find("'author': '") + len("'author': '")
            enda = action.find("', 'permlink':")
            author = action[starta:enda]
            startp = action.find("', 'permlink': '") + len("', 'permlink': '")
            endp = action.find("', 'weight':")
            permalink = action[startp:endp]
            pst = "@" + author + "/" + permalink
            post = Post(pst, s)
            post.upvote(vw, acount)
        except:
            pass


Before you run this program, realize that it is going to be very computationally heavy. It is going to run and download that transaction multiple times per second and will cost a lot if you have limited internet. So to save bandwidth and and time we will use some of the blockchains limitations to our benefit. We will import the time class and inside of our loop add a call to it that looks like this:
time.sleep(3)

since for most general applications, you are not supposed to be able to vote more than once per block which is minted every 3 seconds.Remember, this is a bad script that technically works, doesn't mean it is the best. It does have some potential uses though.



Source
So I know what you are all thinking, "Now show us the easier way to do this!" to which I say this is the easy way, it's just not the most efficient or best. You see, no matter how you do it, yo are pretty much going to have to have something handling the JSON operations and my method above, though flawed, works. My method of getting the username and permalink out of a JSON file will work no matter how you supply the JSON file but there are better ways, kind of. So instead of going too much into JSON's and how to interact with them, I scripted a quick little tool that can be used to look at the transactions of a specific account where you enter the name and the number to look at. It then prints it out, in an easy to read form, so you can look at the transaction yourself without it being all clogged up.
transacctions.py
from steem import Steem

s = Steem()
follow = str(input("Enter who to follow: "))
nactions = int(input("Enter number of transactions to look at: "))-1
action = s.get_account_history(follow, index_from=-1, limit=nactions)

def nl(nt):
    print('\n', end='')
    for i in range(0,nt):
        print("\t", end='')

def pnjson(js):
    ntabs = 0
    for i in range(0, len(js)):
        if js[i]=='{':
            print(js[i], end='')
            ntabs = ntabs+1
            nl(ntabs)
        elif js[i]=='[':
            print(js[i], end='')
            ntabs = ntabs+1
            nl(ntabs)
        elif js[i]==']':
            ntabs = ntabs-1
            nl(ntabs)
            print(js[i], end='')
        elif js[i]=='}':
            ntabs = ntabs-1
            nl(ntabs)
            print(js[i], end='')
        elif js[i]==',':
            print(js[i], end='')
            nl(ntabs)
        else:
            print(js[i], end='')

pnjson(str(action))
nl(0)

and to look at the past 5 transactions for ned:

kryzsec@kryzsec-a101:~$ python transactions.py
Enter who to follow: ned
Enter number of transactions to look at: 5
[
    [
        71938,
         {
            'trx_id': '00559f94f58829adbc49135d67c2979c8b4c1edb',
             'block': 19496052,
             'trx_in_block': 21,
             'op_in_trx': 0,
             'virtual_op': 0,
             'timestamp': '2018-02-01T18:45:27',
             'op': [
                'vote',
                 {
                    'voter': 'gurb',
                     'author': 'ned',
                     'permlink': 'new-logo-teaser',
                     'weight': 10000
                }
            ]
        }
    ],
     [
        71939,
         {
            'trx_id': 'a6b2c862a03f12b840facf3562c6043582148c7e',
             'block': 19496839,
             'trx_in_block': 22,
             'op_in_trx': 0,
             'virtual_op': 0,
             'timestamp': '2018-02-01T19:24:54',
             'op': [
                'vote',
                 {
                    'voter': 'jackhistoria',
                     'author': 'ned',
                     'permlink': 're-dan-proof-of-good-governance-20180101t182240861z',
                     'weight': 10000
                }
            ]
        }
    ],
     [
        71940,
         {
            'trx_id': '59d38cba0d4c8a2e6bb1acc1523e50859824ce61',
             'block': 19497134,
             'trx_in_block': 12,
             'op_in_trx': 0,
             'virtual_op': 0,
             'timestamp': '2018-02-01T19:39:39',
             'op': [
                'vote',
                 {
                    'voter': 'jackhistoria',
                     'author': 'ned',
                     'permlink': 're-frankbacon-re-ned-re-dan-proof-of-good-governance-20180101t232544604z',
                     'weight': 10000
                }
            ]
        }
    ],
     [
        71941,
         {
            'trx_id': '425710bd604afa5fc87ecbcda98f568154dfc24f',
             'block': 19497177,
             'trx_in_block': 45,
             'op_in_trx': 0,
             'virtual_op': 0,
             'timestamp': '2018-02-01T19:41:48',
             'op': [
                'vote',
                 {
                    'voter': 'jackhistoria',
                     'author': 'ned',
                     'permlink': 're-benjojo-re-ned-re-dan-proof-of-good-governance-20180103t014600764z',
                     'weight': 10000
                }
            ]
        }
    ],
     [
        71942,
         {
            'trx_id': 'c78d87d3504fe499eb6ab69d737e654f411306c2',
             'block': 19497513,
             'trx_in_block': 15,
             'op_in_trx': 0,
             'virtual_op': 0,
             'timestamp': '2018-02-01T19:58:42',
             'op': [
                'comment',
                 {
                    'parent_author': 'ned',
                     'parent_permlink': 're-benjojo-re-ned-re-dan-proof-of-good-governance-20180103t014600764z',
                     'author': 'jackhistoria',
                     'permlink': 're-ned-re-benjojo-re-ned-re-dan-proof-of-good-governance-20180201t195842643z',
                     'title': '',
                     'body': '@ned I love your view on things like playing a game. But scrabble? ;-) I was surprised to see on the live communitys that people still play counterstrike and not because it works on all computers like as I was 14 :-D Short rounds,
                     benefits in the long run - 2 partys,
                     fast and easy even for beginners that gain in skill,
                     not in time of being there in the community. \nI went in here active a few days ago and I feel all the time as a new guy in a company after 3.5 years of training and it seems like I need or have to "dig into whale asses" to evolve in here not for being diligent or hard work. (In facebook I felt way better at the start) I understand that money gives power but if it is possible what you want to change that only "diggers" could rise up great content creators will pass over time. So if I understand you right,
                     you want to strengthen the fundamental players and creators. That is only possible to share or reduce the power of the big players and has to be done to give this community a future (not by utilizing one new platform after another when the fundamental basement (steemit.com) is rotten) \nThanks for your effort - I hope it pays out for you and the whole community',
                     'json_metadata': '{
                        "tags":[
                            "eos"
                        ],
                        "users":[
                            "ned"
                        ],
                        "app":"steemit/0.1"
                    }'
                }
            ]
        }
    ]
]

I hope that this can be useful for someone that is just learning how the blockchain works. The next part I will go into using better methods for doing this and I am thinking about going through the steem.post() class in more depth to show usage of it. The part after that I will introduce the blckchain class that will allow you to actually download each block and by then we should have covered enough of the basics so that you will know how take actually build a bot to react to different things. Like say someone you are following upvotes a post and you want to vote it as well so you do, maybe you will want to like any post that has your username in it so long as there are fewer than 10 other people linked. Maybe you want to upvote every post posted by a specific person. After that we will go into the classes that allow you to look at the market and maybe place trades to buy or sell steem or sbd. Eventually we will get into the transaction builder class but more on that when we come to it. And at some point I will introduce the custom_json method that allows you to really do whatever you want.
References
Printing An Error In Python: stackoverflow.com/questions/1483429/how-to-print-an-error-in-python
Steem-Python Documentation: steem.readthedocs.io/en/latest/index.html
Installing Steem Python: steemit.com/programming/@themarkymark/how-to-install-steem-python
Python String Documentation: docs.python.org/3/library/stdtypes.html
JSON: www.json.org/
Making A Vote Bot: steemit.com/steem-python/@kryzsec/making-a-steemit-bot-part-1-basic-voting

Kryzsec's Steemit Board


Image Source from @nitesh9

Do you enjoy reading or writing topics related to STEM (Science, Technology, Engineering, and Mathematics) then I would suggest checking out @steemstem! They do wonderful work curating the best STEM related posts on Steemit. For more information check out the SteemStem chat room on steemit.chat or check out their Guidlines and start writing.

Sort:  

nice post

Will try this, thanks. (commenting, so I can easy find it in a few days)

Btw, every time I print out something json, I get on the screen all condensed into one long multi line. I need to learn, how to get json output like in your example. It does makes life easier ;-)

If you look I have a codeblock named Transactions.py before the finale printout which is a way to print out JSON (from the steem blockchain) nicely. If you use the JSON module they have a built in function to print out JSON files in a similar way to mine, though they do it with more complex functions since they are not trying to make code that people can understand, just making code that works.

If you have any questions I can answer!

Thanks, I haven't try your code yet, just generally whenever I print out json I get everything lumped together. Will try your code and see if it works as you have it in your screenshot.

I hope it works for you, I made it and copied and pasted but I know some spacing issues can come from copying from steemit codeblocks

Coin Marketplace

STEEM 0.28
TRX 0.12
JST 0.033
BTC 69774.83
ETH 3620.03
USDT 1.00
SBD 3.72