Part 10: Address 101

cryptoskillz
Bitcoin e-commerce development
8 min readOct 22, 2018
Photo by Timothy Eberly on Unsplash

Introduction

This guide aims to program a website to accept Bitcoin. In the last tutorial (part 9), we replaced all of our 3rd party code in favour of using fullnode to give us as total sovereignty. In this part, we are going to be looking into addresses, how they function, the way they work and what we have to look for whilst using them.

This is part is not required to run a Bitcoin E-Commerce server, See it as extra credit for the people who like to get under the hood and deep dive subjects.

What is an address?

A Bitcoin address is a single-use token. Like an e-mail address, you can send bitcoins to a person by sending bitcoins to one of their addresses. However, unlike e-mail addresses, people have many different Bitcoin addresses and a unique address should be used for each transaction.

There are 3 address types we will cover in this tutorial.

P2PKH: Legacy
This was the original address. We will not spend to much time discussing this as I am going to be using SegWit for all transactions going forward. If you want to use this address you are free to do and please make sure to change the code accordingly.

P2SH: Current
This is current address in use called SegWit (shot for segregated witness)

Bech32: Future
This is a SegWit address format specified by BIP 0173. This address format is also known as “bc1 addresses”.

Network topology

Below is an excellent chart showing how the address flow in the Bitcoin network.

https://en.bitcoin.it/wiki/Address

We will be focusing on P2SH or current as we will be referring to it in the tutorial (for a complete list of addresses click here) as this is the current standard address to use. The legacy was the previous address type and future address type is not supported across the network as yet.

Using a Current address (Segwit)

Let us look at how this relates to our code. When we call our REST method “/api/address” you will see this, in turn, calls the getNewAddress function which returns us an address (shown below).

client.getNewAddress(process.env.walletaccount).then(address => {

});
//returns: 2Mx1TYm5J87WQAuqo4SBMQZJZLRPNjg716N

This address starts with a 2 that tells us this is a current (Segwit address) on the Test Network. If we were on the Main Network then it would start with a 3.

We could have passed another paramater to this functions called address type which would generate a legacy or future address type.

There are a number of different address types used in Bitcoin but as I said above we are only going to focus on the current address type, however, you can find the full list here if you would like extra credit.

Once we have sent some funds to the address then we have to go ahead and sweep them, we do that using the functions below.

listUnspent

The listUnspent function returns a list of unspent transactions when we call it we pass in 3 parameters.

Minimum Confirmations
The minimum number of confirmations the transaction containing an output must have in order to be returned. Use 0 to return outputs from unconfirmed transactions. The default is 1.

Maximum Confirmations
The maximum number of confirmations the transaction containing an output may have in order to be returned. The default is 9999999.

Addresses
A JSON array of bitcoin addresses. If you do not pass an address it will return all the unspent transactions for the default account.
Note, when this account functionality is fully deprecated in the next version it is unknown (to me) how this function will change.

There are various optional parameters we can also pass but these are beyond the scope of what we aim out to achieve with this tutorial, you can find these parameters by clicking here for more information.

When we call the listUnspent function, it returns an array of the unspent transactions and as this is current (SegWit) address it also returns a redeemScript and scriptPubKey for each of these (which we will use later).

client.listUnspent(1,9999999,["2Mx1TYm5J87WQAuqo4SBMQZJZLRPNjg716N"]).then(result => {
console.log(result);
});
//results
[ { txid:
'eacd42149861188d3de61a36af3663c6988c5d8bc51d3881d3e56b6ce913a22d',
vout: 0,
address: '2N1j6CXWE24rWXC7P1GRdVeirVcTBPN8QWM',
label: 'woot',
redeemScript: '0014207f99f926c27456d9b91eac84f016d5896f91ac',
scriptPubKey: 'a9145d0626be3027c37d9c51b7c6a2a5f684e35a733487',
amount: 0.02,
confirmations: 8,
spendable: true,
solvable: true,
safe: true }
]

Let’s quickly break down this object and see what each of the returned items is and what it is used for.

txid:
The transaction id, we use this later to make sure we can sign and broadcast the transaction correctly.

vout:
vout refers to the index of the output address in question. The index starts from 0. So for example, if a tx has 10 output addresses, the vouts for the addresses would be from 0–9.
Note in our usage the vout should always be 0 as we never reuse an address.

address:
The Bitcoin address.

label:
The associated label that was set when the Bitcoin was spent. This is an optional paramater so it can be blank.

redeemScript:
Similar to a scriptPubKey. One copy of it is hashed to create a P2SH address (used in an actual pubkey script) and another copy is placed in the spending signature script to enforce its conditions.

scriptPubKey:
A script included in outputs which hold the conditions to spend the BTC. Data for fulfilling the conditions can be provided in a signature script.

amount:
the transaction output amount in BTC

confirmations:
“confirmations”: n, (numeric) The number of confirmations

spendable:
Whether we have the private keys to spend this output

solvable:
Whether we know how to spend this output, ignoring the lack of keys

safe:
Whether this output is considered safe to spend. Unconfirmed transaction

Note, as we generate a new address for every transaction we should never have more than 1 item in this array if we do then it is most likely someone has sent us money in error and we may write some code to work with these edge cases later.

dumpPrivKey

The dumpPrivKey function call returns the wallet-import-format (WIP) private key corresponding to an address. (But does not remove it from the wallet.) We use it by passing the address into the function.
Note, if we have control of this address then it will return the private key otherwise it will produce an error.

client.dumpPrivKey(req.query.address).then(pkey => {
});
//returns
cSxwAZCdWqEkextHde9RGsZxP1nJ36yHmGobiWgHB3XH1yRxyzwUQ

estimateSmartFee

We use the estimateSmartFee function to calculate a fee amount. Once we have this amount we deduct it from the amount to send to the recipient address.

Needless to say, It is important we get this right as we do not want to be the guy in the image below, that is a $1,300,000 mistake at today's prices.

signRawTranaction also has a high fee check (set to 0.1 BTC) which will further stop us from making costly mistakes.

When we call the function we pass 1 parameter and that is the maximum number of blocks a transaction should have to wait before it is predicted to be included in a block. As you can see we set this to 6 (never put this below 3). We can also pass a second parameter called feetype by default it is set to conservative and this is good enough for our usage.

client.estimateSmartFee(6).then((fee) => {
});
//retturns
{
feerate: 0.00001017,
blocks: 6
}

The feerate is what is of interest to us and we simply deduct this from the amount from the array returned from the listUnpsent function. This gives us the amount we want to send as shown below.

var amounttosend = result[0].amount - fee.feerate;

We will go into a deep dive in fees in a later tutorial but if you want to read about it now, click here for an excellent article on the topic.

Note you will see a lot of documentation referencing a function called estimatefee this has now been depreciated and should not be used.

createRawTransaction

The createRawTransaction function creates an unsigned serialized transaction that spends a previous output to a new output. The transaction is not stored in the wallet or transmitted to the network.

We pass in a few parameters to create a raw transaction:

txid:
this is the transaction id that we got from the listUnspent function.

vout:
This is the vout that we got from the listUnspent function we have set this to zero as we are only using each address once. To make this function a little more robust we could match the addresses from the listtUnspent function with the address we pass in and use any vout in the result object.

The last parameter we pass id a key-value pair which is the address we want to send to and the amount to send (amount -fee)

This returns a hex string. It is beyond the scope of this tutorial to break this down but if you want to research it further click here.

client.createRawTransaction(
[{"txid":result[0].txid,
"vout":0
}],
[{[process.env.toaddress]:amounttosend
}]
).then((txhash) => {
});//results
02000000012da213e96c6be5d381381dc58b5d8c98c66336af361ae63d8d1861981442cdea0000000000ffffffff0198801e000000000017a91470d835143969a5921541ddd01f7eca615be2b9258700000000

signRawTransaction

The signRawTransaction function signs a transaction in the serialized transaction format using private keys stored in the wallet or provided in the call.

As you see this function takes the results from the previous functions dumpPrivKey, listUnspent, signRawTransaction and createRawTransaction.

txhash:
This is the hash that is returned from the createRawTransaction function

txid:
This the transaction id from the listUnspent function

vout:
We set this to zero as we only ever send 1 transaction to this address as discussed above.

amount:
This the amount from the listUnspent function

scriptPubKey:
This the public key of the script from the listUnspent function

redeemScript:
This the redeem script from the listUnspent function

pkey:
This the private key returned from the dumpPrivKey function

The signRawTransaction command returns another hex-encoded raw transaction which we broadcast to the network.

client.signRawTransaction(
txhash,[{
"txid":result[0].txid,
"vout":0,
"amount":result[0].amount,
"scriptPubKey":result[0].scriptPubKey,
"redeemScript":result[0].redeemScript
}],
[pkey]).then((signed) => {
});//results{
hex:
'02000000000101b3e3657a5c00adc03aa7ac19549c88a8284f7e60f0ba06c4723f3394c7627bc501000000171600142a8990cf46e4934aa2458f298086f7b07686c4a5ffffffff01473e0f000000000017a91470d835143969a5921541ddd01f7eca615be2b9258702473044022077326e84b3a0403447d31bd19acf7763d949eccc98f6e3760b48de2f59072f58022038b45c47019501d6f34025e15ac402376dbbea8d2dee4688df37b54ae7098a62012102f72a0b15f6be8cb80b3342172ee12723802ec8c874bc3bfa96113ee2bb4a735d00000000',
complete: true
}

sendRawTransaction

The sendRawTransaction validates a transaction and broadcasts it to the peer-to-peer network. We use the hex has returned from the signRawTransaction function.

You can pass an optimal paramater called allowhighfees which overrides the 0.1 BTC fee check.

The result (if valid) is the signed hex and the transaction has now been confirmed.

client.sendRawTransaction(signed.hex).then((broadcasted) => {
});
//results
c471ef3419fe487f701b039aabbf8d7897f6facc20bbdceb547f13d4766a21ef

Major Foobar

After spending the last couple of weeks reading about anything and everything to do with addresses it became clear I had made a major mistake with the sweep function. The fact that we send the funds to the same address each time is very bad practice and can lead to all sorts of issues such as being able to identify or even hack you or hack your private key. For a great article on an address, reuse click here

This is something we will fix in our next tutorial by generating a bunch of address from a mnemonic using an offline line command line script. We are going to use this by bringing back BitcoinJs bip39.generateMnemonic() function. Yes, I thought we no longer required this and I was wrong, welcome to programming. We can generate this transaction yourself at a HEX level and using OpenSSL and terminal (and we may do so in the future) but for now, this is overkill. If you want to deep dive this subject there is an excellent tutorial here.

Conclusion

So there we have a nice little introduction to address, I hope you find this useful and if you read it all, then well done you. Next time we are going to fix our sweep function (as described) and the admin section accordingly.

--

--