0

I am currently trying myself in parsing the blockchain using pyblockchain. My problem is that I am not able to encode the scriptPubKey correctly - although I don't know what I could possibly do wrong.

Below you can see how I traverse the blockchain:

from blockchain.reader import BlockchainFileReader

import hashlib
import base58

block_reader = BlockchainFileReader('/media/Data/btc/blocks/blk00325.dat')

count = 0

for block in block_reader:    
    count +=1        
    for t in block.transactions:
        for outp in t.outputs:
            addr = base58.b58encode(outp.script_pub_key)
            if addr.startswith('1'):
                print(addr)        
    if count >= 5:
        break

If I, in my Jupyter notebook, take a look at outp, I'll find for

outp.script_pub_key
>> b'v\xa9\x14\x1e\xbev\x83\xceJd\xad\xc9\x17\xe9\xb1\x93\x7f\x12&Q\xcb\xab\xa1\x88\xac'

this:

base58.b58encode(outp.script_pub_key)
>> 'pkJBVCg6k54E7ZiP7cvxbCvtN9aY9zEcgK'

and this is not a valid bitcoin address.

Apparently, bitcoin addresses are supposed to be encoded i Base58Check - however, that does not work either:

base58.b58encode_check(outp.script_pub_key)
>> '6PSJQapdQn8VeG9SBuZdH8q2ysyP4ND6dmspzLZb'

So what am I doing wrong here?

1

You are not considering the op codes in the pub_key string. For example, a script_pub_key could be OP_DUP OP_HASH160 [pub_key] ... and you have to pull out the pub_key.
This sample code shows the addresses, you can check them against a block explorer for the same transaction id. Note that the byte after OP_HASH160 gives the length of the pub_key in bytes after it, so it needs to be skipped as well to generate the address.


import sys
import base58
import hashlib
import binascii
from blockchain.reader import BlockchainFileReader
block_reader=BlockchainFileReader('/var/data/bitcoin-data/blocks/blk00325.dat')
satochi_convert=1e8
def sha256(x):
    h=hashlib.new('sha256')
    h.update(x)
    return h.digest()

def hashStr(buffer): return binascii.hexlify(buffer)

for block in block_reader: #block has .header, .transactions for iter,tx in enumerate(block.transactions): print(' Transaction (txn_hash):{} {}'.format(type(tx.txn_hash),tx.txn_hash)) for x in tx.outputs: script_pub_key_str=hashStr(x.script_pub_key) if script_pub_key_str[0:4]==b'76a9': #This is a pubkeyhash bytes=x.script_pub_key[2] #number of bytes in the pub_key assert bytes==20 public_key = x.script_pub_key[3:3+bytes] #20 bytes z=b'\00'+public_key #checksum=sha256(sha256(z))[:4] #address1=base58.b58encode(z + checksum) address2=base58.b58encode_check(z) # adds checksum for you print(' output value {:<20} address {}'.format(float(x.value)/satochi_convert,address2)) elif script_pub_key_str[0:2]==b'a9': #this is a scripthash (pay-to-script address) bytes=x.script_pub_key[1] #number of bytes in the pub_key assert bytes==20 public_key = x.script_pub_key[2:2+bytes] #20 bytes z=b'\05'+public_key #used for mainnet address2=base58.b58encode_check(z) print(' output value {:<20} address {}'.format(float(x.value)/satochi_convert,address2)) else: print(' output value {:<20} other {}'.format(float(x.value)/satochi_convert,script_pub_key_str)) print()

Sample output for first transaction in your block file is:

 Transaction (txn_hash): cc728403552d5e1fddf06e6a7e8552353f315be6c1a43a8e64e4d11b081d4ca3
  output value 25.17686501          address 1N6LrEDiHuFwSyJYj2GedZM2FGk7kkLjn
  output value 0.22864963           address 1Hr9uwzwXWpjQDNUWdZ1i9qnoSpnniJe4U
....

OP codes here: https://en.bitcoin.it/wiki/Script, scriptpubkey info: https://en.bitcoin.it/wiki/Transaction NOTE: this is just an example of how to calculate addresses, it is not very robust as it does not check other OP codes afterwards, other possible payment scripts, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.