I am running a node on my laptop and decided to further explore the blocks on my local machine. Wrote a python script that takes a block height as the only input parameter and it extracts all of the transaction IDs and summarizes many of the data points in each block. This is clearly data that has been put together elsewhere, but I wanted to learn more by digging in myself. Thought I would share my progress and get some feedback on the script and some of my findings. For a report on block 802191, the script is invoked like this:
(Still working out vin and vout values above.)
The end of the output identifies the largest transactions by value because it sorts all txs by value in ascending order:
One immediate data point that jumped out - a very large number of tiny transactions. 439 txs with a value of 0.00000294. Every block I have looked at with more than 2k transactions has hundreds or thousands of these dust transactions. Block 802193 has 4508 txs with 0.00000294. And so on. What are these??
I plan on digging in much deeper, and this is the very beginning of my journey. Here is the code below in case anyone is interested:
import sys from bitcoin.rpc import RawProxy def fetch_block(height): proxy = RawProxy() block_hash = proxy.getblockhash(height) block = proxy.getblock(block_hash, 2) # '2' for verbosity return block def get_transaction_details(txid): proxy = RawProxy() raw_tx = proxy.getrawtransaction(txid) decoded_tx = proxy.decoderawtransaction(raw_tx) total_out_value = sum(out['value'] for out in decoded_tx['vout']) # input_addresses = [in_data['prev_out']['addr'] for in_data in decoded_tx['vin'] if 'addr' in in_data['prev_out']] input_addresses = [in_data['prev_out']['addr'] for in_data in decoded_tx['vin'] if 'prev_out' in in_data and 'addr' in in_data['prev_out']] output_addresses = [out['scriptPubKey']['addresses'][0] for out in decoded_tx['vout'] if 'addresses' in out['scriptPubKey']] is_coinbase = len(decoded_tx['vin']) == 1 and 'coinbase' in decoded_tx['vin'][0] number_of_inputs = len(decoded_tx['vin']) number_of_outputs = len(decoded_tx['vout']) return total_out_value, input_addresses, output_addresses, is_coinbase, number_of_inputs, number_of_outputs if __name__ == '__main__': set_height = int(sys.argv[1]) block = fetch_block(set_height) print(f"Block Height: {set_height}") print(f"Block Time: {block['time']}") print(f"Number of Confirmations: {block['confirmations']}") print(f"Difficulty: {block['difficulty']}") print(f"MerkleRoot: {block['merkleroot']}") print(f"Nonce: {block['nonce']}") print(f"Size: {block['size']}") print(f"Weight: {block['weight']}") print(f"Number of Transactions: {len(block['tx'])}") print(f"Median Time: {block['mediantime']}") print(f"Previous Block Hash: {block['previousblockhash']}") if 'nextblockhash' in block: print(f"Next Block Hash: {block['nextblockhash']}") transactions = [] unique_input_addresses, unique_output_addresses = set(), set() for tx in block['tx']: value, input_addresses, output_addresses, is_coinbase, number_of_inputs, number_of_outputs = get_transaction_details(tx['txid']) unique_input_addresses.update(input_addresses) unique_output_addresses.update(output_addresses) transactions.append((tx['txid'], value, is_coinbase, number_of_inputs, number_of_outputs)) print(f"Number of Unique Input Addresses: {len(unique_input_addresses)}") print(f"Number of Unique Output Addresses: {len(unique_output_addresses)}") print('Transactions (sorted by value in ascending order):') for tx, value, is_coinbase, number_of_inputs, number_of_outputs in sorted(transactions, key=lambda x: x[1]): print(f"TXID: {tx}, Value: {value}, Is Coinbase: {is_coinbase}, Number of Inputs: {number_of_inputs}, Number of Outputs: {number_of_outputs}")
Thanks for sharing this on NOSTR. It's nice to look at code from a functional point.
reply