def test_transfer(): wif = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3' c = Commit(steemd_instance=Steemd(nodes=[]), keys=[wif]) rpc_error = None try: c.transfer('test2', '1.000', 'STEEM', 'foo', 'test') except RPCError as e: rpc_error = str(e) else: raise Exception('expected RPCError') assert 'tx_missing_active_auth' in rpc_error
class TransactionListener(object): def __init__(self, steem): self.steem = steem self.commit = Commit(steem) self.watch_account = settings.BOT_ACCOUNT @property def last_irreversible_block_num(self): props = self.steem.get_dynamic_global_properties() if not props: logger.info('Couldnt get block num. Retrying.') return self.last_irreversible_block_num return props['last_irreversible_block_num'] @property def block_interval(self): config = self.steem.get_config() return config["STEEMIT_BLOCK_INTERVAL"] @property def upvote_weight(self): min_weight, max_weight = settings.UPVOTE_WEIGHTS return float(random.randint(min_weight, max_weight)) def process_block(self, block_id, retry_count=0): block_data = self.steem.get_block(block_id) if not block_data: if retry_count > 3: logger.error('Retried 3 times to get this block: %s Skipping.', block_id) return logger.error('Couldnt read the block: %s. Retrying.', block_id) self.process_block(block_id, retry_count=retry_count + 1) logger.info('Processing block: %s', block_id) if 'transactions' not in block_data: return for tx in block_data['transactions']: for operation in tx['operations']: operation_type, operation_data = operation[0:2] if operation_type == 'transfer': self.process_transfer(operation_data, block_data, block_id) def process_transfer(self, op, block_data, block_id): if op["to"] == self.watch_account: logger.info("%d | %s | %s -> %s: %s -- %s" % (block_id, block_data["timestamp"], op["from"], op["to"], op["amount"], op["memo"])) if "SBD" in op['amount']: amount_in_float = float(op['amount'].split(' ')[0]) if amount_in_float < settings.MINIMUM_SBD_FOR_UPVOTE: self.refund( op, 'Minimum SBD for upvote: %s' % settings.MINIMUM_SBD_FOR_UPVOTE) return self.upvote(op) else: logger.info('There is a transfer but its not SBD. Ignoring.') def refund(self, op, message): refund_key = db.refund_key(op['from'], op['memo'], op['amount']) if db.already_refunded(op['from'], op['memo'], op['amount']): logger.info('This is already refunded. Skipping. %s', refund_key) return refund_amount, asset = op['amount'].split(' ') if float(refund_amount) > 0.5: logger.error('Too much for a auto-refund. Skipping.') return self.commit.transfer(op['from'], float(refund_amount), memo=message, asset=asset, account=self.watch_account) logger.info('Refunded %s for invalid request.', op['from']) db.add_refund(op['from'], op['memo'], op['amount']) def upvote(self, op): try: post = Post(op['memo']) except ValueError: logger.info('Invalid identifier: %s', op['memo']) self.refund(op, message='invalid url') return try: weight = self.upvote_weight post.upvote(weight=weight, voter=self.watch_account) except VotingInvalidOnArchivedPost as e: logger.info('Archived post. Cannot upvote. %s', op['memo']) self.refund(op, message='Couldnt vote. Archived post. %s' % op['memo']) return except Exception as e: if 'already voted' in e.args[0]: self.refund(op, message='Already upvoted. %s' % op['memo']) logger.info('Already voted: %s. Skipping.', op['memo']) return if 'Read timed' in e.args[0]: logger.info('Node is not responding. Trying again to upvote.') return self.upvote(op) logger.info('Upvoted %s with weight: %s', op['memo'], weight) def run(self): last_block = db.load_checkpoint( fallback_block_num=self.last_irreversible_block_num, ) logger.info('Last processed block: %s', last_block) while True: while (self.last_irreversible_block_num - last_block) > 0: last_block += 1 self.process_block(last_block) db.dump_checkpoint(last_block) # Sleep for one block block_interval = self.block_interval logger.info('Sleeping for %s seconds.', block_interval) time.sleep(block_interval)
class TransactionListener(object): def __init__(self, steem, config): self.steem = steem self.account = config["account"] self.mysql_uri = config["mysql_uri"] self.config = config self.commit = Commit(steem) def get_table(self, table): db = dataset.connect(self.mysql_uri) return db[table] @property def properties(self): props = self.steem.get_dynamic_global_properties() if not props: logger.info('Couldnt get block num. Retrying.') return self.properties return props @property def last_block_num(self): return self.properties['head_block_number'] @property def block_interval(self): config = self.steem.get_config() return config["STEEMIT_BLOCK_INTERVAL"] def process_block(self, block_num, retry_count=0): block_data = self.steem.get_block(block_num) if not block_data: if retry_count > 3: logger.error('Retried 3 times to get this block: %s Skipping.', block_num) return logger.error('Couldnt read the block: %s. Retrying.', block_num) self.process_block(block_num, retry_count=retry_count + 1) logger.info('Processing block: %s', block_num) if 'transactions' not in block_data: return self.check_block(block_num) dump_state(self.properties) def run(self, start_from=None): if start_from is None: last_block = load_checkpoint( fallback_block_num=self.last_block_num, ) logger.info('Last processed block: %s', last_block) else: last_block = start_from while True: while (self.last_block_num - last_block) > 0: last_block += 1 self.process_block(last_block) dump_checkpoint(last_block) # Sleep for one block block_interval = self.block_interval logger.info('Sleeping for %s seconds.', block_interval) time.sleep(block_interval) def daily_message(self): post_list = [] query = {"limit": 15, "tag": "tr"} # limit for 5 posts for p in self.steem.get_discussions_by_hot(query): metadata = json.loads(p["json_metadata"]) if metadata and 'utopian-io' in metadata["tags"]: continue if metadata and 'sndbox' in metadata["tags"]: continue if p["author"] == "turbot": continue link = "https://steemit.com/@%s/%s" % (p["author"], p["permlink"]) author_link = "https://steemit.com/%s" % p["author"] post = Post(link, steemd_instance=self.steem) try: self.upvote(post, 20) time.sleep(4) pass except Exception as error: logger.error(error) post_list.append("- [%s](%s) - [@%s](%s)" % (p["title"], link, p["author"], author_link)) body = open(self.config["daily_message"]).read() body = body.replace("$post_list", "\n".join(post_list)) today = date.today().strftime("%Y.%m.%d") self.steem.commit.post( "Son 24 saatte turbot tarafından oylanan yazılar (%s)" % today, body, "turbot", tags=["tr", "turbot"]) def upvote(self, post, weight=+5): full_link = "@%s/%s" % (post["author"], post["permlink"]) already_upvoted = self.get_table('upvote').find_one( author=post["author"], permlink=post["permlink"]) if already_upvoted: logger.info('Already voted. Skipping. %s', full_link) return resp = post.commit.vote(post.identifier, weight, account=self.account) if not resp: logger.error("Failed upvoting. %s", full_link) def handle_command(self, post): if post["author"] in self.config["blacklisted_users"]: logger.info("User on blacklist. (%s). Skipping", post["permlink"]) return # welcome command if re.findall("@%s\s!(welcome)" % self.account, post["body"]): main_post = Post(post.root_identifier, steemd_instance=self.steem) already_welcomed = self.get_table('welcome').find_one( author=main_post["author"]) if already_welcomed: logger.info("This user: %s already welcomed. Skipping" % main_post["author"]) return body = open(self.config["welcome_message"]).read() body = body.replace("$username", main_post["author"]) main_post.reply( body=body, author=self.account, ) if not main_post.is_main_post(): logger.info("Skipping. Not a main post.") return try: self.upvote(main_post) except Exception as e: logger.error(e) logger.info("Replied and upvoted user: %s", main_post["author"]) self.get_table('welcome').insert( dict( author=main_post["author"], permlink=main_post["permlink"], created_at=str(datetime.now()), )) if self.config["send_welcome_gift"] == "yes": self.commit.transfer(main_post["author"], self.config["welcome_gift"], memo=self.config["welcome_gift_message"], asset="SBD", account=self.account) # handle help commands help_commands = [ "creating_new_accounts", "bots", "curation_rewards", "downvote", "esteem", "security", "voting_power", "upvote", "tag_spam", "comment_spam", "wallet", "plagiarism", "posting" ] for command in help_commands: if re.findall("@%s\s!(%s)" % (self.account, command), post["body"]): message_path = "%s%s.md" % (self.config["help_commands_path"], command) main_post = Post(post.root_identifier, steemd_instance=self.steem) body = open(message_path).read() body = body.replace("$username", main_post["author"]) if not main_post.is_main_post(): logger.info("Skipping. Not a main post.") return main_post.reply( body=body, author=self.account, ) logger.info("Posted %s command reply." % command) def check_block(self, block_num): operation_data = self.steem.get_ops_in_block(block_num, virtual_only=False) for operation in operation_data: operation_type, raw_data = operation["op"][0:2] if operation_type == "comment": try: post = Post(raw_data, steemd_instance=self.steem) except Exception as error: logger.error(error) continue if post.is_main_post(): # we're only interested in comments. continue if "@" + self.account in post["body"]: try: self.handle_command(post) except Exception as e: logger.error(e)