Saving money on bitcoin transaction fees with segregated witness first requires you to receive bitcoin in the form of segwit utxos. This post will go over a libbitcoin script for generating a testnet P2SH-P2WKH address to send your bitcoins to and have them ready for spending in segwit transactions.
In order to begin spending bitcoins via segregated witness transactions you need receive pay-to-witness-key-hash outputs. So, the first thing you need to create is a witness program that consist of a version number 0 and compressed hash of your public key.
One thing we need to be sure of is that we always use a compressed public key to generate a P2WKH address. So, first I define a function for getting the compressed public key from a mnemonic by decoding it to its seed and then calling the point getter to get the ec compressed public key.
ec_compressed getPublicKey() { std::string mnemonic = "portion shop border uniform loan grab dismiss boss wild magnet strong supreme era swing else keep voyage forest"; data_chunk seed = to_chunk(decode_mnemonic(split(mnemonic))); hd_private privateKey = hd_private(seed, hd_private::testnet); ec_compressed compressedPublicKey = privateKey.to_public().point(); return compressedPublicKey; }
Then we need to define a function that will create a the P2WKH which simply looks like this:
0 [Compressed Public Key Hash]
To do this we need to create a bitcoin short hash of the compressed public key which we will pass as an argument. This short hash amounts to a RIPEMD160 hash of a SHA256 hash of the compressed public key point. We then return this key hash as a data chunk in an operations list prefixed with an opcode 0 object.
operation::list witnessProgram(ec_compressed publicKey) { short_hash KeyHash = bitcoin_short_hash(publicKey); return {operation(opcode(0)), operation(to_chunk(KeyHash))}; }
Now we can create a script object for our witness program and print it out to the console.
int main() { //Output Compressed Public Key std::cout << "Public Key: "<< encode_base16(getPublicKey()) << std::endl; //Output Witness Program script P2WPKH = script(witnessProgram(getPublicKey())); std::cout << "Witness Program: " << P2WPKH.to_string(0) << std::endl; }
Now in order to make these P2WPKH outputs payable by anyone regardless of their segwit awareness, we need to wrap them in a P2SH address. To do this we first save a short hash of the witness program and pass it to a P2SH script pattern factory.
int main() { //Output Compressed Public Key std::cout << "Public Key: "<< encode_base16(getPublicKey()) << std::endl; //Output Witness Program script P2WPKH = script(witnessProgram(getPublicKey())); std::cout << "Witness Program: " << P2WPKH.to_string(0) << std::endl; //Create P2SH script short_hash WitnessProgramHash = bitcoin_short_hash(P2WPKH.to_data(0)); script P2SH_P2WPKH = script::to_pay_script_hash_pattern(WitnessProgramHash); }
Then we can print out the P2SH_P2WPKH script pubkey as a string to the console.
We can also print the payment address by passing the witness program script to the payment address object and calling the encoded accessor.
int main() { //Output Compressed Public Key std::cout << "Public Key: "<< encode_base16(getPublicKey()) << std::endl; //Output Witness Program script P2WPKH = script(witnessProgram(getPublicKey())); std::cout << "Witness Program: " << P2WPKH.to_string(0) << std::endl; //Create P2SH script short_hash WitnessProgramHash = bitcoin_short_hash(P2WPKH.to_data(0)); script P2SH_P2WPKH = script::to_pay_script_hash_pattern(WitnessProgramHash); //Print our P2SH script and address std::cout <<"P2SH Script: " <<P2SH_P2WPKH.to_string(0) << std::endl; std::cout << "Payment Address: " <<payment_address(P2WPKH, payment_address::testnet_p2sh).encoded() << std::endl; }
As usual this program can be compiled and run via the Command line:
$ g++ -std=c++11 -o segwit segwit.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin) $ ./segwit
You’ll note that the payment address begins with a 2, this denotes a testnet Pay-To-Script-Hash address since segwit address can be paid to the same as P2SH. A mainnet segwit address with start with a 3.
Any testnet coins sent to this address will be ready to spend with a fee-discounted segwit transaction.