Native Segwit P2WPKH

Read more about P2WPKH in BIP141

P2WPKH is the native Segwit version of a Pay to Public Key hash.

The scripts and script data are spread out as follows

witness:      <signature> <pubkey>
scriptSig:    (empty)
scriptPubKey: 0 <20-byte-key-hash>

Each Bitcoin full node will parse the scriptPubKey and check the witness program size.
If it is 20 bytes long, it is interpreted as a P2WPKH program.

Then each validating node

  • checks that Witness is <sig> <pubKey>
  • HASH160 of the public key match the 20-byte witness program
  • verify the signature against the public key with CHECKSIG operation

Comparing with a traditional P2PKH output, the P2WPKH equivalent occupies 3 less bytes in the scriptPubKey, and moves
the signature and public key from scriptSig to witness.

Spend a Native Segwit P2WPKH UTXO

To follow along this tutorial and enter the commands step-by-step

  • Type node in a terminal after cd into ./code for a Javascript prompt
  • Open the Bitcoin Core GUI console or use bitcoin-cli for the Bitcoin Core commands
  • Use bx aka Libbitcoin-explorer as a handy complement

Let's spend a native Segregated Witness P2WPKH output and create a new legacy P2PKH output.

Create a UTXO to spend from

Import libraries, test wallets and set the network

const bitcoin = require('bitcoinjs-lib')
const { alice, bob } = require('./wallets.json')
const network = bitcoin.networks.regtest

Send 1 BTC to Alice_0 native Segwit P2WPKH address in order to create a P2WPKH UTXO.

Check out Generating and Importing Wallets and your wallets.json
file in the code directory. Replace the address if necessary.

$ sendtoaddress bcrt1qlwyzpu67l7s9gwv4gzuv4psypkxa4fx4ggs05g 1

Get the output index so that we have the outpoint (txid / vout).

Find the output index (or vout) under details > vout.

$ gettransaction "txid"

Creating the transaction

Now let's spend the UTXO with BitcoinJS.

Create a bitcoinJS key pair object for Alice_0, the spender of our new UTXO, and the only one capable of spending it.

const keyPairAlice0 = bitcoin.ECPair.fromWIF(alice[0].wif, network)
const p2wpkhAlice0 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice0.publicKey, network})

Create a key pair object and a P2PKH address for the recipient Bob_0.

const keyPairBob0 = bitcoin.ECPair.fromWIF(bob[0].wif, network)
const p2pkhBob0 = bitcoin.payments.p2pkh({pubkey: keyPairBob0.publicKey, network})

Create a BitcoinJS transaction builder object.

const txb = new bitcoin.TransactionBuilder(network)

Create the input by providing the outpoint but also the script of the previous transaction (vout > scriptPubKey > hex).
Adding the prevTxScript is a specificity of P2WPKH spending.

The script is composed as follow: <version program 00> PUSHBYTES_14
The HASH160 of the public key must match the 20-bytes witness program.

$ bx bitcoin160 03745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d
fb8820f35effa054399540b8ca86040d8ddaa4d5 

or with bitcoinJS

bitcoin.crypto.hash160(Buffer.from('03745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d', 'hex')).toString('hex')
// txb.addInput(prevTx, input.vout, input.sequence, prevTxScript)
txb.addInput('TX_ID', TX_VOUT, null, p2wpkhAlice0.output) 

Pay 0.999 BTC to Bob_0 public key hash

txb.addOutput(p2pkhBob0.address, 999e5)

The miner fee is calculated by subtracting the outputs from the inputs.
100 000 000 - 99 900 000 = 100 000
100 000 satoshis equals 0,001 BTC, this is the miner fee.

We don't have to specify any redeem or witness scripts here, since we are spending a native segwit UTXO.
But we need to sign the input value.

// txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript)
txb.sign(0, keyPairAlice0, null, null, 1e8)

Finally we can build the transaction and get the raw hex serialization.

const tx = txb.build()
console.log('tx.toHex()  ', tx.toHex())

Inspect the raw transaction with Bitcoin Core CLI, check that everything is correct.

$ decoderawtransaction "hexstring"

Broadcasting the transaction

It's time to broadcast the transaction via Bitcoin Core CLI.

$ sendrawtransaction "hexstring"

sendrawtransaction returns the transaction ID, with which you can inspect your transaction again.

Don't forget the second argument. If false, it returns the hex string, otherwise it returns a detailed json object.

$ getrawtransaction "txid" true

Observations

In the vin section we note that scriptSig is empty and that we have an additional txinwitness field which contains
Alice signature and public key.

In the vout section we have one witness_v0_keyhash output, which is the code name for native Segwit.

Typical Transaction (1 input, 2 outputs) - Native Segwit P2WPKH

To follow along this tutorial and enter the commands step-by-step

  • Type node in a terminal after cd into ./code for a Javascript prompt
  • Open the Bitcoin Core GUI console or use bitcoin-cli for the Bitcoin Core commands
  • Use bx aka Libbitcoin-explorer as a handy complement

Let's create a typical P2WPKH transaction, spending 1 P2WPKH UTXO and creating 2 new P2WPKH UTXOs, one for the actual
payment and one for the change.

Create a UTXO to spend from

Import libraries, test wallets and set the network

const bitcoin = require('bitcoinjs-lib')
const { alice, bob } = require('./wallets.json')
const network = bitcoin.networks.regtest

Send 1 BTC to Alice_0 native Segwit P2WPKH address in order to create a P2WPKH UTXO.

Check out Generating and Importing Wallets and your wallets.json
file in the code directory. Replace the address if necessary.

$ sendtoaddress bcrt1qlwyzpu67l7s9gwv4gzuv4psypkxa4fx4ggs05g 1

Get the output index so that we have the outpoint (txid / vout).

Find the output index (or vout) under details > vout.

$ gettransaction "txid"

Creating the transaction

Now let's spend the UTXO with BitcoinJS.

Create a bitcoinJS key pair object for Alice_0, the spender of our new UTXO, and the only one capable of spending it.

const keyPairAlice0 = bitcoin.ECPair.fromWIF(alice[0].wif, network)
const p2wpkhAlice0 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice0.publicKey, network})

Create a key pair object and a P2PKH address for the recipient Bob_0.

const keyPairBob0 = bitcoin.ECPair.fromWIF(bob[0].wif, network)
const p2wpkhBob0 = bitcoin.payments.p2wpkh({pubkey: keyPairBob0.publicKey, network})

Create a BitcoinJS transaction builder object.

const txb = new bitcoin.TransactionBuilder(network)

Create the input by providing the outpoint but also the script of the previous transaction (vout > scriptPubKey > hex).
Adding the prevTxScript is a specificity of P2WPKH spending.

The script is composed as follow: <version program 00> PUSHBYTES_14
The HASH160 of the public key must match the 20-bytes witness program.

$ bx bitcoin160 03745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d

fb8820f35effa054399540b8ca86040d8ddaa4d5

or with bitcoinJS
bitcoin.crypto.hash160(Buffer.from('03745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d', 'hex')).toString('hex')

// txb.addInput(prevTx, input.vout, input.sequence, prevTxScript)
txb.addInput('TX_ID', TX_VOUT, null, p2wpkhAlice0.output) 

Add the output #1 with the Bob_0 P2WPKH recipient address and the amount of 0.5 BTC.
Add the output #2 with alice's change address (the same one or a new one for better privacy) and the amount of 0.499 BTC.

txb.addOutput(p2wpkhBob0.address, 5e7)
txb.addOutput(p2wpkhAlice0.address, 499e5)

100 000 000 - (50 000 000 + 49 900 000) = 100 000
100 000 satoshis equals 0,001 BTC, this is the miner fee.

We don't have to specify any redeem or witness scripts here, since we are spending a native segwit UTXO.
But we need to sign the input value.

// txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript)
txb.sign(0, keyPairAlice0, null, null, 1e8)

Finally we can build the transaction and get the raw hex serialization.

const tx = txb.build()
console.log('tx.toHex()  ', tx.toHex())

Inspect the raw transaction with Bitcoin Core CLI, check that everything is correct.

$ decoderawtransaction "hexstring"

Broadcasting the transaction

It's time to broadcast the transaction via Bitcoin Core CLI.

$ sendrawtransaction "hexstring"

sendrawtransaction returns the transaction ID, with which you can inspect your transaction again.

Don't forget the second argument. If false, it returns the hex string, otherwise it returns a detailed json object.

$ getrawtransaction "txid" true

Observations

In the vin section we note that scriptSig is empty and that we have an additional txinwitness field which contains
Alice signature and public key.

In the vout section we have two witness_v0_keyhash outputs, which is the code name for native Segwit.

Spend a Embedded Segwit P2SH-P2WPKH UTXO

To follow along this tutorial and enter the commands step-by-step

  • Type node in a terminal after cd into ./code for a Javascript prompt
  • Open the Bitcoin Core GUI console or use bitcoin-cli for the Bitcoin Core commands
  • Use bx aka Libbitcoin-explorer as a handy complement

Let's spend a P2SH-P2WPKH output (embedded Segwit) and create a new P2WPKH output.
Working with P2SH now is a bit premature as we are dedicated this topic to part three of this guide.
Nevertheless, the purpose of a P2SH-P2WPKH transaction is to pay to a Segwit public key hash, inside a legacy P2SH only
for backward compatibility.

Create a UTXO to spend from

Import libraries, test wallets and set the network

const bitcoin = require('bitcoinjs-lib')
const { alice, bob } = require('./wallets.json')
const network = bitcoin.networks.regtest

Send 1 BTC to Alice_0 embedded Segwit P2SH-P2WPKH address in order to create a P2SH-P2WPKH UTXO (which is in fact a regular P2SH UTXO).

Check out Generating and Importing Wallets and your wallets.json
file in the code directory. Replace the address if necessary.

$ sendtoaddress 2MzFvFvnhFskGnVQpUr1ZPr4wYWLwf211s6 1

Inspect the transaction.

$ getrawtransaction "txid" true

Get the output index so that we have the outpoint (txid / vout).

Find the output index (or vout) under details > vout.

You can note that the UTXO is of type scripthash, which means that it is a P2SH UTXO.

Read more about P2SH here

Creating the transaction

Now let's spend the P2SH-P2WPKH UTXO with BitcoinJS.

Create a bitcoinJS key pair object for the spender Alice_0.
Create a P2WPKH payment address and pass it to the P2SH payment method.

const keyPairAlice0 = bitcoin.ECPair.fromWIF(alice[0].wif, network)
const p2wpkhAlice0 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice0.publicKey, network})
const p2shAlice0 = bitcoin.payments.p2sh({redeem: p2wpkhAlice0, network})

Create a key pair object and a P2PKH address for the recipient Bob_0.

const keyPairBob0 = bitcoin.ECPair.fromWIF(bob[0].wif, network)
const p2wpkhBob0 = bitcoin.payments.p2wpkh({pubkey: keyPairBob0.publicKey, network})

Create a BitcoinJS transaction builder object.

const txb = new bitcoin.TransactionBuilder(network)
txb.addInput('TX_ID', TX_VOUT)
txb.addOutput(p2wpkhBob0.address, 999e5)

The redeem script is composed of a 0 version byte and a 20 bytes witness program, HASH160 of Alice_0 public key.
It is the same as the prevOutScript p2wpkhAlice0.output in Native Segwit P2WPKH UTXO.

// txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript)
txb.sign(0, keyPairAlice0, p2shAlice0.redeem.output, null, 1e8)

Finally we can build the transaction and get the raw hex serialization.

const tx = txb.build()
console.log('tx.toHex()', tx.toHex())

Inspect the raw transaction with Bitcoin Core CLI, check that everything is correct.

$ decoderawtransaction "hexstring"

Broadcasting the transaction

It's time to broadcast the transaction.

$ sendrawtransaction "hexstring"

Inspect the transaction.

$ getrawtransaction "txid" true

Observations

In the vin section the scriptSig is the prevOutScript. When passed through HASH160 it should match the hash contained
in the scripthash UTXO that we are spending.
The Alice_0 public key and signature in txinwitness are then verified, like a P2WPKH ( CHECKSIG).

In the vout section we have one witness_v0_keyhash UTXO.