From f41b7e20082c1ea2daff120e3c2dd08d7965fe92 Mon Sep 17 00:00:00 2001 From: sisygoboom Date: Sat, 26 May 2018 03:09:21 +0100 Subject: [PATCH] Included utilisation of steem sincerity Added use of the steem sincerity api and switched from the official steem library to beem. --- abuse_detection_steemit.py | 120 +++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 39 deletions(-) diff --git a/abuse_detection_steemit.py b/abuse_detection_steemit.py index b3d5a85..b67ec40 100644 --- a/abuse_detection_steemit.py +++ b/abuse_detection_steemit.py @@ -1,12 +1,16 @@ -from steem.instance import set_shared_steemd_instance -from steem.blockchain import Blockchain -from steem.steemd import Steemd -from steem.amount import Amount +from beem.instance import set_shared_steem_instance +from beem.blockchain import Blockchain +#from beem.steemd import Steemd +from beem.amount import Amount +from beem.comment import Comment +from beem.account import Account +from beem import Steem from datetime import datetime +from datetime import timedelta from pathlib import Path -from steem import Steem from time import sleep import json +import requests nodes = ['https://rpc.buildteam.io', 'https://api.steemit.com', @@ -17,7 +21,7 @@ s = Steem(nodes) bchn = Blockchain(s) -set_shared_steemd_instance(Steemd(nodes=nodes)) +set_shared_steem_instance(s) # Minimum vote worth to be considered abuse, remember that making this too high # will prevent you from detecting botnets with lots of smaller votes @@ -38,24 +42,30 @@ def save(): with open("abuse_log.json", "w") as abuse_log: abuse_log.write(json.dumps(data)) + +def findRole(sincerity_info): + role = 'unknown' + if sincerity_info['bot_score'] > 0.5: role = 'bot' + elif sincerity_info['spam_score'] > 0.5: role = 'spammer' + elif sincerity_info['human_score'] > 0.5: role = 'human' + return role ### Main procedure, every vote we stream is sent here to be analysed def infoDigger(operation): - # Get preliminary information on the post: author, permlink and cashout time + # Get preliminary information on the post: author and permlink author = operation['author'] permlink = operation['permlink'] - cashout = s.get_content(author, permlink)['cashout_time'] - # Make cashout into a datetime object - cashout = datetime.strptime(cashout, '%Y-%m-%dT%H:%M:%S') - # Get the difference between current time and the cashout time - now = datetime.now() - diff = cashout - now + + # Get time until cashout + creation = Comment(author + "/" + permlink).time_elapsed() + week = timedelta(days=7) + cashout = week - creation # Continue if the difference is smaller than accepted days, but hasn't cashed out # Bear in mind that a half day is the same as 0 days, a full 24 hours is needed for the day - if diff.days < max_time_days and diff.days>=0: + if cashout.days < max_time_days and cashout.days>=0: # Calculate difference in hours - hours = diff.seconds/3600 + hours = cashout.seconds/3600 # If the difference is below max accepted hours, continue if hours < max_time_hours: @@ -63,12 +73,12 @@ def infoDigger(operation): voter = operation['voter'] # Get eight as a fraction weight = operation['weight']*0.0001 - try: voter_account = s.get_account(voter) + try: voter_account = Account(voter) except: print(voter) # Tally vests - vests = float(voter_account['vesting_shares'].replace(' VESTS','')) - vests -= float(voter_account['delegated_vesting_shares'].replace(' VESTS','')) - vests += float(voter_account['received_vesting_shares'].replace(' VESTS','')) + vests = float(voter_account['vesting_shares'].amount) + vests -= float(voter_account['delegated_vesting_shares'].amount) + vests += float(voter_account['received_vesting_shares'].amount) # Vests if upvote was 100% vests *= 1000000 vests *= 0.02 @@ -78,14 +88,14 @@ def infoDigger(operation): # Ignore downvotes if vests > 0: # Calculate how much steem that vote has earned the author - reward_fund = s.get_reward_fund('post') + reward_fund = s.get_reward_funds('post') fund_vests = float(reward_fund.get('recent_claims')) fund_balance = Amount(reward_fund.get('reward_balance')).amount fund_percent = vests/fund_vests to_steem = fund_percent * fund_balance # Convert that steem to usd using internal median price - price = s.get_current_median_history_price() + price = s.get_current_median_history() quote = Amount(price["quote"]) base = Amount(price["base"]) conversion_rate = base.amount / quote.amount @@ -93,20 +103,48 @@ def infoDigger(operation): # Continue if usdreward is above minimum requirements if usd_reward > min_usd_reward: + # Get spammer and bot ratings from steem sincerity + r = requests.get('https://steem-sincerity.dapptools.info/s/api/accounts-info/%s,%s' % (voter, author)) + accounts_info = r.json()['data'] + + # Separate accounts + author_info = accounts_info[author] + voter_info = accounts_info[voter] + + # Store dictionary of bot, human and spammer scores + author_info = { + 'bot_score':author_info['classification_bot_score'], + 'spam_score':author_info['classification_spammer_score'], + 'human_score':author_info['classification_human_score'] + } + voter_info = { + 'bot_score':voter_info['classification_bot_score'], + 'spam_score':voter_info['classification_spammer_score'], + 'human_score':voter_info['classification_human_score'] + } + # Visual user feedback print("$" + str(usd_reward)) - print(voter) - print("https://steemit.com/@" + author + "/" + permlink) + print("voter: @%s (%s)" % (voter, findRole(voter_info))) + print("author: @%s (%s)" % (author, findRole(author_info))) + print("https://steemit.com/@%s/%s\n" % (author, permlink)) + # Adds a tally to the voters # of outgoing last day votes # also, calculates the cumulative USD reward of all LM votes # both incoming and outgoing - if voter in data['voters']: - data['voters'][voter]['quantity'] += 1 - data['voters'][voter]['value'] += usd_reward + voters = data['voters'] + + if voter in voters: + voters[voter]['quantity'] += 1 + voters[voter]['value'] += usd_reward # Create a new entry for unknown user else: - data['voters'][voter] = {"quantity":1,"value":usd_reward} + voters[voter] = dict() + voters[voter]['quantity'] = 1 + voters[voter]['value'] = usd_reward + # Store/update sincerity information + voters[voter]['info'] = voter_info # Updates the total revenue from last day votes for the author # also updates stats for individual posts for further data mining @@ -142,11 +180,15 @@ def infoDigger(operation): else: # Create dictionary for new author recievers[author] = dict() + recieving_author = recievers[author] # Populate with necessary information - recievers[author]['total_lme'] = usd_reward, - recievers[author][permlink] = dict() - recievers[author][permlink]['bal'] = usd_reward, - recievers[author][permlink]['voters'] = [voter] + recieving_author['total_lme'] = usd_reward + recieving_author[permlink] = dict() + recieving_author[permlink]['bal'] = usd_reward + recieving_author[permlink]['voters'] = [voter] + + # Store/update sincerity information + recieving_author['info'] = author_info save() @@ -155,15 +197,15 @@ def infoDigger(operation): ### Safetylopp while True: - try: +# try: # Blockstream (Mainloop) - streams all votes on the blockchain - for i in bchn.stream(filter_by=['vote']): + for i in bchn.stream(opNames=['vote']): # Check vote for eligibility infoDigger(i) - except Exception as e: - print(e) - # Switch nodes if stream breaks - nodes = nodes[1:] + nodes[:1] - print("======================= node unavaliable, switching =======================") - sleep(1) \ No newline at end of file +# except Exception as e: +# print(e) +# # Switch nodes if stream breaks +# nodes = nodes[1:] + nodes[:1] +# print("======================= node unavaliable, switching =======================") +# sleep(1) \ No newline at end of file