def process_tx_header_from_db(tx_db_data, human_readable = True):
    tx_dict = {
        "block_height": tx_db_data["block_height"],
        "change": tx_db_data["tx_change"],

        "funds_balance_validation_status": \
        btc_grunt.bin2bool(tx_db_data["tx_funds_balance_validation_status"]),

        "lock_time": tx_db_data["tx_lock_time"],

        "lock_time_validation_status": \
        btc_grunt.bin2bool(tx_db_data["tx_lock_time_validation_status"]),

        "num_inputs": tx_db_data["num_txins"],
        "num_outputs": tx_db_data["num_txouts"],
        "size": tx_db_data["tx_size"],
        "version": tx_db_data["tx_version"],
        "tx_num": tx_db_data["tx_num"],
        "input": {},
        "output": {}
    }
    if human_readable:
        tx_dict["hash"] = tx_db_data["tx_hash_hex"]
        tx_dict["block_hash"] = tx_db_data["block_hash_hex"]
    else:
        tx_dict["hash"] = btc_grunt.hex2bin(tx_db_data["tx_hash_hex"])
        tx_dict["block_hash"] = btc_grunt.hex2bin(tx_db_data["block_hash_hex"])

    if human_readable:
        tx_dict = btc_grunt.human_readable_tx(tx_dict, 0, 0, 0, 0, None)

    return tx_dict
Beispiel #2
0
def get_tx_data_from_rpc(input_arg_format, data):
    btc_grunt.connect_to_rpc()

    if input_arg_format == "blockheight-txnum":
        # the program always requires the txhash, regardless of input format
        (block_height, tx_num) = data
        block_rpc_dict = btc_grunt.get_block(block_height, "json")
        try:
            txhash_hex = block_rpc_dict["tx"][tx_num]
        except IndexError:
            raise IndexError(
                "\n\ntx number %d does not exist in block %d\n\n"
                % (tx_num, block_height)
            )
    elif input_arg_format == "txhash":
        txhash_hex = data

    # note that this bitcoin-rpc dict is in a different format to the btc_grunt
    # tx dicts
    tx_rpc_dict = btc_grunt.get_transaction(txhash_hex, "json")

    if input_arg_format == "txhash":
        tx_hash_hex = data
        block_rpc_dict = btc_grunt.get_block(tx_rpc_dict["blockhash"], "json")
        block_height = block_rpc_dict["height"]
        tx_num = block_rpc_dict["tx"].index(txhash_hex)

    tx_bin = btc_grunt.hex2bin(tx_rpc_dict["hex"])
    required_info = copy.deepcopy(btc_grunt.all_tx_and_validation_info)
    (tx_dict, _) = btc_grunt.tx_bin2dict(
        tx_bin, 0, required_info, tx_num, block_height, ["rpc"]
    )

    return (tx_dict, tx_num, block_rpc_dict, tx_rpc_dict)
Beispiel #3
0
if len(sys.argv) < 2:
	raise ValueError(
		"\n\nUsage: ./get_tx.py <the tx hash in hex>\n"
		"eg: ./get_tx.py 514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b1"
		"9d98832b58\n\n"
	)
txhash_hex = sys.argv[1]

btc_grunt.connect_to_rpc()

# note that this bitcoin-rpc dict is in a different format to the btc_grunt tx
# dicts
tx_rpc_dict = btc_grunt.get_transaction(txhash_hex, "json")

# the blockhash that the tx appears in
blockhash = tx_rpc_dict["blockhash"]

block_rpc_dict = btc_grunt.get_block(blockhash, "json")
block_height = block_rpc_dict["height"]
tx_num = block_rpc_dict["tx"].index(txhash_hex)
tx_bin = btc_grunt.hex2bin(tx_rpc_dict["hex"])
tx_dict = btc_grunt.human_readable_tx(tx_bin, tx_num, block_height)
explain_errors = False
print "\nblock height: %d\nblock hash: %s\ntx num: %d\ntx: %s" % (
	block_height, blockhash, tx_num,
	os.linesep.join(l.rstrip() for l in json.dumps(
		tx_dict, sort_keys = True, indent = 4
	).splitlines())
)
alice_signature3 = ecdsa_ssl.sign(alice_signs_this3)
#print btc_grunt.bin2hex(alice_signature3)
#print btc_grunt.bin2hex(alice_public_key3)

# alice: ok, here is the signature: 304402204db6eb1dbad806c30dd1ca9d447a83d02560
# 4f5fdc240071c1701b0f570c8ce9022029c8d82bbd5054191b705e1b59a01b5f1fb83dd95e3759
# bf697190f376916011 and my public key is 043541f2e75c8ee8266dd11fdc1885c48efeea
# 551fbb41f8e52f7bb69cf25c2b8c33a692474756f8d6849b1a7b5e15500b6aac261bdca3c5a897
# 01c8cd69e3516e

# bob: ok let me first check that the public key actually corresponds to address
# 1KZfohMK4dt1eCP1tbGrSaWmQ5KMX5MV98...

bob_test_pubkey_hex3 = "043541f2e75c8ee8266dd11fdc1885c48efeea551fbb41f8e52f7" \
"bb69cf25c2b8c33a692474756f8d6849b1a7b5e15500b6aac261bdca3c5a89701c8cd69e3516e"
bob_test_pubkey_bin3 = btc_grunt.hex2bin(bob_test_pubkey_hex3)

bob_derived_address3 = btc_grunt.pubkey2address(bob_test_pubkey_bin3)
if bob_derived_address3 == alice_address3:
	# bob: yep. it checks out!
	pass
else:
	# bob: nope. this public key does not belong to the address you gave me. i
	# knew you were lying!
	lang_grunt.die(
		"fail. alice's address %s differs from the address bob has derived from"
		" her public key: %s" % (
			alice_address3, bob_derived_address3
		)
	)
#!/usr/bin/env python2.7

import os, sys

# when executing this script directly include the parent dir in the path
if (
	(__name__ == "__main__") and
	(__package__ is None)
):
	os.sys.path.append(
		os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
	)
import btc_grunt

if len(sys.argv) < 2:
	raise ValueError(
		"\n\nUsage: ./script_hex2human_str.py <the script in hex>\n"
		"eg: ./script_hex2human_str.py 76a914b0c1c1de86419f7c6f3186935e6bd6ccb5"
		"2b8ee588ac\n\n"
	)

script_hex = sys.argv[1]

script_bin = btc_grunt.hex2bin(script_hex)

# convert to a list of binary opcodes and data elements
script_list = btc_grunt.script_bin2list(script_bin)

# convert to a human readable string
print btc_grunt.script_list2human_str(script_list)
	),
	("30 06 02 02 7f 02 01 7f 01", "wrong <length r>"),
	("30 06 02 01 7f 02 02 7f 01", "<length r> and <length s> do not add up"),
	("30 06 02 00    02 01 7f 01 00", "no r (append 00 otherwise too short)"),
	("30 06 02 01 ff 02 01 7f 01", "r is ambiguously negative"),
	("30 07 02 02 00 01 02 01 7f 01", "r starts with 00 and is not negative"),
	(
		"30 06 02 01 7f 00 01 7f 01",
		"wrong placeholder 3 byte, otherwise correct"
	),
	("30 06 02 01 7f 02 00    01 00", "no s (append 00 otherwise too short)"),
	("30 06 02 01 7f 02 01 ff 01", "s is ambiguously negative"),
	("30 07 02 01 7f 02 02 00 01 01", "s starts with 00 and is not negative"),
]
for (i, (der_signature_human, error_description)) in enumerate(inputs):
	der_signature_bin = btc_grunt.hex2bin(der_signature_human.replace(" ", ""))
	if verbose:
		print """
================== test for incorrect der signature encoding %s ================
ensure %s. der signature: %s
""" % (i, error_description, der_signature_human)

	res = btc_grunt.valid_der_signature(der_signature_bin, explain = True)
	if res is True:
		raise Exception(
			"function valid_der_signature() failed to detect the error in der"
			" signature bytes %"
			% der_signature_human
		)
	else:
		if verbose:
def process_tx_body_from_db(tx_dict, human_readable = True):

    if (btc_grunt.valid_hex_hash(tx_dict["hash"])):
        tx_hash_hex = tx_dict["hash"]
    else:
        tx_hash_hex = btc_grunt.bin2hex(tx_dict["hash"])

    txin_txout_data = queries.get_txins_and_txouts(tx_hash_hex)
    count_txins = 0
    count_txouts = 0

    for (i, row) in enumerate(txin_txout_data):
        if (row["type"] == "txin"):
            count_txins += 1
            prev_txout = {}
            if tx_dict["tx_num"] > 0:
                prev_txout_script = btc_grunt.hex2bin(
                    row["prev_txout_script_hex"]
                )
                prev_txout0 = {
                    "script": prev_txout_script,
                    "script_format": row["prev_txout_script_format"],
                    "script_length": len(prev_txout_script),
                    "standard_script_pubkey": row["prev_txout_pubkey"],
                    "standard_script_address": row["prev_txout_address"],
                    "standard_script_alternate_address": \
                    row["prev_txout_alternate_address"]
                }
                prev_txout0["script_list"] = btc_grunt.script_bin2list(
                    prev_txout_script
                )
                if human_readable:
                    prev_txout0["parsed_script"] = \
                    btc_grunt.script_list2human_str(prev_txout0["script_list"])

                prev_txout["output"] = { row["prev_txout_num"]: prev_txout0 }

            txin_script = btc_grunt.hex2bin(row["txin_script_hex"])
            txin = {
                "checksig_validation_status": \
                btc_grunt.bin2bool(row["txin_checksig_validation_status"]),

                "funds": row["txin_funds"],
                "hash": btc_grunt.hex2bin(row["prev_txout_hash_hex"]),
                "hash_validation_status": btc_grunt.bin2bool(
                    row["txin_hash_validation_status"]
                ),
                "index": row["prev_txout_num"],
                "index_validation_status": btc_grunt.bin2bool(
                    row["txin_index_validation_status"]
                ),
                "mature_coinbase_spend_validation_status": \
                btc_grunt.bin2bool(
                    row["txin_mature_coinbase_spend_validation_status"]
                ),
                "script": txin_script,
                "script_format": row["txin_script_format"],
                "script_length": len(txin_script),
                "sequence_num": row["txin_sequence_num"],

                "single_spend_validation_status": \
                btc_grunt.bin2bool(row["txin_single_spend_validation_status"]),

                "spend_from_non_orphan_validation_status": \
                btc_grunt.bin2bool(
                    row["txin_spend_from_non_orphan_validation_status"]
                )
            }
            if tx_dict["tx_num"] > 0:
                txin["prev_txs"] = { 0: prev_txout }

            txin["script_list"] = btc_grunt.script_bin2list(txin_script)
            if human_readable:
                txin["parsed_script"] = \
                btc_grunt.script_list2human_str(txin["script_list"])

            tx_dict["input"][row["txin_num"]] = txin

        if (row["type"] == "txout"):
            count_txouts += 1
            txout_script = btc_grunt.hex2bin(row["txout_script_hex"])
            txout = {
                "funds": row["txout_funds"],
                "script": txout_script,
                "script_format": row["txout_script_format"],
                "script_length": len(txout_script),
                "standard_script_address": row["txout_address"],

                "standard_script_alternate_address": \
                row["txout_alternate_address"],

                "standard_script_address_checksum_validation_status": \
                btc_grunt.bin2bool(
                    row["standard_script_address_checksum_validation_status"]
                )
            }
            if row["txout_pubkey_hex"] is None:
                txout["standard_script_pubkey"] = None
            else:
                txout["standard_script_pubkey"] = \
                btc_grunt.hex2bin(row["txout_pubkey_hex"])

            txout["script_list"] = btc_grunt.script_bin2list(txout_script)
            if human_readable:
                txout["parsed_script"] = \
                btc_grunt.script_list2human_str(txout["script_list"])

            tx_dict["output"][row["txout_num"]] = txout

    tx_dict["txins_exist_validation_status"] = \
    (count_txins == tx_dict["num_inputs"])

    tx_dict["txouts_exist_validation_status"] = \
    (count_txouts == tx_dict["num_outputs"])

    if human_readable:
        tx_dict = btc_grunt.human_readable_tx(tx_dict, 0, 0, 0, 0, None)

    return tx_dict
def process_block_header_from_db(input_arg_format, data, human_readable = True):

    block_hash = block_height = None
    if (btc_grunt.valid_hex_hash(data)):
        input_arg_format = "blockhash"
        block_hash = data
    else:
        input_arg_format = "blockheight"
        block_height = data

    # first get the block header
    block_data_rows = queries.get_tx_header(input_arg_format, data)
    bits = btc_grunt.hex2bin(block_data_rows[0]["bits_hex"])
    num_txs = block_data_rows[0]["num_txs"]
    block_dict = {
        "block_hash": btc_grunt.hex2bin(block_data_rows[0]["block_hash_hex"]),
        "orphan_status": btc_grunt.bin2bool(
            block_data_rows[0]["block_orphan_status"],
        ),
        "block_height": block_data_rows[0]["block_height"],
        "timestamp": block_data_rows[0]["block_time"],
        "bits_validation_status": btc_grunt.bin2bool(
            block_data_rows[0]["bits_validation_status"]
        ),
        "difficulty_validation_status": btc_grunt.bin2bool(
            block_data_rows[0]["difficulty_validation_status"],
        ),
        "block_hash_validation_status": btc_grunt.bin2bool(
            block_data_rows[0]["block_hash_validation_status"],
        ),
        "nonce": block_data_rows[0]["nonce"],
        "num_txs": num_txs,
        "merkle_root_validation_status": btc_grunt.bin2bool(
            block_data_rows[0]["merkle_root_validation_status"],
        ),
        "block_hash_validation_status": btc_grunt.bin2bool(
            block_data_rows[0]["block_hash_validation_status"],
        ),
        "block_size": block_data_rows[0]["block_size"],
        "block_size_validation_status": btc_grunt.bin2bool(
            block_data_rows[0]["block_size_validation_status"]
        ),
        "version": block_data_rows[0]["block_version"],
        "tx": {}
    }
    if human_readable:
        block_dict["block_hash"] = block_data_rows[0]["block_hash_hex"]

        block_dict["prev_block_hash"] = \
        block_data_rows[0]["prev_block_hash_hex"]

        block_dict["merkle_root"] = block_data_rows[0]["merkle_root_hex"]
        block_dict["bits"] = block_data_rows[0]["bits_hex"]
    else:
        block_dict["prev_block_hash"] = btc_grunt.hex2bin(
            block_data_rows[0]["prev_block_hash_hex"]
        )
        block_dict["merkle_root"] = btc_grunt.hex2bin(
            block_data_rows[0]["merkle_root_hex"]
        )
        block_dict["bits"] = bits

    block_dict["target"] = btc_grunt.int2hex(btc_grunt.bits2target_int(bits))
    block_dict["difficulty"] = btc_grunt.bits2difficulty(bits)

    # next get the transactions
    for tx_row in block_data_rows:
        tx_num = tx_row["tx_num"]
        tx_dict = get_tx_from_db.process_tx_header_from_db(
            block_data_rows[tx_num], human_readable = False
        )
        tx_dict = get_tx_from_db.process_tx_body_from_db(
            tx_dict, human_readable
        )
        tx_dict["timestamp"] = block_data_rows[0]["block_time"]
        del tx_dict["block_hash"]
        del tx_dict["block_height"]
        del tx_dict["tx_num"]
        block_dict["tx"][tx_num] = tx_dict

    return block_dict
def sanitize_options_or_die(options):
	"""
	sanitize and update the options dict.

	note that at this point, anything that has not been specified by the user as
	a cli argument will have a value of None in the options dict - keep it this
	way, as it is easier to check for None than the check for length == 0, or
	value == 0.
	"""

	global n
	n = os.linesep if options.progress else ""

	# create a new options element to house txin hashes that are to be hunted
	# for and returned as part of the result set. this is necessary because txin
	# addresses can only be derived by looking at the address of the previous
	# txout they point to (the txin address is the same as the txout address it
	# references). this option will only get updated if the user directly
	# specifies addresses, but we always need to initialise it to empty
	# regardless. the format is {hash: [index, ..., index]}. this is the only
	# option that is not initialized to None when it is empty.
	options.TXINHASHES = {}

	if options.ADDRESSES is not None:
		if options.ADDRESSES[-1] == ",":
			raise ValueError(
				"trailing comma found in the ADDRESSES input argument. please"
				" ensure there are no spaces in the ADDRESSES input argument."
				# TODO - or are spaces allowed if quotations are used?
			)
		currency_types = {}
		first_currency = ""
		for address in options.ADDRESSES.split(","):
			currency_types[address] = get_currency(address)
			if currency_types[address] == "any":
				del currency_types[address]
				continue
			if not first_currency:
				first_currency = currency_types[address]
				continue
			if first_currency != currency_types[address]:
				raise ValueError(
					"all supplied addresses must be of the same currency:%s%s"
					% (os.linesep, pprint.pformat(currency_types, width = -1))
				)
		# convert csv string to list
		options.ADDRESSES = options.ADDRESSES.split(",")

	if options.TXHASHES is not None:
		if options.TXHASHES[-1] == ",":
			raise ValueError(
				"trailing comma found in the TXHASHES input argument. please"
				" ensure there are no spaces in the TXHASHES input argument."
			)
		for tx_hash in options.TXHASHES.split(","):
			if not btc_grunt.valid_hash(tx_hash):
				raise ValueError(
					"Supplied transaction hash %s is not in the correct format."
					% tx_hash
				)
		# convert csv string to list
		options.TXHASHES = [
			btc_grunt.hex2bin(txhash) for txhash in options.TXHASHES.split(",")
		]

	if options.BLOCKHASHES is not None:
		if options.BLOCKHASHES[-1] == ",":
			raise ValueError(
				"trailing comma found in the BLOCKHASHES input argument. please"
				" ensure there are no spaces in the BLOCKHASHES input argument."
			)
		for block_hash in options.BLOCKHASHES.split(","):
			if not btc_grunt.valid_hash(block_hash):
				raise ValueError(
					"supplied block hash %s is not n the correct format."
					% block_hash
				)
		# convert csv string to list
		options.BLOCKHASHES = [
			btc_grunt.hex2bin(blockhash) for blockhash in
			options.BLOCKHASHES.split(",")
		]

	# convert date to integer unixtime. note that ("1.0".isdigit() == False) but
	# ("123".isdigit() == True)
	if options.STARTBLOCKDATE is not None:
		if options.STARTBLOCKDATE.isdigit():
			options.STARTBLOCKDATE = int(options.STARTBLOCKDATE)
		else:
			options.STARTBLOCKDATE = get_unixtime(options.STARTBLOCKDATE)

	if options.STARTBLOCKHASH is not None:
		options.STARTBLOCKHASH = btc_grunt.hex2bin(options.STARTBLOCKHASH)

	if options.ENDBLOCKDATE is not None:
		if options.ENDBLOCKDATE.isdigit():
			options.ENDBLOCKDATE = int(options.ENDBLOCKDATE)
		else:
			options.ENDBLOCKDATE = get_unixtime(options.ENDBLOCKDATE)

	if options.ENDBLOCKHASH is not None:
		options.ENDBLOCKHASH = btc_grunt.hex2bin(options.ENDBLOCKHASH)

	num_start_options = 0
	if options.STARTBLOCKDATE is not None:
		num_start_options += 1
	if options.STARTBLOCKHASH is not None:
		num_start_options += 1
	if options.STARTBLOCKNUM is not None:
		num_start_options += 1
	if num_start_options > 1:
		raise ValueError(
			"only one of options --start-blockdate, --start-blockhash and"
			" --start-blocknum can be specified."
		)
	num_end_options = 0
	if options.ENDBLOCKDATE is not None:
		num_end_options += 1
	if options.ENDBLOCKHASH is not None:
		num_end_options += 1
	if options.ENDBLOCKNUM is not None:
		num_end_options += 1
	if num_end_options > 1:
		raise ValueError(
			"only one of options --end-blockdate, --end-blockhash and"
			" --start-blocknum can be specified."
		)
	if (
		(options.LIMIT) and
		(num_end_options > 0)
	):
		raise SyntaxError(
			"if option --limit (-L) is specified then neither option"
			" --end-blockdate, nor --end-blockhash, nor --end-blocknum can also"
			" be specified."
		)
	if not num_start_options:
		options.STARTBLOCKNUM = 0 # go from the start

	if not num_end_options:
		options.ENDBLOCKNUM = "end" # go to the end

	permitted_output_formats = [
		"MULTILINE-JSON",
		"SINGLE-LINE-JSON",
		"MULTILINE-XML",
		"SINGLE-LINE-XML",
		"BINARY",
		"HEX"
	]
	if (
		(options.FORMAT is None) or
		(options.FORMAT not in permitted_output_formats)
	):
		raise ValueError(
			"option --output-format (-o) must be either %s."
			% lang_grunt.list2human_str(permitted_output_formats)
		)

	# ORPHAN_OPTIONS is never None - it has a default value
	options.ORPHAN_OPTIONS = options.ORPHAN_OPTIONS.upper() # capitalize
	permitted_orphan_options = [
		"NONE",
		"ALLOW",
		"ONLY"
	]
	if (options.ORPHAN_OPTIONS not in permitted_orphan_options):
		raise ValueError(
			"option --orphan-options must be either %s."
			% lang_grunt.list2human_str(permitted_orphan_options)
		)

	if (
		(options.OUTPUT_TYPE is None) and
		(options.validate is None)
	):
		raise ValueError(
			"either option --output-type (-t) or option --validate (-v) must"
			" be specified."
		)

	if options.OUTPUT_TYPE is not None:
		options.OUTPUT_TYPE = options.OUTPUT_TYPE.upper() # capitalize
		permitted_output_types = [
			"BLOCKS",
			"TXS",
			"BALANCES"
		]
		if options.OUTPUT_TYPE not in permitted_output_types:
			raise ValueError(
				"option --output-types (-t) must be either %s."
				% lang_grunt.list2human_str(permitted_output_types)
			)

		if options.OUTPUT_TYPE == "BALANCES":
			if options.FORMAT == "BINARY":
				raise ValueError(
					"Option --output-type (-t) cannot be set to BALANCES while"
					" option --output-format (-o) is set to BINARY."
				)
			if options.ADDRESSES is None:
				raise ValueError(
					"when option --output-type (-t) is set to BALANCES then"
					" ADDRESSES must also be specified via option --addresses"
					" (-a)."
				)

	return options
	),
	("30 06 02 02 7f 02 01 7f 01", "wrong <length r>"),
	("30 06 02 01 7f 02 02 7f 01", "<length r> and <length s> do not add up"),
	("30 06 02 00    02 01 7f 01 00", "no r (append 00 otherwise too short)"),
	("30 06 02 01 ff 02 01 7f 01", "r is ambiguously negative"),
	("30 07 02 02 00 01 02 01 7f 01", "r starts with 00 and is not negative"),
	(
		"30 06 02 01 7f 00 01 7f 01",
		"wrong placeholder 3 byte, otherwise correct"
	),
	("30 06 02 01 7f 02 00    01 00", "no s (append 00 otherwise too short)"),
	("30 06 02 01 7f 02 01 ff 01", "s is ambiguously negative"),
	("30 07 02 01 7f 02 02 00 01 01", "s starts with 00 and is not negative"),
]
for (i, (der_signature_human, error_description)) in enumerate(inputs):
	der_signature_bin = btc_grunt.hex2bin(der_signature_human.replace(" ", ""))
	if verbose:
		print """
================== test for incorrect der signature encoding %s ================
ensure %s. der signature: %s
""" % (i, error_description, der_signature_human)

	res = btc_grunt.valid_der_signature(der_signature_bin, explain = True)
	if res is True:
		raise Exception(
			"function valid_der_signature() failed to detect the error in der"
			" signature bytes %"
			% der_signature_human
		)
	else:
		if verbose:
def process_range(block_height_start, block_height_end):

    print "updating all txin funds between block %d and %d by copying over" \
    " the funds being spent from the previous txouts..." % \
    (block_height_start, block_height_end)
    rows_updated = queries.update_txin_funds_from_prev_txout_funds(
        block_height_start, block_height_end
    )
    print "done. %d rows updated\n" % rows_updated

    # note that txin.tx_change_calculated and txout.tx_change_calculated are
    # used to speed up the query
    print "updating the change funds for each tx between block %d and %d..." \
    % (block_height_start, block_height_end)
    rows_updated = queries.update_txin_change_from_prev_txout_funds(
        block_height_start, block_height_end
    )
    print "done. %d rows updated\n" % rows_updated

    print "marking off the txins that have been used to calculate the change" \
    " funds for each tx between block %d and %d..." \
    % (block_height_start, block_height_end)
    rows_updated = queries.update_txin_change_calculated_flag(
        block_height_start, block_height_end
    )
    print "done. %d rows updated\n" % rows_updated

    print "marking off the txouts that have been used to calculate the change" \
    " funds for each tx between block %d and %d..." \
    % (block_height_start, block_height_end)
    rows_updated = queries.update_txout_change_calculated_flag(
        block_height_start, block_height_end
    )
    print "done. %d rows updated\n" % rows_updated

    print "updating the coinbase change funds for each coinbase txin between" \
    " block %d and %d..." \
    % (block_height_start, block_height_end)
    row_count = queries.update_coinbase_change_funds(
        block_height_start, block_height_end
    )
    print "done. %d rows updated\n" % row_count

    # the following code can only be tested once a non-standard txout script is
    # found:
    # the logic here mimics validate_tx_scripts.py and update_addresses_db.py
    #print "extracting the valid pubkeys for each txin and txout script pair" \
    #" where the txin belongs to a block between %d and %d..." \
    #% (block_height_start, block_height_end)
    #all_rows = mysql_grunt.quick_fetch("""
    #    select
    #    block.timestamp,
    #    block.version,
    #    block.block_height,
    #    block.
    #    from blockchain_txins txin
    #    inner join blockchain_txouts txout on (
    #        txin.prev_txout_hash = txout.tx_hash
    #        and txin.prev_txout_num = txout.txout_num
    #    )
    #    inner join blockchain_txs tx on txin.tx_hash = tx.tx_hash
    #    inner join blockchain_headers block on tx.block_hash = block.block_hash
    #    where txout.pubkey is null
    #    and txout.address is null
    #    and txout.alternate_address is null
    #    and txin.non_standard_pubkey_extraction_attempted = false
    #    and tx.tx_num != 0
    #    and block_height >= %s
    #    and block_height < %s
    #""", (block_height_start, block_height_end))
    #num_txins = mysql_grunt.cursor.rowcount
    #print "found %d txins which require pubkey extraction" % num_txins

    #rows_updated = 0 # init
    #skip_checksig = False
    #bugs_and_all = True
    #explain = True
    #for (i, row) in enumerate(all_rows):
    #    block_time = row["blocktime"]
    #    block_version = row["version"]
    #    tx =
    #    prev_tx0 = 
    #    script_eval_data = verify_script(
    #        block_time, tx, txin_num, prev_tx0, block_version, skip_checksig,
    #        bugs_and_all, explain
    #    )

    #    for on_txin_num in range(len(tx_rpc_dict["vin"])):

    #    pubkey_hex = row["pubkey_hex"]
    #    (uncompressed_address, compressed_address) = btc_grunt.pubkey2addresses(
    #        btc_grunt.hex2bin(pubkey_hex)
    #    )
    #    # if there is only one valid pubkey then update the row
    #    mysql_grunt.cursor.execute("""
    #        update blockchain_txouts
    #        set address = %s,
    #        alternate_address = %s
    #        where pubkey = unhex(%s)
    #    """, (uncompressed_address, compressed_address, pubkey_hex))
    #    rows_updated += mysql_grunt.cursor.rowcount
    #    progress_meter.render(
    #        100 * i / float(num_pubkeys),
    #        "updated addresses for %d unique pubkeys (of %d pubkeys)" \
    #        % (i, num_pubkeys)
    #    )

    #progress_meter.render(100, "updated pubkeys for %d txins\n" % num_txins)
    #print "done. %d rows updated\n" % mysql_grunt.cursor.rowcount

    print "updating the address and alternate address for txout pubkeys" \
    " between block %d and %d..." % (block_height_start, block_height_end)
    all_rows = queries.get_pubkeys_with_uncalculated_addresses(
        block_height_start, block_height_end
    )
    num_pubkeys = len(all_rows)
    print "found %d unique pubkeys without addresses" % num_pubkeys

    rows_updated = 0 # init
    for (i, row) in enumerate(all_rows):
        pubkey_hex = row["pubkey_hex"]
        (uncompressed_address, compressed_address) = btc_grunt.pubkey2addresses(
            btc_grunt.hex2bin(pubkey_hex)
        )
        rows_updated += queries.update_txin_addresses_from_pubkey(
            uncompressed_address, compressed_address, pubkey_hex
        )
        progress_meter.render(
            100 * i / float(num_pubkeys),
            "updated addresses for %d/%d unique pubkeys" \
            % (i, num_pubkeys)
        )

    progress_meter.render(
        100, "updated addresses for %d unique pubkeys\n" % num_pubkeys
    )
    print "done. %d rows updated (some pubkeys may exist in multiple rows)\n" \
    % rows_updated

    print "updating all txin addresses between block %d and %d by copying" \
    " over the addresses from the previous txouts..." \
    % (block_height_start, block_height_end)
    rows_updated = queries.update_txin_addresses_from_prev_txout_addresses(
        block_height_start, block_height_end
    )
    print "done. %d rows updated\n" % rows_updated