Welcome to Lightsteem code golf series #2
Workflow/Requirements of the evil script
- Get followers
- Exclude inactive followers (Last bandwidth update)
- Exclude followers using a proxy for voting
- Exclude followers already voting for you
- Exclude followers already actively voting for 30 witnesses
- Bundle 100 operations into one transaction to keep the network effect limited.
Source
import logging
import time
from datetime import datetime
from dateutil.parser import parse
from lightsteem.client import Client
from lightsteem.datastructures import Operation
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logging.basicConfig()
WITNESS_ACCOUNT = "emrebeyler"
MEMO_TEMPLATE = "Hey {username}, I have been running a STEEM witness in the last" \
" six months. Since you already follow me and have free slots on " \
"your witness voting, please consider casting a witness vote for" \
" me. (@{witness_account}). Here you can directly cast a vote: https://steemconnect.com/sign/account-witness-vote?witness=emrebeyler&approve=1"
USERLIST_FILE = "/users/emre/memo-sent.txt"
ACTIVE_KEY = ""
def chunks(l, n):
for i in range(0, len(l), n):
yield l[i:i + n]
def add_to_list(username):
with open(USERLIST_FILE, 'a+') as f:
f.write("%s\n" % username)
def already_sent(username):
with open(USERLIST_FILE, 'r') as f:
for line in f.readlines():
if username in line:
return True
return False
def main():
c = Client(keys=[ACTIVE_KEY,])
account = c.account(WITNESS_ACCOUNT)
followers = account.followers()
print(f"{len(followers)} follower found.")
suitable_followers = []
account_details_of_followers = c.get_accounts(followers)
for follower_data in account_details_of_followers:
follower = follower_data["name"]
# check the follower is not dead
last_bandwidth_update = parse(follower_data["last_bandwidth_update"])
if (datetime.utcnow() - last_bandwidth_update).total_seconds() > 86400 * 30:
logger.debug(f"{follower} account looks like dead. Skipping.")
continue
# check the follower is full on their votes.
witness_votes = follower_data["witness_votes"]
if len(witness_votes) == 30:
logger.debug(f"{follower} is full. Skipping.")
continue
# check the follower has a proxy?
if follower_data["proxy"]:
logger.debug(f"{follower} has a proxy. Skipping.")
continue
# check the follower is already voting for me
if WITNESS_ACCOUNT in witness_votes:
logger.debug(
f"{follower} is already voting for {WITNESS_ACCOUNT}. Skipping.")
continue
suitable_followers.append(follower)
# handle memos
print(f"{len(suitable_followers)} found.")
for follower_username_list in chunks(suitable_followers, 100):
ops = []
for follower_username in follower_username_list:
memo = MEMO_TEMPLATE.format(
username=follower_username,
witness_account=WITNESS_ACCOUNT
)
if already_sent(follower_username):
logger.info(f"{follower_username} already got a memo. Skipping")
continue
ops.append(
Operation('transfer', {
'from': WITNESS_ACCOUNT,
'to': follower_username,
'amount': '0.001 SBD',
'memo': memo
})
)
add_to_list(follower_username)
if len(ops):
c.broadcast(ops)
time.sleep(3)
if __name__ == '__main__':
main()