← head back

bitcoinnodejs

Bitcoin Protocol in 45 minutes

14/12/2022

Summary

In this article you will learn how:

  1. The network discovers its nodes
  2. Bitcoin's wire protocol works
  3. Addresses are calculated from private keys
  4. A payment transactions is constructed
  5. Such transaction is broadcasted in the network

 

The Bitcoin Network

Bitcoin is a decentralized network of nodes. Each node connects to a few other nodes to share information about the network.

Nodes exchange information about other nodes they know about and share new transactions and blocks for the network to sync.

Node Discovery

Bitcoin uses DNS to discover its seed nodes. These seed DNS servers are hardcoded in Bitcoin's code and are usually hosted by Bitcoin core devs. Every DNS server returns 5 to 10 IP addresses of Bitcoin nodes.

Discovering new nodes and peers in the Bitcoin network

Takeaway 1: Bitcoin node addresses are discovered from a few hardcoded DNS servers.

We will build a local node that reads a list of nodes from the hardcoded DNS addresses and then sends a version and a ping message to one of them.

Discover nodes from seed

The script above has 0 dependencies.

Wire Protocol

The nodes communicate over TCP. Each TCP message contains some metadata and a payload. The metadata are the message payload length, the message type, a checksum hash of the payload and the message payload itself.

The bitcoin tcp wire protocol network

Takeaway 2: Bitcoin messages are sent over TCP and contain a payload and some metadata.

The version contains information about the node, verack acknowledges the version message. Then ping and pong are sent periodically to check if a node is online.

Bitcoin wire protocol version verack syn ack messages Takeaway 3: The version and verack messages are used to establish a connection. A ping message is sent periodically waiting for a pong.

We can connect to a Bitcoin node by sending version message and response to incoming pings.

Connect to a node

The script above has 0 dependencies.

Bitcoin Addresses

A bitcoin address is derived from an ECDSA public key and an identifier. The public key is in turn derived from an ECDSA private key. The identifier indicates the Bitcoin address type and in most cases there are different identifiers for testnet and mainnet addresses of the same type.

Comparison to EVM addresses

Every blockchain has a way to check that transactions is valid.

Bitcoin data model is called the UTXO model. The UTXO model provides a quicker way to process payment transactions but has the drawback that the user has to provide a reference to a previous transaction themselves.

EVM chains use a different model called the Account model. One advantage of the Account Model is that addresses are not network specific. Testnets addresses are exactly the same as mainnet addresses (and other EVM chains too).

In the examples here we are using legacy bitcoin addresses. More on different address types on shiftcrypto.ch. There also a list of addresses identifiers (or prefixes) on Bitcoin Wiki.

Bitcoin address derivation private key Takeaway 4: Bitcoin addresses are derived from private keys (or seed phrases). For most address types, mainnet and testnet have different address formats.

The script bellow creates a random ECDSA private key and then derives a public key and an address from it.

Create a new address

The script above has 2 dependencies.

Fund your addresses

In the next section we are going to create a payment transaction and you'd need a have some testnet Bitcoins in your address. You will also need a reference to the transaction that sent you these Bitcoins, called a UTXO.

To get that UTXO you'd need to:

  1. Fund your new testnet address with a faucet that supports legacy addresses. For example coinfaucet.eu.
  2. Go to a block explorer (eg. blockstream.com) and copy the transaction id, the output index and the transaction value.

More on the UTXO model on horizen.io.

Transaction Format

Each transaction has a version, some inputs, some outputs and a locktime. Version represents the version of the transaction. The inputs represent a previous transaction that the signer owns and the outputs represent where to spend the coins. Any coins left in the outputs are used for fees. Moreover, locktime (if not 0) represents a timestamp in the future that will unlock the transaction for spending.

Bitcoin transaction overview data fields Takeaway 4: Transactions contain inputs and outputs. Inputs validate the owner of the transaction and outputs indicate where the coins should go.

This script creates a transaction hex using a private key, a sender and a UTXO controlled by the private key.

Create transaction

The script above has 2 dependencies.

NOTE: To create an unspent transaction (UTXO) with the script bellow you'd need a UTXO and its corresponding private key. The UTXO is given in 3 parameters, the transaction id, the transaction index and the transaction value. You can find the UTXO in Blockstream explorer in the details section, with the Blockstream API or by running a Bitcoin node locally.

Payment Transaction

When a node has a new transaction or block it sends an inv message advertise it with the transaction or block hash. If any of the connectted nodes do not have it the ask for with a getdata message and the node sends it back in a tx or block message.

Bitcoin wire protocol inventory message transaction block Takeaway 4: A node advertise a block or tx with inv message. When is asked for the resources with getdata it sends it as a tx or block message.

We will now broadcast the transaction by sending an inv message and then sending the transaction in a tx message when it receives a getdata message.

NOTE: If the broadcasting transaction does not work double check that you created the transaction hex correctly in the previous section. That means a valid UTXO belonging to a funded Bitcoin address.

Broadcast transaction

The script above has 0 dependencies.

 

Thanks to ETFbitcoin for reviewing.

Related Posts

Andreas Tzionis @

Github

Twitter

LinkedIn