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
Example #2
0
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)
Example #3
0
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)