Как преобразовать байты scriptPubKey в биткойн-адрес?

В настоящее время я пытаюсь разобрать блокчейн с помощью pyblockchain . Моя проблема в том, что я не могу правильно закодировать scriptPubKey, хотя я не знаю, что я мог сделать неправильно.

Ниже вы можете увидеть, как я обхожу блокчейн:

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

Если я в своем блокноте Jupyter взгляну на outp, я найду для

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'

этот:

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

и это недействительный биткойн-адрес .

Судя по всему, биткойн-адреса должны быть закодированы в Base58Check , однако это тоже не работает:

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

Так что я делаю неправильно здесь?

Ответы (1)

Вы не учитываете коды операций в строке pub_key. Например, script_pub_key может быть OP_DUP OP_HASH160 [pub_key] ... и вам нужно вытащить pub_key.
Этот пример кода показывает адреса, вы можете проверить их с помощью обозревателя блоков для того же идентификатора транзакции. Обратите внимание, что байт после OP_HASH160 указывает длину pub_key в байтах после него, поэтому его также необходимо пропустить для генерации адреса.


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()

Пример вывода для первой транзакции в вашем блочном файле:

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

Коды операций здесь: https://en.bitcoin.it/wiki/Script , информация о scriptpubkey : https://en.bitcoin.it/wiki/Transaction очень надежен, поскольку впоследствии не проверяет другие OP-коды, другие возможные платежные сценарии и т. д.