1

We are using jgarzik/python-bitcoinrpc and in some cases curl to retrieve data from bitcoin core using RPC.

However, for some txns where pubkey is used, bitcoin-cli/rpc gives no address in corresponding vout.

e.g. for bitcoin-cli getrawtransaction 835fffaae22a3932882c50e8755407dc6dba4f41350271405765660beaa45a63 2 :

  "vout": [
    {
      "value": 0.00010000,
      "n": 0,
      "scriptPubKey": {
        "asm": "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1 OP_CHECKSIG",
        "hex": "2103f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1ac",
        "type": "pubkey"
      }
    },
    {
      "value": 0.00010000,
      "n": 1,
      "scriptPubKey": {
        "asm": "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1 OP_CHECKSIG",
        "hex": "2103f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1ac",
        "type": "pubkey"
      }
    },

Is there any way to retrieve addresses where script type is pubkey using bitcoin-cli/RPC ?

Thanks.

2 Answers 2

3

The ScriptPubKey 2103f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1ac is a pay-to-public-key. There is no defined address for this output type. There is therefore no way to retrieve addresses when type is pubkey.

7
  • Yes, I know that the mentioned ScriptPubKey is a pay-to-public-key for which there is no defined address for this output type which I mentioned in question too. However, since almost all Bitcoin Explorers are able to display the address for corresponding pub-key, I was wondering if there was a simpler way to retrieve the same using RPC/bitcoin-cli. Yes, I was aware of other solutions like github.com/alecalve/python-bitcoin-blockchain-parser which directly read the data from blocks (.dat files) and calculate addresses from corresponding key.
    – curious
    May 3, 2023 at 5:49
  • 1
    You really shouldn't. It's a dated, confusing practice. More modern block explorers do not show P2PKH addresses for P2PK outputs, FWIW. May 3, 2023 at 6:40
  • @pieter-wuille Since most of the explorers I used like blockchain.com, blockchair.com, blockcypher.com etc. were displaying the corresponding addresses, I believed that the process is legitimate. Can you pls explain it a bit further why it is a dated and confusing practice ?
    – curious
    May 3, 2023 at 12:26
  • 2
    For example blockstream.info and mempool.space correctly don't show any address for P2PK. Why is it confusing? Simply because those outputs don't have an address - the address corresponds to a different output. It dates from a time when P2PK and P2PKH were the only types used in practice, and addresses were more a way to indicate "identity" rather than "way of conveying a payment output". A block explorer started it, and others copied it for compatibility, but it is nonsensical. May 3, 2023 at 13:06
  • 2
    @curious I've written more about the history on bitcoin.stackexchange.com/a/117426/208. TL;DR: the meaning of the word address has dramatically shifted starting in 2012. May 4, 2023 at 5:12
0

If you want to try something beyond using the RPC, you can calculate addresses.

In the ScriptPubKey object, remove 21 from the start and ac from the end. The 21 is hex to indicate the length of the pubkey. ac is the opcode for OP_CHECKSIG.

You will be left with your pubkey 03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1. From here you can convert it to a base58 encoded address.

An example of how to do this in with python

import bitcoin
from bitcoin.core import x
from bitcoin.core import CoreMainParams
from bitcoin.wallet import P2PKHBitcoinAddress

def calc_addr_tool(pubkey, pubtype, p2shtype, wiftype):
    class CoinParams(CoreMainParams):
        MESSAGE_START = b'\x24\xe9\x27\x64'
        DEFAULT_PORT = 7770
        BASE58_PREFIXES = {'PUBKEY_ADDR': int(pubtype),
                           'SCRIPT_ADDR': int(p2shtype),
                           'SECRET_KEY': int(wiftype)}
    bitcoin.params = CoinParams

    try:
        address = str(P2PKHBitcoinAddress.from_pubkey(x(pubkey)))
        return {
            "pubkey": pubkey,
            "pubtype": pubtype,
            "p2shtype": p2shtype,
            "wiftype": wiftype,
            "address": address
        }

    except Exception as e:
        logger.error(f"[calc_addr_tool] Exception: {e}")
        return {"error": str(e)}

(from https://github.com/smk762/kmd_ntx_stats_docker/blob/master/code/kmd_ntx_api/lib_base58.py#L242-L263)

For a segwit address try

from bip32utils import Base58

def p2wpkh_in_p2sh_addr(pk, testnet=False):
    """
    Compressed public key (hex string) -> p2wpkh nested in p2sh address. 'SegWit address.'
    """
    # Script sig is just PUSH(20){hash160(cpk)}
    push_20 = bytes.fromhex("0014")
    script_sig = push_20 + hash160_bytes(bytes.fromhex(pk))

    # Address is then prefix + hash160(script_sig)
    prefix = b"\xc4" if testnet else b"\x05"
    address = Base58.check_encode(prefix + hash160(script_sig))
    return address

(from https://matthewdowney.github.io/create-segwit-address.html)

Be careful with any output and confirm with sending a small amount first.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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