Bitcoinjs-lib: Decoding pubkey addresses

Created on 31 Jan 2018  路  6Comments  路  Source: bitcoinjs/bitcoinjs-lib

I was trying to get an address from an outputscript using address.fromOutputScript; but when I try it with a pubkey script (OP_DATA() + OP_CHECKSIG), the library fails with the error:

02397df78c9c3fecbcbcee12025230fc4b30e6e617f5fc9c10513eebd0cf4b327d OP_CHECKSIG has no matching Address

Inspecting the library code I found the problem here: https://github.com/bitcoinjs/bitcoinjs-lib/blob/413495b101e6dec80b4a310a52ab1a28cd9f7bec/src/address.js#L51 the pubkey template is not used. I know that pubkey addresses are deprecated, but they are used on coinbase transactions. How should I do to decode these type of addresses?

My solution is this, but it seems too tricky:

let s = bitcoinjs.script.pubKey.output.decode(txout.script);
s = bitcoinjs.crypto.sha256(s);
s = bitcoinjs.crypto.ripemd160(s);
spendableby = bitcoinjs.address.toBase58Check(bitcoinjs.script.compile(s), _network.pubKeyHash);
how to / question / docs

Most helpful comment

  • <> represents data or script
  • {} represents data that must prefixed by OP_PUSHDATA
  • [] represents multiple {}

Standard Scripts

PubKey (pay-to-pubkey / P2PK)

Address: N/A
scriptPubKey: {pubKey} OP_CHECKSIG
scriptSig: {signature}

PubKeyHash (pay-to-pubkeyhash / P2PKH)

Address: Base58(0x00 <hash160 pubKey> <checksum>)
scriptPubKey: OP_DUP OP_HASH160 {hash160(pubKey)} OP_EQUALVERIFY OP_CHECKSIG
scriptSig: {signature} {pubKey}

ScriptHash (pay-to-scripthash / P2SH)

Address: Base58(0x05 <hash160 script> <checksum>)
scriptPubKey: OP_HASH160 {hash160(scriptPubKey2)} OP_EQUAL
scriptSig: [scriptSig2 ...] {scriptPubKey2}

MultiSig (pay-to-multisig / P2MS)

Address: N/A
scriptPubKey: m [pubKeys ...] n OP_CHECKMULTISIG
scriptSig: OP_0 [signatures ...]

Witness PubKeyHash (pay-to-witness-pubkeyhash / P2WPKH)

Address: Bech32('bc' {hash160(pubKey)})
scriptPubKey: 0 {hash160(pubKey)}
scriptSig: (empty)
witness: {signature} {pubKey}

Witness ScriptHash (pay-to-witness-scripthash / P2WSH)

Address: Bech32('bc' {sha256(script)})
scriptPubKey: 0 {sha256(scriptPubKey2)}
scriptSig: (empty)
witness: [scriptSig2 ...] {scriptPubKey2}

Non-standard Scripts

OP_RETURN

Address: N/A
scriptPubKey: OP_RETURN {data}
scriptSig: N/A

Anyone-can-spend

Address: N/A
scriptPubKey: N/A
scriptSig: OP_TRUE

Transaction-puzzle

Address: N/A
scriptPubKey: OP_HASH256 {hash} OP_EQUAL
scriptSig: <data>

Ref https://gist.github.com/dcousens/1d8c24d01e3f34bee453

All 6 comments

the pubkey template is not used. I know that pubkey addresses are deprecated

They aren't deprecated, they aren't even a thing.
Blame block explorers for this.

An address is a user-space convention for wrapping up an output script for sharing.
It is a two way encoding, it can be encoded (for sharing), and decoded (for sending to!).

Deriving an address from a P2PK script isn't wrapping it up, or encoding it.
It is simply the derivation of a P2PKH script (and address) from the public key, ignoring the context.

If you send to an address derived from a P2PK script, you are sending to a P2PKH script.

P2PK does not have an equivalent base58 address.

Your "solution" additionally shouldn't work, as you are taking the HASH_160 of {pubKey} OP_CHECKSIG.
Be careful to always verify you can spend your output scripts before funding them.

See https://github.com/bitcoinjs/bitcoinjs-lib/issues/586#issuecomment-224508501

  • <> represents data or script
  • {} represents data that must prefixed by OP_PUSHDATA
  • [] represents multiple {}

Standard Scripts

PubKey (pay-to-pubkey / P2PK)

Address: N/A
scriptPubKey: {pubKey} OP_CHECKSIG
scriptSig: {signature}

PubKeyHash (pay-to-pubkeyhash / P2PKH)

Address: Base58(0x00 <hash160 pubKey> <checksum>)
scriptPubKey: OP_DUP OP_HASH160 {hash160(pubKey)} OP_EQUALVERIFY OP_CHECKSIG
scriptSig: {signature} {pubKey}

ScriptHash (pay-to-scripthash / P2SH)

Address: Base58(0x05 <hash160 script> <checksum>)
scriptPubKey: OP_HASH160 {hash160(scriptPubKey2)} OP_EQUAL
scriptSig: [scriptSig2 ...] {scriptPubKey2}

MultiSig (pay-to-multisig / P2MS)

Address: N/A
scriptPubKey: m [pubKeys ...] n OP_CHECKMULTISIG
scriptSig: OP_0 [signatures ...]

Witness PubKeyHash (pay-to-witness-pubkeyhash / P2WPKH)

Address: Bech32('bc' {hash160(pubKey)})
scriptPubKey: 0 {hash160(pubKey)}
scriptSig: (empty)
witness: {signature} {pubKey}

Witness ScriptHash (pay-to-witness-scripthash / P2WSH)

Address: Bech32('bc' {sha256(script)})
scriptPubKey: 0 {sha256(scriptPubKey2)}
scriptSig: (empty)
witness: [scriptSig2 ...] {scriptPubKey2}

Non-standard Scripts

OP_RETURN

Address: N/A
scriptPubKey: OP_RETURN {data}
scriptSig: N/A

Anyone-can-spend

Address: N/A
scriptPubKey: N/A
scriptSig: OP_TRUE

Transaction-puzzle

Address: N/A
scriptPubKey: OP_HASH256 {hash} OP_EQUAL
scriptSig: <data>

Ref https://gist.github.com/dcousens/1d8c24d01e3f34bee453

ok got it

@dakk would you mind posting final solution for this ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

prahaladbelavadi picture prahaladbelavadi  路  3Comments

zhaozhiming picture zhaozhiming  路  3Comments

coingeek picture coingeek  路  4Comments

rbndg picture rbndg  路  3Comments

tuyennvtb picture tuyennvtb  路  3Comments