Examples

Syncing Blockchain to a Flat File

Here is a relatively simple script built on top of steem-python that will let you sync STEEM blockchain into a simple file. You can run this script as many times as you like, and it will continue from the last block it synced.

import json
import os
from contextlib import suppress
from steem.blockchain import Blockchain


def get_last_line(filename):
    if os.path.isfile(filename):
        with open(filename, 'rb') as f:
            f.seek(-2, 2)
            while f.read(1) != b"\n":
                f.seek(-2, 1)
            return f.readline()


def get_previous_block_num(block):
    if not block:
        return -1

    if type(block) == bytes:
        block = block.decode('utf-8')

    if type(block) == str:
        block = json.loads(block)

    return int(block['previous'][:8], base=16)


def run(filename):
    b = Blockchain()
    # automatically resume from where we left off
    # previous + last + 1
    start_block = get_previous_block_num(get_last_line(filename)) + 2
    with open(filename, 'a+') as file:
        for block in b.stream_from(start_block=start_block, full_blocks=True):
            file.write(json.dumps(block, sort_keys=True) + '\n')


if __name__ == '__main__':
    output_file = '/home/user/Downloads/steem.blockchain.json'
    with suppress(KeyboardInterrupt):
        run(output_file)

To see how many blocks we currently have, we can simply perform a line count.

wc -l steem.blockchain.json

We can also inspect an arbitrary block, and pretty-print it. Replace 10000 with desired block_number + 1.

sed '10000q;d' steem.blockchain.json | python -m json.tool

Witness Killswitch

Occasionally things go wrong: software crashes, servers go down… One of the main roles for STEEM witnesses is to reliably mint blocks. This script acts as a kill-switch to protect the network from missed blocks and prevents embarrassment when things go totally wrong.

import time
from steem import Steem

steem = Steem()

# variables
disable_after = 10  # disable witness after 10 blocks are missed
witness_name = 'furion'
witness_url = "https://steemit.com/steemit/@furion/power-down-no-more"
witness_props = {
    "account_creation_fee": "0.500 STEEM",
    "maximum_block_size": 65536,
    "sbd_interest_rate": 15,
}


def total_missed():
    return steem.get_witness_by_account(witness_name)['total_missed']


if __name__ == '__main__':
    treshold = total_missed() + disable_after
    while True:
        if total_missed() > treshold:
            tx = steem.commit.witness_update(
                signing_key=None,
                url=witness_url,
                props=witness_props,
                account=witness_name)

            print("Witness %s Disabled!" % witness_name)
            quit(0)

        time.sleep(60)

Batching Operations

Most of the time each transaction contains only one operation (for example, an upvote, a transfer or a new post). We can however cram multiple operations in a single transaction, to achieve better efficiency and size reduction.

This script will also teach us how to create and sign transactions ourselves.

from steem.transactionbuilder import TransactionBuilder
from steembase import operations

# lets create 3 transfers, to 3 different people
transfers = [
    {
        'from': 'richguy',
        'to': 'recipient1',
        'amount': '0.001 STEEM',
        'memo': 'Test Transfer 1'
    },
    {
        'from': 'richguy',
        'to': 'recipient2',
        'amount': '0.002 STEEM',
        'memo': 'Test Transfer 2'
    },
    {
        'from': 'richguy',
        'to': 'recipient3',
        'amount': '0.003 STEEM',
        'memo': 'Test Transfer 3'
    }

]

# now we can construct the transaction
# we will set no_broadcast to True because
# we don't want to really send funds, just testing.
tb = TransactionBuilder(no_broadcast=True)

# lets serialize our transfers into a format Steem can understand
operations = [operations.Transfer(**x) for x in transfers]

# tell TransactionBuilder to use our serialized transfers
tb.appendOps(operations)

# we need to tell TransactionBuilder about
# everyone who needs to sign the transaction.
# since all payments are made from `richguy`,
# we just need to do this once
tb.appendSigner('richguy', 'active')

# sign the transaction
tb.sign()

# broadcast the transaction (publish to steem)
# since we specified no_broadcast=True earlier
# this method won't actually do anything
tx = tb.broadcast()

Simple Voting Bot

Here is a simple bot that will reciprocate by upvoting all new posts that mention us. Make sure to set whoami to your Steem username before running.

from contextlib import suppress

from steem.blockchain import Blockchain
from steem.post import Post


def run():
    # upvote posts with 30% weight
    upvote_pct = 30
    whoami = 'my-steem-username'

    # stream comments as they are published on the blockchain
    # turn them into convenient Post objects while we're at it
    b = Blockchain()
    stream = map(Post, b.stream(filter_by=['comment']))

    for post in stream:
        if post.json_metadata:
            mentions = post.json_metadata.get('users', [])

            # if post mentions more than 10 people its likely spam
            if mentions and len(mentions) < 10:
                post.upvote(weight=upvote_pct, voter=whoami)

if __name__ == '__main__':
    with suppress(KeyboardInterrupt):
        run()