3

The createrawtransaction RPC takes as parameters the source TX ID and the UTXO index (to create the new unsigned input) and the destination address and amount of bitcoins (to create the new output).

In the output created, the scriptPubKey is a standard P2PKH script containing the pubkey hash. What I don't understand is...if createrawtransaction only received the address, how did it get the pubkey hash from it?

I understand that going from the pubkey hash to the address is pretty easy:

[PubKey Hash] -> Add network bytes -> SHA-256 -> SHA-256 -> checksum -> Base58Check -> [BTC Address]

So how does createrawtransaction go the other way from BTC Address -> PubKey Hash?

To show this, you can follow my steps using this web based interface of Bitcoin API:

http://chainquery.com/bitcoin-api/createrawtransaction

In that page, let's use this transaction for the Outpoints

f0f5ad66b8c09a8b5ec5a379439281a32fc446e0185c3b1b854880d3dc49d065

and output index 3

Now, for the Outputs, use this address

183XLwHyKJGCD9Dj9Pafv2zoqfiXWd5WMZ

and put 0.00159468 as the amount of BTC.

Click Execute Command and you should get this result

{
"result": "020000000165d049dcd38048851b3b5c18e046c42fa381924379a3c55e8b9ac0b866adf5f00300000000ffffffff01ec6e0200000000001976a9144d430ac5863757f5dc45f475d7cd2ccf43cf784588ac00000000",
"error": null,
"id": null

}

Now, let's decode this transaction with decoderawtransaction RPC

http://chainquery.com/bitcoin-api/decoderawtransaction

Just put there the "result" field value you got from the previous response. Click Execute Command and you'll get the raw transaction

{
"result": {
    "txid": "8d02780fbd265fdeaf08195b5488fc309270a8ff9d23043d0dfc9a0d8599a01c",
    "hash": "8d02780fbd265fdeaf08195b5488fc309270a8ff9d23043d0dfc9a0d8599a01c",
    "version": 2,
    "size": 85,
    "vsize": 85,
    "locktime": 0,
    "vin": [
        {
            "txid": "f0f5ad66b8c09a8b5ec5a379439281a32fc446e0185c3b1b854880d3dc49d065",
            "vout": 3,
            "scriptSig": {
                "asm": "",
                "hex": ""
            },
            "sequence": 4294967295
        }
    ],
    "vout": [
        {
            "value": 0.00159468,
            "n": 0,
            "scriptPubKey": {
                "asm": "OP_DUP OP_HASH160 4d430ac5863757f5dc45f475d7cd2ccf43cf7845 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a9144d430ac5863757f5dc45f475d7cd2ccf43cf784588ac",
                "reqSigs": 1,
                "type": "pubkeyhash",
                "addresses": [
                    "183XLwHyKJGCD9Dj9Pafv2zoqfiXWd5WMZ"
                ]
            }
        }
    ]
},
"error": null,
"id": null

}

If you see the scriptPubKey script, i.e.

OP_DUP OP_HASH160 4d430ac5863757f5dc45f475d7cd2ccf43cf7845 OP_EQUALVERIFY OP_CHECKSIG

you can see the pubkey hash is there

4d430ac5863757f5dc45f475d7cd2ccf43cf7845

and this pubkey hash matches the address given as parameter in the beginning. You can verify this by pasting the pubkey hash in step #3 in this page:

http://gobittest.appspot.com/Address

and clicking Send. You should get this address

183XLwHyKJGCD9Dj9Pafv2zoqfiXWd5WMZ

in step #9.

So, my question once again...how did createrawtransaction go from the address to the pubkey hash if it didn't have the public key?

3 Answers 3

4

I think I can answer my own question...

I just saw the code of createrawtransaction and what it does is a Base58 decode, remove the checksum and network bytes and it gets the pubkey hash.

2
  • Thanx for great synthetised response. I am github-diving into bitcoin/src in order to check and find out where the function "f" that makes pubkeyHash=f(address) is. Where should I look for? I'd like to see that base58 decode and bytes removing. Thank you. Jan 9, 2020 at 19:22
  • 1
    @JoséCrespoBarrios I'm glad my answer was useful. I believe the function you are looking for is DecodeDestination. You can find it here: github.com/bitcoin/bitcoin/blob/master/src/key_io.cpp#L72
    – xtian777x
    Jan 11, 2020 at 0:41
1

An address encodes the data necessary to produce the scriptPubKey for an output. In the case of 1... addresses, these encode the pubkey hash using Base58 Check encoding. Because an encoding is bidirectional, you can encode the pubkey hash with it, and then decode the Base58 string to get the pubkey hash as a binary string.

Furthermore, the encodings also include a version number which indicates additional information necessary to construct the entire scriptPubKey. For 1... addresses, the version number is 0 and is reflected in the address as the leading 1 character. The version number 0 indicates that the resulting scriptPubKey should be a Pay to Pubkey Hash type script so the wallet constructs a scriptPubKey using the P2PKH template and dropping in the provided pubkey hash into the correct place.

0

Bitcoin Core has different methods for the different address formats, but you don't need to worry about that, there are generic functions that handle complexity internally. For example:

CMutableTransaction myTx;
myTx.vin.resize(1);
myTx.vin[0].prevout.SetNull();

const string addressString = "my_address";
CAmount amount = 10;
string error_str;
CTxDestination destination = DecodeDestination(addressString, error_str);

// You don't need much more checks than the following
if (!IsValidDestination(destination)) {
   return error(error_str);
}

CScript pubKeyHash = GetScriptForDestination(destination);
myTx.vout[0] = CTxOut(amount, pubKeyHash);

Above you see how DecodeDestination() and GetScriptForDestination() do the hard job for us, then CTxOut() takes care of the last mile.

For an implementation of the above, refer to: https://github.com/devcoin/core/blob/4ec355c0e42108afcfc8d2467fdeed0119a4123b/src/miner.cpp#L163

Your Answer

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

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