Chapter One: Introduction to Learning Bitcoin Core (& Lightning) from the Command Line
Introduction
The ways that we make payments for goods and services has been changing dramatically over the last several decades. Where once all transactions were conducted through cash or checks, now various electronic payment methods are the norm. However, most of these electronic payments still occur through centralized systems, where credit card companies, banks, or even internet-based financial institutions like Paypal keep long, individually correlated lists of transactions and have the power to censor transactions that they don't like.
These centralization risks were some of the prime catalysts behind the creation of cryptocurrencies, the first and most successful of which is Bitcoin. Bitcoin offers pseudonymity; it makes it difficult to correlate transactions; and it makes censorship by individual entities all but impossible. These advantages have made it one of the quickest growing currencies in the world. That growth in turn has made Bitcoin into a going concern among entrepreneurs and developers, eager to create new services for the Bitcoin community.
If you're one of those entrepreneurs or developers, then this course is for you, because it's all about learning to program Bitcoin. It's an introductory course that explains all the nuances and features of Bitcoin as it goes. It also takes a very specific tack, by offering lessons in how to work directly with Bitcoin Core and with the c-lightning server using their RPC interfaces.
Why not use some of the more fully featured libraries found in various programming languages? Why not create your own from scratch? It's because working with cryptocurrency is dangerous. There are no safety nets. If you accidentally overpay your fees or lose a signing key or create an invalid transaction or make any number of potential mistakes, then your cryptocurrency will be gone forever. Much of that responsibility will, of course, lie with you as a cryptocurrency programmer, but it can be minimized by working with the most robust, secure, and safe cryptocurrency interfaces around, the ones created by the cryptocurrency programming teams themselves: bitcoind
and lightningd
.
Much of this book thus discusses how to script Bitcoin (and Lightning) directly from the command line. Some later chapters deal with more sophisticated programming languages, but again they continue to interact directly with the bitcoind
and lightningd
daemons by using RPC or by interacting with the files they create. This allows you to stand on the shoulders of giants and use their trusted technology to learn how to create your own trusted systems.
Required Skill Level
You do not need to be particularly technical for the majority of this course. All you need is the confidence to run basic commands on the UNIX command line. If you're familiar with things like ssh
, cd
, and ls
, the course will supply you with the rest.
A minority of this course requires programming knowledge, and you should skip over those sections if needed, as discussed in the next section.
Overview of Topics
This book is broadly divided into the following sections:
Part | Description | Skills |
---|---|---|
Part One: Preparing for Bitcoin | Understanding the basics of Bitcoin and setting up a server for use. | Command Line |
Part Two: Using Bitcoin-CLI | Using the Bitcoin-CLI for creating transactions. | Command Line |
Part Three: Bitcoin Scripting | Expanding your Bitcoin work with scripts. | Programming Concepts |
Part Four: Using Tor | Improving your node security with Tor | Command Line |
Part Five: Programming with RPC | Accessing RPC from C and other languages. | Programming in C |
Part Six: Using Lightning-CLI | Using the Lightning-CLI for creating transactions. | Command Line |
Appendices | Utilizing less common Bitcoin setups. | Command Line |
How To Use This Course
So where do you start? This book is primarily intended to be read sequentially. Just follow the "What's Next?" Links at the end of each section and/or click through the individual section links on each chapter page. You'll achieve the best understanding from this course if you actually build yourself a Bitcoin server (per Chapter 2) and then run through all the examples over the course of the book: trying out examples is an excellent learning methodology.
If you have different levels of skill or want to learn different things, you might skip to different parts of the book:
- If you've already got a Bitcoin environment ready to be used, jump to Chapter Three: Understanding Your Bitcoin Setup.
- If you only care about Bitcoin scripting, jump to Chapter Nine: Introducing Bitcoin Scripts.
- If you just want to read about using programming languages, jump to Chapter Sixteen: Talking to Bitcoin.
- If you conversely don't want to do any programming, definitely skip chapters 15-17 while you're reading, and perhaps skip chapters 9-13. The rest of the course should still make sense without them.
- If you are only interested in Lightning, zap over to Chapter Nineteen: Understanding Your Lightning Setup.
- If you want to read the major new content added for v2 of the course (2020), following on v1 (2017), read §3.5: Understanding the Descriptor, §4.6: Creating a SegWit Transaction, Chapter 7: Expanding Bitcoin with PSBTs, §9.5: Scripting a P2WPKH, §10.5: Scripting a SegWit Script, Chapter 14: Using Tor, Chapter 15: Using i2p, Chapter 16: Talking to Bitcoind with C, Chapter 17: Programming with Libwally, Chapter 18: Talking to Bitcoind with Other Languages, Chapter 19: Understanding Your Lighting Setup, and Chapter 20: Using Lightning.
Why to Use this Course
Obviously, you're working through this course because you're interested in Bitcoin. Besides imparting basic knowledge, it's also helped readers to join (or create) open-source projects and to get entry-level jobs in Bitcoin programming. A number of Blockchain Commons' interns learned about Bitcoin from this course, as have some members of our programming team.
How to Support this Course
- Please use Issues for any questions. Blockchain Commons does not have an active support team, and so we can't address individual problems or queries, but we will look over them in time, and use them to improve future iterations of the course.
- Please use PRs for any fixes of typos or incorrect (or changed) commands. For command-line or technical changes, it's very helpful if you also use the PR comments to explain why you did what you did, so that we don't have to research it.
- Please Use Our Community discussions area for talking about careers and skills. Blockchain Commons occasionally offers internships, as discussed in our Community repo.
- Please become a patron if you find this course helpful or if you want to help educate the next generation of blockchain programmers.
What's Next?
If you'd like a basic introduction to Bitcoin, public-key cryptography, ECC, blockchains, and Lightning, read the Introducing Bitcoin interlude.
Otherwise, if you're ready to dive into the course, go to Setting Up a Bitcoin-Core VPS.
Interlude: Introducing Bitcoin
Before you can get started programming Bitcoin (and Lightning), you should have a basic understanding of what they are and how they work. This section provides that overview. Many more definitions will appear within the document itself; this is only intended to lay the foundation.
About Bitcoin
Bitcoin is a programmatic system that allows for the transfer of the bitcoin currency. It is enabled by a decentralized, peer-to-peer system of nodes, which include full nodes, wallets, and miners. Working together, they ensure that bitcoin transactions are fast and non-repudiable. Thanks to the decentralized nature of the system, these transactions are also censor-resistant and can provide other advantages such as pseudonymity and non-correlation if used well.
Obviously, Bitcoin is the heart of this book, but it's also the originator of many other systems, including blockchains and Lightning, which are both detailed in this tutorial, and many other cryptocurrencies such as Ethereum and Litecoin, which are not.
How Are Coins Transferred? Bitcoin currency isn't physical coins. Instead it's an endless series of ownership reassignments. When one person sends coins to another, that transfer is stored as a transaction. It's the transaction that actually records the ownership of the money, not any token local to the owner's wallet or their machine.
Who Can You Send Coins To? The vast majority of bitcoin transactions involve coins being sent to individual people (or at least to individual Bitcoin addresses). However, more complex methodologies can be used to send bitcoins to groups of people or to scripts. These various methodologies have names like P2PKH, multisig, and P2SH.
How Are Transactions Stored? Transactions are combined into larger blocks of data, which are then written to the blockchain ledger. A block is built in such a way that it cannot be replaced or rewritten once several blocks have been built atop (following) it. This is what makes bitcoins non-repudiable: the decentralized global ledger where everything is recorded is effectively a permanent and unchangeable database.
However, the process of building these blocks is stochastic: it's somewhat random, so you can never be assured that a transaction will be placed in a specific block. There can also be changes in blocks if they're very recent, but only if they're very recent. So, things become non-repudiable (and permanent and unchangeable) after a little bit of time.
How Are Transactions Protected? The funds contained in a Bitcoin transaction are locked with a cryptographic puzzle. These puzzles are designed so that they can be easily solved by the person who the funds were sent to. This is done using the power of public-key cryptography. Technically, a transaction is protected by a signature that proves you're the owner of the public key that a transaction was sent to: this proof of ownership is the puzzle that's being solved.
Funds are further protected by the use of hashes. Public keys aren't actually stored in the blockchain until the funds are spent: only public-key hashes are. This means that even if quantum computer were to come along, Bitcoin transactions would remain protected by this second level of cryptography.
How Are Transactions Created? The heart of each Bitcoin transaction is a FORTH-like scripting language that is used to lock the transaction. To respend the money, the recipient provides specific information to the script that proves he's the intended recipient.
However, these Bitcoin scripts are the lowest level of Bitcoin functionality. Much Bitcoin work is done through the bitcoind
Bitcoin daemon, which is controlled through RPC commands. Many people send those RPC commands through the bitcoin-cli
program, which provides an even simpler interface. Non-programmers don't even worry about these minutia, but instead use programmed wallets with simpler interfaces.
Bitcoin — In Short
One way to think of Bitcoin is as a sequence of atomic transactions. Each transaction is authenticated by a sender with the solution to a previous cryptographic puzzle that was stored as a script. The new transaction is locked for the recipient with a new cryptographic puzzle that is also stored as a script. Every transaction is recorded in an immutable global ledger.
About Public-Key Cryptography
Public-key cryptography is a mathematical system for protecting data and proving ownership through an asymmetric pair of linked keys: the public key and the private key.
It's important to Bitcoin (and to most blockchain systems) because it's the basis of a lot of the cryptography that protects the cryptocurrency funds. A Bitcoin transaction is typically sent to an address that is a hashed public key. The recipient is then able to retrieve the money by revealing both the public key and the private key.
What Is a Public Key? A public key is the key given out to other people. In a typical public-key system, a user generates a public key and a private key, then he gives the public key to all and sundry. Those recipients can encrypt information with the public key, but it can't be decrypted with the same public key because of the asymmetry of the key pair.
What Is a Private Key? A private key is linked to a public key in a key pair. In a typical public-key system, a user keeps his private key secure and uses it to decrypt messages that were encrypted with his public key before being sent to him.
What Is a Signature? A message (or more commonly, a hash of a message) can be signed with a private key, creating a signature. Anyone with the corresponding public key can then validate the signature, which verifies that the signer owns the private key associated with the public key in question. SegWit is a specific format for storing a signature on the Bitcoin network that we'll meet down the line.
What Is a Hash Function? A hash function is an algorithm frequently used with cryptography. It's a way to map a large, arbitrary amount of data to a small, fixed amount of data. Hash functions used in cryptography are one-way and collision-resistant, meaning that a hash can reliably be linked to the original data, but the original data can not be regenerated from the hash. Hashes thus allow the transmission of small amounts of data to represent large amounts of data, which can be important for efficiency and storage requirements.
Bitcoin takes advantage of a hash's ability to disguise the original data, which allows concealment of a user's actual public key, making transactions resistant to quantum computing.
Public-Key Cryptography — In Short
One way to think of public-key cryptography is: a way for anyone to protect data such that only an authorized person can access it, and such that the authorized person can prove that he will have that access.
About ECC
ECC stands for elliptic-curve cryptography. It's a specific branch of public-key cryptography that depends on mathematical calculations conducted using elliptic curves defined over finite fields. It's more complex and harder to explain than classic public-key cryptography (which used prime numbers), but it has some nice advantages.
ECC does not receive much attention in this tutorial. That's because this tutorial is all about integrating with Bitcoin Core and Lightning servers, which have already taken care of the cryptography for you. In fact, this tutorial's intention is that you don't have to worry about cryptography at all, because that's something that you really want experts to deal with.
What is an Elliptic Curve? An elliptic curve is a geometric curve that takes the form y
2
= x
3
+ ax + b
. A specific elliptic curve is chosen by selecting specific values of a
and b
. The curve must then be carefully examined to determine if it works well for cryptography. For example, the secp256k1 curve used by Bitcoin is defined as a=0
and b=7
.
Any line that intersects an elliptic curve will do so at either 1 or 3 points ... and that's the basis of elliptic-curve cryptography.
What are Finite Fields? A finite field is a finite set of numbers, where all addition, subtraction, multiplication, and division is defined so that it results in other numbers also in the same finite field. One simple way to create a finite field is through the use of a modulo function.
How is an Elliptic Curve Defined Over a Finite Field? An elliptic curve defined over a finite field has all of the points on its curve drawn from a specific finite field. This takes the form: y
2
% field-size = (x
3
+ ax + b) % field-size
The finite field used for secp256k1 is 2
256
- 2
32
- 2
9
- 2
8
- 2
7
- 2
6
- 2
4
- 1
.
How Are Elliptic Curves Used in Cryptography? In elliptic-curve cryptography, a user selects a very large (256-bit) number as his private key. He then adds a set base point on the curve to itself that many times. (In secp256k1, the base point is G = 04 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8
, which prefixes the two parts of the tuple with an 04
to say that the data point is in uncompressed form. If you prefer a straight geometric definition, it's the point "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8") The resultant number is the public key. Various mathematical formula can then be used to prove ownership of the public key, given the private key. As with any cryptographic function, this one is a trap door: it's easy to go from private key to public key and largely impossible to go from public key to private key.
This particular methodology also explains why finite fields are used in elliptic curves: it ensures that the private key will not grow too large. Note that the finite field for secp256k1 is slightly smaller than 256 bits, which means that all public keys will be 256 bits long, just like the private keys are.
What Are the Advantages of ECC? The main advantage of ECC is that it allows the same security as classic public-key cryptography with a much smaller key. A 256-bit elliptic-curve public key corresponds to a 3072-bit traditional (RSA) public key.
ECC - In Short
One way to think of ECC is: a way to enable public-key cryptography that uses very small keys and very obscure math.
About Blockchains
Blockchain is the generalization of the methodology used by Bitcoin to create a distributed global ledger. Bitcoin is a blockchain as are any number of alt-coins, each of which lives on its own network and writes to its own chain. Sidechains like Liquid are blockchains too. Blockchains don't even need to have anything to do with finances. For example, there have been many discussions of using blockchains to protect self-sovereign identities.
Though you need to understand the basics of how a blockchain works to understand how transactions work in Bitcoin, you won't need to go any further than that. Because blockchains have become a wide category of technology, those basic concepts are likely to be applicable to many other projects in this growing technology sector. The specific programming commands learned in this book will not be, however, as they're fairly specific to Bitcoin (and Lightning).
Why Is It Called a Chain? Each block in the blockchain stores a hash of the block before it. This links the current block all the way back to the original "genesis block" through an unbroken chain. It's a way to create absolute order among possibly conflicting data. This also provides the security of blockchain, because each block is stacked atop an old one makes it harder to recreate the old block due to the proof-of-work algorithms used in block creation. Once several blocks have been built atop a block in the chain, it's essentially irreversible.
What is a Fork? Occasionally two blocks are created around the same time. This temporarily creates a one-block fork, where either if the current blocks could be the "real" one. Every once in a while, a fork might expand to become two blocks, three blocks, or even four blocks long, but pretty quickly one side of the fork is determined to be the real one, and the other is "orphaned". This is part of the stochastic process of block creation, and demonstrates why several blocks must be built atop a block before it can be considered truly trustworthy and non-repudiable.
Blockchain — In Short
One way to think of blockchain is: a linked series of blocks of unchangeable data, going back in time. Another way is: a linked series of blocks to absolutely order data that could be conflicting.
Is Blockchain Right for Me?
If you want to transact bitcoins, then obviously Bitcoin is right for you. However, more widely, blockchain has become a popular buzz-word even though it's not a magic bullet for all technical problems. With that said, there are many specific situations where blockchain is a superior technology.
Blockchains probably will be helpful if:
- Users don't trust each other.
- Or: Users exist across various borders.
- Users don't trust central authorities.
- And: Users want to control their own destinies.
- Users want transparent technology.
- Users want to share something.
- And: Users want what's shared to be permanently recorded.
- Users want fast transaction finality.
- But: Users don't need instant transaction finality.
Blockchains probably will not be helpful if:
- Users are trusted:
- e.g.: transactions occur within a business or organization.
- e.g.: transactions are overseen by a central authority.
- Secrecy is required:
- e.g.: Information should be secret.
- e.g.: Transactions should be secret.
- e.g.: Transactors should be secret.
- Unless: A methodology for cryptographic secrecy is carefully considered, analyzed, and tested.
- Users need instant transaction finality.
- e.g.: in less than 10 minutes on a Bitcoin-like network, in less than 2.5 minutes on a Litecoin-like network, in less than 15 seconds on an Ethereum-like network
Do note that there may still be solutions for some of these situations within the Bitcoin ecosystem. For example, payment channels are rapidly addressing questions of liquidity and payment finality.
About Lightning
Lightning is a layer-2 protocol that interacts with Bitcoin to allow users to exchange their bitcoins "off-chain". It has both advantages and disadvantages over using Bitcoin on its own.
Lightning is also the secondary focus of this tutorial. Though it's mostly about interacting directly with Bitcoin (and the bitcoind
), it pays some attention to Lightning because it's an upcoming technology that is likely to become a popular alternative to Bitcoin in the near future. This book takes the same approach to Lightning as to Bitcoin: it teaches how to interact directly with a trusted Lightning daemon from the command line.
Unlike with Bitcoin, there are actually several variants of Lightning. This tutorial uses the standard-compliant c-lightning implementation as its trusted Lightning server.
What is a Layer-2 Protocol? A layer-2 Bitcoin protocol works on top of Bitcoin. In this case, Lightning works atop Bitcoin, interacting with it through smart contracts.
What is a Lightning Channel? A Lightning Channel is a connection between two Lightning users. Each of the users locks up some number of bitcoins on the Bitcoin blockchain using a multi-sig signed by both of them. The two users can then exchange bitcoins through their Lightning channel without ever writing to the Bitcoin blockchain. Only when they want to close out their channel do they settle their bitcoins, based on the final division of coins.
What is a Lightning Network? Putting together a number of Lightning Channels creates the Lightning Network. This allows two users who have not created a channel between themselves to exchange bitcoins using Lightning: the protocol forms a chain of Channels between the two users, then exchanges the coins through the chain using time-locked transactions.
What are the Advantages of Lightning? Lightning allows for faster transactions with lower fees. This creates the real possibility of bitcoin-funded micropayments. It also offers better privacy, since it's off-chain with only the first and last states of the transaction being written to the immutable Bitcoin ledger.
What are the Disadvantages of Lightning? Lightning is still a very new technology and hasn't been tested as thoroughly as Bitcoin. That's not just a question of the technological implementation, but also whether the design itself can be gamed in any unexpected ways.
Lightning - In Short
One way to think of Lightning is: a way to transact bitcoins using off-chain channels between pairs of people, so that only a first and final state have to be written to the blockchain.
Summary: Introducing Bitcoin
Bitcoin is a peer-to-peer system that allows for the transfer of funds through transactions that are locked with puzzles. These puzzles are dependent upon public-key elliptic-curve cryptography. When you generalize the ideas behind Bitcoin, you get blockchains, a technology that's currently growing and innovating. When you expand the ideas behind Bitcoin, you get layer-2 protocols such as Lightning, which expand the currency's potential.
What's Next?
Advance through "Preparing for Bitcoin" with Chapter Two: Setting Up a Bitcoin-Core VPS.
Chapter Two: Creating a Bitcoin-Core VPS
To get started with Bitcoin, you first need to set up a machine running Bitcoin. The articles in this chapter describe how to do so, primarily by using a VPS (Virtual Private Server).
Objectives for this Chapter
After working through this chapter, a developer will be able to:
- Decide Between the Five Major Types of Bitcoin Nodes
- Create a Bitcoin Node for Development
- Create a Local Instance of the Bitcoin Blockchain
Supporting objectives include the ability to:
- Understand the Basic Network Setup of the VPS
- Decide Which Security Priorities to Implement
- Understand the Difference between Pruned and Unpruned Nodes
- Understand the Difference between Mainnet, Testnet, and Regtest Nodes
- Interpret the Basics of the Bitcoin Configuration File
Table of Contents
You don't actually need to read this entire chapter. Decide if you want to run a StackScript to set a node up on a Linode VPS (§2.2); or you want to set up on a different environment, such as on an AWS machine or a Mac (§2.3). Then, jump to the appropriate section. Additional information on our suggested setups may also be found in Appendix I.
- Section One: Setting Up a Bitcoin Core VPS with Bitcoin Standup
- Section Two: Setting Up a Bitcoin Core Machine via Other Means
2.1: Setting Up a Bitcoin-Core VPS with Bitcoin Standup
This document explains how to set up a VPS (Virtual Private Sever) to run a Bitcoin node on Linode.com, installed using an automated StackScript from the Bitcoin Standup project. You just need to enter a few commands and boot your VPS. Almost immediately after you boot, you'll find your new Bitcoin node happily downloading blocks.
:warning: WARNING: Don’t use a VPS for a bitcoin wallet with significant real funds; see http://blog.thestateofme.com/2012/03/03/lessons-to-be-learned-from-the-linode-bitcoin-incident/ . It is very nice to be able experiment with real bitcoin transactions on a live node without tying up a self-hosted server on a local network. It's also useful to be able to use an iPhone or iPad to communicate via SSH to your VPS to do some simple bitcoin tasks. But a higher level of safety is required for significant funds.
- If you want to understand what this setup does, read Appendix I: Understanding Bitcoin Standup as you install.
- If you want to instead setup on a machine other than a Linode VPS, such as an AWS machine or a Mac, goto §2.2: Setting Up a Bitcoin-Core via Other Means
- If you already have a Bitcoin node running, goto Chapter Three: Understanding Your Bitcoin Setup.
Getting Started with Linode
Linode is a Cloud Hosting service that offers quick, cheap Linux servers with SSD storage. We use them for this tutorial primarily because their BASH-driven StackScripts offer an easy way to automatically set up a Bitcoin node with no fuss and no muss.
Set Up a Linode Account
You can create a Linode account by going here:
https://www.linode.com
If you prefer, the following referral code will give you two months worth of free usage (up to $100), great for learning Bitcoin:
https://www.linode.com/?r=3c7fa15a78407c9a3d4aefb027539db2557b3765
You'll need to provide an email address and later preload money from a credit card or PayPal for future costs.
When you're done, you should land on https://cloud.linode.com/dashboard.
Consider Two-Factor Authentication
Your server security won't be complete if people can break into your Linode account, so consider setting up Two-Factor Authentication for it. You can find this setting on your My Profile: Password & Authentication page. If you don't do this now, make a TODO item to come back and do it later.
Creating the Linode Image using a StackScript
Load the StackScript
Download the Linode Standup Script from the Bitcoin Standup Scripts repo. This script basically automates all Bitcoin VPS setup instructions. If you want to be particulary prudent, read it over carefully. If you are satisfied, you can copy that StackScript into your own account by going to the Stackscripts page on your Linode account and selecting to Create New Stackscript. Give it a good name (we use Bitcoin Standup
), then copy and paste the script. Choose Debian 11 for your target image and "Save" it.
Do the Initial Setup
You're now ready to create a node based on the Stackscript.
- On the Stackscripts page, click on the "..." to the right of your new script and choose "Deploy New Linode".
- Fill in a short and a fully qualified hostname
- Short Hostname. Pick a name for your VPS. For example, "mybtctest".
- Fully Qualified Hostname. If you're going to include this VPS as part of a network with full DNS records, type in the hostname with its domain. For example, "mybtctest.mydomain.com". Otherwise, just repeat the short hostname and add ".local", for example "mybtctest.local".
- Enter the password for the "standup" user.
- Fill in the appropriate advanced options.
- X25519 Public Key. This is a public key to add to Tor's list of authorized clients. If you don't use it, anyone who gets the QR code for your node can access it. You'll get this public key from whichever client you're using to connect to your node. For example, if you use FullyNoded 2, you can go to its settings and "Export Tor V3 Authentication Public Key" for use here.
- Installation Type. This is likely "Mainnet" or "Pruned Mainnet" if you are setting up a node for usage and "Testnet" or "Pruned Testnet" if you're just playing around. The bulk of this tutorial will assume you chose "Pruned Testnet", but you should still be able to follow along with other types. See the Synopsis for more information on these options. (Note that if you plan to try out the Lightning chapters, you'll probably want to use an Unpruned node, as working with Pruned nodes on Lightning is iffy. See §18.1 for the specifics.)
- SSH Key. Copy your local computer's SSH key here; this allows you be able to automatically login in via SSH to the standup account. If you haven't setup an SSH key on your local computer yet, there are good instructions for it on Github. You may also want to add your SSH key into your Linode LISH (Linode Interactive Shell) by going to your "Linode Home Page / My Preferences / LISH Settings / LISH Keys". Using an SSH key will give you a simpler and safer way to log in to your server.
- SSH-Allowed IPs. This is a comma-separated list of IPs that will be allowed to SSH into the VPS. For example "192.168.1.15,192.168.1.16". If you do not enter any IPs, your VPS will not be very secure. It will constantly be bombarded by attackers trying to find their way in, and they may very well succeed.
- Select an Image
- Target Image. If you followed the instructions, this will only allow you to select "Debian 11" (though previous versions of this Stackscript worked with Debian 9 or 10and might still).
- Choose a region for where the Linode will be located.
The remaining questions all have to do with the mechanics of the VPS deployment and should be left as they are with one exception: bump the Swap Disk from 256MB to 512MB, to ensure that you have enough memory to download the blockchain.
Choose Other Standup Options
Blockchain Commons is currently in the process of expanding its Bitcoin Standup Scripts with options to install Lightning and other Bitcoin apps of note. Take a look at any extra options, and see if they're things that you'd like to play with. In particular, if Lightning is an option, we suggest installing it, because it will make Chapter 18 and Chapter 19 much easier.
Choose a Linode Plan
You'll next to choose a Linode plan.
Linode will default to Dedicated-CPU plans, but you can select the more cost-efficient Shared-CPU instead. A Shared-CPU Linode 4GB will suffice for most setups, including: Pruned Mainnet, Pruned Testnet, and even non-Pruned Testnet. They all use less than 50G of storage and 4GB is a comfortable amount of memory. This is the setup we suggest. It runs $20 per month.
If you want to instead have a non-Pruned Mainnet in a VPS, you'll need to install a Linode with a disk in excess of 280G(!), which is currently the Linode 16GB, which has 320G of storage and 16G of memory and costs approximately $80 per month. We do not suggest this.
The following chart shows minimum requirements
Setup | Memory | Storage | Linnode |
---|---|---|---|
Mainnet | 2G | 280G | Linode 16GB |
Pruned Mainnet | 2G | ~5G | Linode 4GB |
Testnet | 2G | ~15G | Linode 4GB |
Pruned Testnet | 2G | ~5G | Linode 4GB |
Regtest | 2G | ~ | Linode 4GB |
Note, there may be ways to reduce both costs.
- For the machines we suggest as Linode 4GB, you may be able to reduce that to a Linode 2GB. Some versions of Bitcoin Core have worked well at that size, some have occasionally run out of memory and then recovered, and some have continuously run out of memory. Remember to up that swap space to maximize the odds of this working. Use at your own risk.
- For the Unpruned Mainnet, which we suggest as a Linode 16GB, you can probably get by with a Linode 4GB, but add Block Storage sufficient to store the blockchain. This is certainly a better long-term solution since the Bitcoin blockchain's storage requirements continuously increase if you don't prune, while the CPU requirements don't (or don't to the same degree). A 320 GibiByte storage would be $32 a month, which combined with a Linode 4GB is $52 a month, instead of $80, and more importantly you can keep growing it. We don't fully document this setup for two reasons (1) we don't suggest the unpruned mainnet setup, and so we suspect it's a much less common setup; and (2) we haven't tested how Linodes volumes compare to their intrinic SSDs for performance and usage. But there's full documentation on the Block Storage page. You'd need to set up the Linode, run its stackscript, but then interrupt it to move the blockchain storage overly to a newly commissioned volume before continuing.
If you are running a deployment that will be transacting real Bitcoins, you may want to alternatively consider a Dedicated-CPU Linode, which tends to run 50% more expensive than the Shared-CPU Linode. We've generally found the Shared CPUs to be entirely sufficient, but for a wide deployment, you may wish to consider higher levels of reliability.
Do the Final Setup
The last thing you need to do is enter a root password. (If you missed anything, you'll be told so now!)
Click "Deploy" to initialize your disks and to prepare your VPS. The whole queue should run in less than a minute. When it's done you should see in the "Host Job Queue", green "Success" buttons stating "Disk Create from StackScript - Setting password for root… done." and "Create Filesystem - 256MB Swap Image".
You may now want to change your Linode VPS's name from the default linodexxxxxxxx
. Go to the Settings tab, and change the label to be more useful, such as your VPS's short hostname. For instance you might name it bitcoin-testnet-pruned
to differentiate it from other VPSs in your account.
Login to Your VPS
If you watch your Linode control panel, you should see the new computer spin up. When the job has reached 100%, you'll be able to login.
First, you'll need the IP address. Click on the "Linodes" tab and you should see a listing of your VPS, the fact that it's running, its "plan", its IP address, and some other information.
Go to your local console and login to the standup
account using that address:
ssh standup@[IP-ADDRESS]
For example:
ssh standup@192.168.33.11
If you configured your VPS to use an SSH key, the login should be automatic (possibly requiring your SSH password to unlock your key). If you didn't configure a SSH key, then you'll need to type in the user1 password.
Wait a Few Minutes
Here's a little catch: your StackScript is running right now. The BASH script gets executed the first time the VPS is booted. That means your VPS isn't ready yet.
The total run time is about 10 minutes. So, go take a break, get an espresso, or otherwise relax for a few minutes. There are two parts of the script that take a while: the updating of all the Debian packages; and the downloading of the Bitcoin code. They shouldn't take more than 5 minutes each, which means if you come back in 10 minutes, you'll probably be ready to go.
If you're impatient you can jump ahead and sudo tail -f /standup.log
which will display the current progress of installation, as described in the next section.
Verify Your Installation
You'll know that stackscrpit is done when the tail
of the standup.log
says something like the following:
/root/StackScript - Bitcoin is setup as a service and will automatically start if your VPS reboots and so is Tor
/root/StackScript - You can manually stop Bitcoin with: sudo systemctl stop bitcoind.service
/root/StackScript - You can manually start Bitcoin with: sudo systemctl start bitcoind.service
At that point, your home directory should look like this:
$ ls
bitcoin-22.0-x86_64-linux-gnu.tar.gz keys.txt SHA256SUMS SHA256SUMS.asc
These are the various files that were used to install Bitcoin on your VPS. None of them are necessary. We've just left them in case you want to do any additional verification. Otherwise, you can delete them:
$ rm *
Verify the Bitcoin Setup
In order to ensure that the downloaded Bitcoin release is valid, the StackScript checks both the signature and the SHA checksum. You should verify that both of those tests came back right:
$ sudo grep VERIFICATION /standup.log
If you see something like the following, all should be well:
./standup.sh - SIG VERIFICATION SUCCESS: 9 GOOD SIGNATURES FOUND.
./standup.sh - SHA VERIFICATION SUCCESS / SHA: bitcoin-22.0-x86_64-linux-gnu.tar.gz: OK
If either of those two checks instead reads "VERIFICATION ERROR", then there's a problem.
The log also contains more information on the Signatures, if you want to make sure you know who signed the Bitcoin release:
$ sudo grep -i good /standup.log
./standup.sh - SIG VERIFICATION SUCCESS: 9 GOOD SIGNATURES FOUND.
gpg: Good signature from "Andrew Chow (Official New Key) <achow101@gmail.com>" [unknown]
gpg: Good signature from "Ben Carman <benthecarman@live.com>" [unknown]
gpg: Good signature from "Antoine Poinsot <darosior@protonmail.com>" [unknown]
gpg: Good signature from "Stephan Oeste (it) <it@oeste.de>" [unknown]
gpg: Good signature from "Michael Ford (bitcoin-otc) <fanquake@gmail.com>" [unknown]
gpg: Good signature from "Oliver Gugger <gugger@gmail.com>" [unknown]
gpg: Good signature from "Hennadii Stepanov (hebasto) <hebasto@gmail.com>" [unknown]
gpg: Good signature from "Jon Atack <jon@atack.com>" [unknown]
gpg: Good signature from "Wladimir J. van der Laan <laanwj@visucore.com>" [unknown]
Since this is all scripted, it's possible that there's just been a minor change that has caused the script's checks not to work right. (This has happened a few times over the existence of the script that became Standup.) But, it's also possible that someone is trying to encourage you to run a fake copy of the Bitcoin daemon. So, be very sure you know what happened before you make use of Bitcoin!
Read the Logs
You may also want to read through all of the setup log files, to make sure that nothing unexpected happened during the installation.
It's best to look through the standard StackScript log file, which has all of the output, including errors:
$ sudo more /standup.log
Note that it is totally normal to see some errors, particularly when running the very noisy gpg software and when various things try to access the non-existant /dev/tty
device.
If you want instead to look at a smaller set of info, all of the errors should be in:
$ sudo more /standup.err
It still has a fair amount of information that isn't errors, but it's a quicker read.
If all look good, congratulations, you have a functioning Bitcoin node using Linode!
What We Have Wrought
Although the default Debian 11 image that we are using for your VPS has been modified by Linode to be relatively secure, your Bitcoin node as installed through the Linode StackScript is set up with an even higher level of security. You may find this limiting, or be unable to do things that you expect. Here are a few notes on that:
Protected Services
Your Bitcoin VPS installation is minimal and allows almost no communication. This is done through the uncomplicated firewall (ufw
), which blocks everything except SSH connections. There's also some additional security possible for your RFC ports, thanks to the hidden services installed by Tor.
Adjusting UFW. You should probably leave UFW in its super-protected stage! You don't want to use a Bitcoin machine for other services, because everyone increases your vulnerability! If you decide otherwise, there are several guides to UFW that will allow you to add services. As advertised, it's uncomplicated. For example adding mail services would just require opening the mail port: sudo ufw allow 25
. But don't do that.
Adjusting Tor. You might want to better protect services like SSH. See Chapter 14: Using Tor for more on Tor.
Protected Shells
If you defined "SSH-allowed IPs", SSH (and SCP) access to the server is severely restricted. /etc/hosts.deny
disallows anyone from logging in. We do not suggest changing this. /etc/hosts.allow
then allows specific IP addresses. Just add more IP addresses in a comma-separated list if you need to offer more access.
For example:
sshd: 127.0.0.1, 192.128.23.1
Automated Upgrades
Debian is also set up to automatically upgrade itself, to ensure that it remains abreast of the newest security patches.
If for some reason you wanted to change this (we don't suggest it), you can do this:
echo "unattended-upgrades unattended-upgrades/enable_auto_updates boolean false" | debconf-set-selections
If you'd like to know more about what the Bitcoin Standup stackscript does, please see Appendix I: Understanding Bitcoin Standup.
Playing with Bitcoin
So now you probably want to play with Bitcoin!
But wait, your Bitcoin daemon is probably still downloading blocks. The bitcoin-cli getblockcount
will tell you how you're currently doing:
$ bitcoin-cli getblockcount
1771352
If it's different every time you type the command, you need to wait before working with Bitcoin. This takes 1-6 hours currently for a pruned setup, depending on your precise machine.
But, once it settles at a number, you're ready to continue!
Still, it might be time for a few more espressos. But soon enough, your system will be ready to go, and you'll be read to start experimenting.
Summary: Setting Up a Bitcoin-Core VPS by Hand
Creating a Bitcoin-Core VPS with the Standup scripts made the whole process quick, simple and (hopefully) painless.
What's Next?
You have a few options for what's next:
- Read the StackScript to understand your setup.
- Read what the StackScript does in Appendix I.
- Choose an entirely alternate methodology in §2.2: Setting Up a Bitcoin-Core Machine via Other Means.
- Move on to "bitcoin-cli" with Chapter Three: Understanding Your Bitcoin Setup.
Synopsis: Bitcoin Installation Types
Mainnet. This will download the entirety of the Bitnet blockchain. That's 280G of data (and getting more every day).
Pruned Mainnet. This will cut the blockchain you're storing down to just the last 550 blocks. If you're not mining or running some other Bitcoin service, this should be plenty for validation.
Testnet. This gives you access to an alternative Bitcoin blockchain where the Bitcoins don't actually have value. It's intended for experimentation and testing.
Pruned Testnet. This is just the last 550 blocks of Testnet ... because the Testnet blockchain is pretty big now too.
Private Regtest. This is Regression Testing Mode, which lets you run a totally local Bitcoin server. It allows for even more in-depth testing. There's no pruning needed here, because you'll be starting from scratch. This is a very different setup, and so is covered in Appendix 3.
2.2: Setting Up a Bitcoin-Core Machine via Other Means
The previous section, §2.1: Setting Up a Bitcoin-Core VPS with Bitcoin Standup, presumed that you would be creating a full node on a VPS using a Linode Stackscript. However, you can actually create a Bitcoin-Core instance via any methodology of your choice and still follow along with the later steps of this tutorial.
Following are other setup methodologies that we are aware of:
- Compiling from Source. If you prefer to compile Bitcoin Core by hand, that's covered in Appendix 2.
- Using GordianNode-macOS. If you have a modern Mac, you can use Blockchain Commons' GordianNode app, powered by BitcoinStandup, to install a full node on your Mac.
- Using Other Bitcoin Standup Scripts. Blockchain Commons also offers a version of the Linode script that you used that can be run from the command line on any Debian or Ubuntu machine. This tends to be the leading-edge script, which means that it's more likely to feature new functions, like Lightning installation.
- Setting Up a Bitcoin Node on AWS. @wolfmcnally has written a step-by-step tutorial for setting up Bitcoin-Core with Amazon Web Services (AWS).
- Setting Up a Bitcoin Node on a Raspberry Pi 3. Damian Mee explains how to set up a headless full node on a Raspberry Pi 3.
What's Next?
Unless you want to return to one of the other methodologies for creating a Bitcoin-Core node, you should:
- Move on to "bitcoin-cli" with Chapter Three: Understanding Your Bitcoin Setup.
Chapter Three: Understanding Your Bitcoin Setup
You're now ready to begin working with the bitcoin-cli
command-line interface. But that first requires that you understand your Bitcoin setup and its wallet features, which is what will be explained in this chapter.
For this and future chapters, we presume that you have a VPS with Bitcoin installed, running bitcoind
. We also presume that you are connected to testnet, allowing for access to bitcoins without using real funds. You can either do this with Bitcoin Standup at Linode.com, per §2.1: Setting up a Bitcoin-Core VPS with Bitcoin Standup, or via other means, per §2.2: Setting up a Bitcoin-Core Machine via Other Means.
Objectives for This Chapter
After working through this chapter, a developer will be able to:
- Demonstrate that Their Bitcoin Node is Installed and Up-to-date
- Create an Address to Receive Bitcoin Funds
- Use Basic Wallet Commands
- Create an Address from a Descriptor
Supporting objectives include the ability to:
- Understand the Basic Bitcoin File Layout
- Use Basic Informational Commands
- Understand What a Bitcoin Address Is
- Understand What a Wallet Is
- Understand How to Import Addresses
Table of Contents
- Section One: Verifying Your Bitcoin Setup
- Section Two: Knowing Your Bitcoin Setup
- Section Three: Setting Up Your Wallet
- Section Four: Receiving a Transaction
- Section Five: Understanding the Descriptor
3.1: Verifying Your Bitcoin Setup
Before you start playing with Bitcoin, you should ensure that everything is setup correctly.
Create Your Aliases
We suggest creating some aliases to make it easier to use Bitcoin.
You can do so by putting them in your .bash_profile
, .bashrc
or .profile
.
cat >> ~/.bash_profile <<EOF
alias btcdir="cd ~/.bitcoin/" #linux default bitcoind path
alias bc="bitcoin-cli"
alias bd="bitcoind"
alias btcinfo='bitcoin-cli getwalletinfo | egrep "\"balance\""; bitcoin-cli getnetworkinfo | egrep "\"version\"|connections"; bitcoin-cli getmininginfo | egrep "\"blocks\"|errors"'
EOF
After you enter these aliases you can either source .bash_profile
to input them or just log out and back in.
Note that these aliases includes shortcuts for running bitcoin-cli
, for running bitcoind
, and for going to the Bitcoin directory. These aliases are mainly meant to make your life easier. We suggest you create other aliases to ease your use of frequent commands (and arguments) and to minimize errors. Aliases of this sort can be even more useful if you have a complex setup where you regularly run commands associated with Mainnet, with Testnet, and with Regtest, as explained further below.
With that said, use of these aliases in this document might accidentally obscure the core lessons being taught about Bitcoin, so the only alias directly used here is btcinfo
because it encapsulates much longer and more complex command. Otherwise, we show the full commands; adjust for your own use as appropriate.
Run Bitcoind
You'll begin your exploration of the Bitcoin network with the bitcoin-cli
command. However, bitcoind must be running to use bitcoin-cli, as bitcoin-cli sends JSON-RPC commands to the bitcoind. If you used our standard setup, bitcoind should already be up and running. You can double check by looking at the process table.
$ ps auxww | grep bitcoind
standup 455 1.3 34.4 3387536 1392904 ? SLsl Jun16 59:30 /usr/local/bin/bitcoind -conf=/home/standup/.bitcoin/bitcoin.conf
If it's not running, you'll want to run /usr/local/bin/bitcoind -daemon
by hand and also place it in your crontab.
Verify Your Blocks
You should have the whole blockchain downloaded before you start playing. Just run the bitcoin-cli getblockcount
alias to see if it's all loaded.
$ bitcoin-cli getblockcount
1772384
That tells you what's loaded; you'll then need to check that against an online service that tells you the current block height.
:book: What is Block Height? Block height is the the distance that a particular block is removed from the genesis block. The current block height is the block height of the newest block added to a blockchain.
You can do this by looking at a blocknet explorer, such as the Blockcypher Testnet explorer. Does its most recent number match your getblockcount
? If so, you're up to date.
If you'd like an alias to look at everything at once, the following currently works for Testnet, but may disappear at some time in the future:
$ cat >> ~/.bash_profile << EOF
alias btcblock="echo \\\`bitcoin-cli getblockcount 2>&1\\\`/\\\`wget -O - https://blockstream.info/testnet/api/blocks/tip/height 2> /dev/null | cut -d : -f2 | rev | cut -c 1- | rev\\\`"
EOF
$ source .bash_profile
$ btcblock
1804372/1804372
:link: TESTNET vs MAINNET: Remember that this tutorial generally assumes that you are using testnet. If you're using the mainnet instead, you can retrieve the current block height with:
wget -O - http://blockchain.info/q/getblockcount 2>/dev/null
. You can replace the latter half of thebtblock
alias (after/
) with that.
If you're not up-to-date, but your getblockcount
is increasing, no problem. Total download time can take from an hour to several hours, depending on your setup.
Optional: Know Your Server Types
TESTNET vs MAINNET: When you set up your node, you choose to create it as either a Mainnet, Testnet, or Regtest node. Though this document presumes a testnet setup, it's worth understanding how you might access and use the other setup types — even all on the same machine! But, if you're a first-time user, skip on past this, as it's not necessary for a basic setup.
The type of setup is mainly controlled through the ~/.bitcoin/bitcoin.conf file. If you're running testnet, it probably contains this line:
testnet=1
If you're running regtest, it probably contains this line:
regtest=1
However, if you want to run several different sorts of nodes simultaneously, you should leave the testnet (or regtest) flag out of your configuration file. You can then choose whether you're using the mainnet, the testnet, or your regtest every time you run bitcoind or bitcoin-cli.
Here's a set of aliases that would make that easier by creating a specific alias for starting and stopping the bitcoind, for going to the bitcoin directory, and for running bitcoin-cli, for each of the mainnet (which has no extra flags), the testnet (which is -testnet), or your regtest (which is -regtest).
cat >> ~/.bash_profile <<EOF
alias bcstart="bitcoind -daemon"
alias btstart="bitcoind -testnet -daemon"
alias brstart="bitcoind -regtest -daemon"
alias bcstop="bitcoin-cli stop"
alias btstop="bitcoin-cli -testnet stop"
alias brstop="bitcoin-cli -regtest stop"
alias bcdir="cd ~/.bitcoin/" #linux default bitcoin path
alias btdir="cd ~/.bitcoin/testnet" #linux default bitcoin testnet path
alias brdir="cd ~/.bitcoin/regtest" #linux default bitcoin regtest path
alias bc="bitcoin-cli"
alias bt="bitcoin-cli -testnet"
alias br="bitcoin-cli -regtest"
EOF
For even more complexity, you could have each of your 'start' aliases use the -conf flag to load configuration from a different file. This goes far beyond the scope of this tutorial, but we offer it as a starting point for when your explorations of Bitcoin reaches the next level.
Summary: Verifying Your Bitcoin Setup
Before you start playing with bitcoin, you should make sure that your aliases are set up, your bitcoind is running, and your blocks are downloaded. You may also want to set up some access to alternative Bitcoin setups, if you're an advanced user.
What's Next?
Continue "Understanding Your Bitcoin Setup" with §3.2: Knowing Your Bitcoin Setup.
3.2: Knowing Your Bitcoin Setup
Before you start playing with Bitcoin, you may always want to come to a better understanding of your setup.
Know Your Bitcoin Directory
To start with, you should understand where everything is kept: the ~/.bitcoin
directory.
The main directory just contains your config file and the testnet directory:
$ ls ~/.bitcoin
bitcoin.conf testnet3
The setup guides in Chapter Two: Creating a Bitcoin-Core VPS laid out a standardized config file. §3.1: Verifying Your Bitcoin Setup suggested how to change it to support more advanced setups. If you're interested in learning even more about the config file, you may wish to consult Jameson Lopp's Bitcoin Core Config Generator.
Moving back to your ~/.bitcoin directory, you'll find that the testnet3 directory contains all of the guts:
$ ls ~/.bitcoin/testnet3
banlist.dat blocks debug.log mempool.dat peers.dat
bitcoind.pid chainstate fee_estimates.dat onion_private_key wallets
You shouldn't mess with most of these files and directories — particularly not the blocks
and chainstate
directories, which contain all of the blockchain data, and the information in your wallets
directory, which contains your personal wallet. However, do take careful note of the debug.log
file, which you should refer to if you ever have problems with your setup.
:link: TESTNET vs MAINNET: If you're using mainnet, then everything will instead be placed in the main
~/.bitcoin
directory. These various setups do elegantly stack, so if you are using mainnet, testnet, and regtest, you'll find that~/.bitcoin
contains your config file and your mainnet data, the~/.bitcoin/testnet3
directory contains your testnet data, and the~/.bitcoin/regtest
directory contains your regtest data.
Know Your Bitcoin-cli Commands
Most of your early work will be done with the bitcoin-cli
command, which offers an easy interface to bitcoind
. If you ever want more information on its usage, just run it with the help
argument. Without any other arguments, it shows you every possible command:
$ bitcoin-cli help
== Blockchain ==
getbestblockhash
getblock "blockhash" ( verbosity )
getblockchaininfo
getblockcount
getblockfilter "blockhash" ( "filtertype" )
getblockhash height
getblockheader "blockhash" ( verbose )
getblockstats hash_or_height ( stats )
getchaintips
getchaintxstats ( nblocks "blockhash" )
getdifficulty
getmempoolancestors "txid" ( verbose )
getmempooldescendants "txid" ( verbose )
getmempoolentry "txid"
getmempoolinfo
getrawmempool ( verbose )
gettxout "txid" n ( include_mempool )
gettxoutproof ["txid",...] ( "blockhash" )
gettxoutsetinfo
preciousblock "blockhash"
pruneblockchain height
savemempool
scantxoutset "action" ( [scanobjects,...] )
verifychain ( checklevel nblocks )
verifytxoutproof "proof"
== Control ==
getmemoryinfo ( "mode" )
getrpcinfo
help ( "command" )
logging ( ["include_category",...] ["exclude_category",...] )
stop
uptime
== Generating ==
generatetoaddress nblocks "address" ( maxtries )
generatetodescriptor num_blocks "descriptor" ( maxtries )
== Mining ==
getblocktemplate ( "template_request" )
getmininginfo
getnetworkhashps ( nblocks height )
prioritisetransaction "txid" ( dummy ) fee_delta
submitblock "hexdata" ( "dummy" )
submitheader "hexdata"
== Network ==
addnode "node" "command"
clearbanned
disconnectnode ( "address" nodeid )
getaddednodeinfo ( "node" )
getconnectioncount
getnettotals
getnetworkinfo
getnodeaddresses ( count )
getpeerinfo
listbanned
ping
setban "subnet" "command" ( bantime absolute )
setnetworkactive state
== Rawtransactions ==
analyzepsbt "psbt"
combinepsbt ["psbt",...]
combinerawtransaction ["hexstring",...]
converttopsbt "hexstring" ( permitsigdata iswitness )
createpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime replaceable )
createrawtransaction [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime replaceable )
decodepsbt "psbt"
decoderawtransaction "hexstring" ( iswitness )
decodescript "hexstring"
finalizepsbt "psbt" ( extract )
fundrawtransaction "hexstring" ( options iswitness )
getrawtransaction "txid" ( verbose "blockhash" )
joinpsbts ["psbt",...]
sendrawtransaction "hexstring" ( maxfeerate )
signrawtransactionwithkey "hexstring" ["privatekey",...] ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" )
testmempoolaccept ["rawtx",...] ( maxfeerate )
utxoupdatepsbt "psbt" ( ["",{"desc":"str","range":n or [n,n]},...] )
== Util ==
createmultisig nrequired ["key",...] ( "address_type" )
deriveaddresses "descriptor" ( range )
estimatesmartfee conf_target ( "estimate_mode" )
getdescriptorinfo "descriptor"
signmessagewithprivkey "privkey" "message"
validateaddress "address"
verifymessage "address" "signature" "message"
== Wallet ==
abandontransaction "txid"
abortrescan
addmultisigaddress nrequired ["key",...] ( "label" "address_type" )
backupwallet "destination"
bumpfee "txid" ( options )
createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse )
dumpprivkey "address"
dumpwallet "filename"
encryptwallet "passphrase"
getaddressesbylabel "label"
getaddressinfo "address"
getbalance ( "dummy" minconf include_watchonly avoid_reuse )
getbalances
getnewaddress ( "label" "address_type" )
getrawchangeaddress ( "address_type" )
getreceivedbyaddress "address" ( minconf )
getreceivedbylabel "label" ( minconf )
gettransaction "txid" ( include_watchonly verbose )
getunconfirmedbalance
getwalletinfo
importaddress "address" ( "label" rescan p2sh )
importmulti "requests" ( "options" )
importprivkey "privkey" ( "label" rescan )
importprunedfunds "rawtransaction" "txoutproof"
importpubkey "pubkey" ( "label" rescan )
importwallet "filename"
keypoolrefill ( newsize )
listaddressgroupings
listlabels ( "purpose" )
listlockunspent
listreceivedbyaddress ( minconf include_empty include_watchonly "address_filter" )
listreceivedbylabel ( minconf include_empty include_watchonly )
listsinceblock ( "blockhash" target_confirmations include_watchonly include_removed )
listtransactions ( "label" count skip include_watchonly )
listunspent ( minconf maxconf ["address",...] include_unsafe query_options )
listwalletdir
listwallets
loadwallet "filename"
lockunspent unlock ( [{"txid":"hex","vout":n},...] )
removeprunedfunds "txid"
rescanblockchain ( start_height stop_height )
sendmany "" {"address":amount} ( minconf "comment" ["address",...] replaceable conf_target "estimate_mode" )
sendtoaddress "address" amount ( "comment" "comment_to" subtractfeefromamount replaceable conf_target "estimate_mode" avoid_reuse )
sethdseed ( newkeypool "seed" )
setlabel "address" "label"
settxfee amount
setwalletflag "flag" ( value )
signmessage "address" "message"
signrawtransactionwithwallet "hexstring" ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" )
unloadwallet ( "wallet_name" )
walletcreatefundedpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime options bip32derivs )
walletlock
walletpassphrase "passphrase" timeout
walletpassphrasechange "oldpassphrase" "newpassphrase"
walletprocesspsbt "psbt" ( sign "sighashtype" bip32derivs )
== Zmq ==
getzmqnotifications
You can also type bitcoin-cli help [command]
to get even more extensive info on that command. For example:
$ bitcoin-cli help getmininginfo
...
Returns a json object containing mining-related information.
Result:
{ (json object)
"blocks" : n, (numeric) The current block
"currentblockweight" : n, (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)
"currentblocktx" : n, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)
"difficulty" : n, (numeric) The current difficulty
"networkhashps" : n, (numeric) The network hashes per second
"pooledtx" : n, (numeric) The size of the mempool
"chain" : "str", (string) current network name (main, test, regtest)
"warnings" : "str" (string) any network and blockchain warnings
}
Examples:
> bitcoin-cli getmininginfo
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getmininginfo", "params": []}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
:book: What is RPC?
bitcoin-cli
is just a handy interface that lets you send commands to thebitcoind
. More specifically, it's an interface that lets you send RPC (or Remote Procedure Protocol) commands to thebitcoind
. Often, thebitcoin-cli
command and the RPC command have identical names and interfaces, but somebitcoin-cli
commands instead provide shortcuts for more complex RPC requests. Generally, thebitcoin-cli
interface is much cleaner and simpler than trying to send RPC commands by hand, usingcurl
or some other method. However, it also has limitations as to what you can ultimately do.
Optional: Know Your Bitcoin Info
A variety of bitcoin-cli commands can give you additional information on your bitcoin data. The most general ones are:
bitcoin-cli -getinfo
returns information from different RPCs (user-friendly)
$ bitcoin-cli -getinfo
! Chain: test
Blocks: 1977694
Headers: 1977694
Verification progress: 0.9999993275374796
Difficulty: 1
+ Network: in 0, out 8, total 8
Version: 219900
Time offset (s): 0
Proxy: N/A
Min tx relay fee rate (BTC/kvB): 0.00001000
@@ Wallet: ""@@
Keypool size: 1000
Unlocked until: 0
Transaction fee rate (-paytxfee) (BTC/kvB): 0.00000000
# Balance: 0.02853102
- Warnings: unknown new rules activated (versionbit 28)
Other commands to get information about blockchain, mining, network, wallet etc.
$ bitcoin-cli getblockchaininfo
$ bitcoin-cli getmininginfo
$ bitcoin-cli getnetworkinfo
$ bitcoin-cli getnettotals
$ bitcoin-cli getwalletinfo
For example bitcoin-cli getnetworkinfo
gives you a variety of information on your setup and its access to various networks:
$ bitcoin-cli getnetworkinfo
{
"version": 200000,
"subversion": "/Satoshi:0.20.0/",
"protocolversion": 70015,
"localservices": "0000000000000408",
"localservicesnames": [
"WITNESS",
"NETWORK_LIMITED"
],
"localrelay": true,
"timeoffset": 0,
"networkactive": true,
"connections": 10,
"networks": [
{
"name": "ipv4",
"limited": false,
"reachable": true,
"proxy": "",
"proxy_randomize_credentials": false
},
{
"name": "ipv6",
"limited": false,
"reachable": true,
"proxy": "",
"proxy_randomize_credentials": false
},
{
"name": "onion",
"limited": false,
"reachable": true,
"proxy": "127.0.0.1:9050",
"proxy_randomize_credentials": true
}
],
"relayfee": 0.00001000,
"incrementalfee": 0.00001000,
"localaddresses": [
{
"address": "45.79.111.171",
"port": 18333,
"score": 1
},
{
"address": "2600:3c01::f03c:92ff:fecc:fdb7",
"port": 18333,
"score": 1
},
{
"address": "4wrr3ktm6gl4sojx.onion",
"port": 18333,
"score": 4
}
],
"warnings": "Warning: unknown new rules activated (versionbit 28)"
}
Feel free to reference any of these and to use "bitcoin-cli help" if you want more information on what any of them do.
Summary: Knowing Your Bitcoin Setup
The ~/.bitcoin
directory contains all of your files, while bitcoin-cli help
and a variety of info commands can be used to get more information on how your setup and Bitcoin work.
What's Next?
Continue "Understanding Your Bitcoin Setup" with §3.3: Setting Up Your Wallet.
Interlude: Using Command-Line Variables
The previous section demonstrated a number of command-line commands used without obfuscation or interference. However, that's often not the best way to run Bitcoin from the command line. Because you're dealing with long, complex, and unreadable variables, it's easy to make a mistake if you're copying those variables around (or, satoshi forfend, if you're typing them in by hand). Because those variables can mean the difference between receiving and losing real money, you don't want to make mistakes. For these reasons, we strongly suggest using command-line variables to save addresses, signatures, or other long strings of information whenever it's reasonable to do so.
If you're using bash
, you can save information to a variable like this:
$ VARIABLE=$(command)
That's a simple command substitution, the equivalent to VARIABLE=`command`
. The command inside the parentheses is run, then assigned to the VARIABLE.
To create a new address would then look like this:
$ unset NEW_ADDRESS_1
$ NEW_ADDRESS_1=$(bitcoin-cli getnewaddress "" legacy)
These commands clear the NEW_ADDRESS_1 variable, just to be sure, then fill it with the results of the bitcoin-cli getnewaddress
command.
You can then use your shell's echo
command to look at your (new) address:
$ echo $NEW_ADDRESS_1
mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE
Because you have your address in a variable, you can now easily sign a message for that address, without worrying about mistyping the address. You'll of course save that signature into a variable too!
$ NEW_SIG_1=$(bitcoin-cli signmessage $NEW_ADDRESS_1 "Hello, World")
$ echo $NEW_SIG_1
IPYIzgj+Rg4bxDwCyoPiFiNNcxWHYxgVcklhmN8aB2XRRJqV731Xu9XkfZ6oxj+QGCRmTe80X81EpXtmGUpXOM4=
The rest of this tutorial will use this style of saving information to variables when it's practical.
:book: When is it not practical to use command-line variables? Command-line variables aren't practical if you need to use the information somewhere other than on the command line. For example, saving your signature may not actually be useful if you're just going to have to send it to someone else in an email. In addition, some future commands will output JSON objects instead of simple information, and variables can't be used to capture that information ... at least not without a little more work.
Summary: Using Command-Line Variables
Shell variables can be used to hold long Bitcoin strings, minimizing the chances of mistakes.
What's Next?
Continue "Understanding Your Bitcoin Setup" with §3.4: Receiving a Transaction.
3.3: Setting Up Your Wallet
You're now ready to start working with Bitcoin. To begin with, you'll need to create a wallet for sending and receiving funds.
Create a Wallet
:warning: VERSION WARNING: Newer versions of Bitcoin Core, starting with v0.21.0, will no longer automatically create a default wallet on startup. So, you will need to manually create one. But if you're running an older version of Bitcoin Core, a new wallet has already been created for you, in which case you can skip ahead to Create an Address.
The first thing you need to do is create a new wallet, which can be done with the bitcoin-cli createwallet
command. By creating a new wallet, you'll be creating your public-private key pair. Your public key is the source from which your addresses will be created, and your private key is what will allow you to spend any funds you receive into your addresses. Bitcoin Core will automatically save that information into a wallet.dat
file in your ~/.bitcoin/testnet3/wallets
directory.
If you check your wallets
directory, you'll see that it's currently empty.
$ ls ~/.bitcoin/testnet3/wallets
$
Although Bitcoin Core won't create a new wallet for you, it will still load a top-level unnamed ("") wallet on startup by default. You can take advantage of this by creating a new unnamed wallet.
$ bitcoin-cli createwallet ""
{
"name": "",
"warning": ""
}
Now, your wallets
directory should be populated.
$ ls ~/.bitcoin/testnet3/wallets
database db.log wallet.dat
:book: What is a Bitcoin wallet? A Bitcoin wallet is the digital equivalent of a physical wallet on the Bitcoin network. It stores information on the amount of bitcoins you have and where it's located (addresses), as well as the ways you can use to spend it. Spending physical money is intuitive, but to spend bitcoins users need to provide the correct private key. We will explain this in more detail throughout the course, but what you should know for now is that this public-private key dynamic is part of what makes Bitcoin secure and trustless. Your key pair information is saved in the
wallet.dat
file, in addition to data about preferences and transactions. For the most part, you won't have to worry about that private key:bitcoind
will use it when it's needed. However, this makes thewallet.dat
file extremely important: if you lose it, you lose your private keys, and if you lose your private keys, you lose your funds!
Sweet, now you have a Bitcoin wallet. But a wallet will be of little use for receiving bitcoins if you don't create an address first.
Create an Address
The next thing you need to do is create an address for receiving payments. This is done with the bitcoin-cli getnewaddress
command. Remember that if you want more information on this command, you should type bitcoin-cli help getnewaddress
. Currently, there are three types of addresses: legacy
and the two types of SegWit address, p2sh-segwit
and bech32
. If you do not otherwise specify, you'll get the default, which is currently bech32
.
However, for the next few sections we're instead going to be using legacy
addresses, both because bitcoin-cli
had some teething problems with its early versions of SegWit addresses, and because other people might not be able to send to bech32
addresses. This is all unlikely to be a problem for you now, but for the moment we want to get your started with transaction examples that are (mostly) guaranteed to work.
First, restart bitcoind
so your new unnamed wallet is set as default and automatically loaded.
$ bitcoin-cli stop
Bitcoin Core stopping # wait a minute so it stops completely
$ bitcoind -daemon
Bitcoin Core starting # wait a minute so it starts completely
You can now create an address. You can require legacy
address either with the second argument to getnewaddress
or with the named addresstype
argument.
$ bitcoin-cli getnewaddress -addresstype legacy
moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B
Note that this address begins with an "m" (or sometimes an "n") to signify a testnet Legacy address. It would be a "2" for a P2SH address or a "tb1" for a Bech32 address.
:link: TESTNET vs MAINNET: The equivalent mainnet address would start with a "1" (for Legacy), "3" (for P2SH), or "bc1" (for Bech32).
Take careful note of the address. You'll need to give it to whomever will be sending you funds.
:book: What is a Bitcoin address? A Bitcoin address is literally where you receive money. It's like an email address, but for funds. Technically, it's a public key, though different address schemes adjust that in different ways. However unlike an email address, a Bitcoin address should be considered single use: use it to receive funds just once. When you want to receive funds from someone else or at some other time, generate a new address. This is suggested in large part to improve your privacy. The whole blockchain is immutable, which means that explorers can look at long chains of transactions over time, making it possible to statistically determine who you and your contacts are, no matter how careful you are. However, if you keep reusing the same address, then this becomes even easier. By creating your first Bitcoin address, you've also begun to fill in your Bitcoin wallet. More precisely, you've begun to fill the
wallet.dat
file in your~/.bitcoin/testnet3 /wallets
directory.
With a single address in hand, you could jump straight to the next section and begin receiving funds. However, before we get there, we're going to briefly discuss the other sorts of addresses that you'll meet in the future and talk about a few other wallet commands that you might want to use in the future.
Knowing Your Bitcoin Addresses
There are three types of Bitcoin addresses that you can create with the getnewaddress
RPC command. You'll be using a legacy
(P2PKH) address here, while you'll move over to a SegWit (P2SH-SegWit) or Bech32 address in §4.6: Creating a Segwit Transaction.
As noted above, the foundation of a Bitcoin address is a public key: someone sends funds to your public key, and then you use your private key to redeem it. Easy? Except putting your public key out there isn't entirely secure. At the moment, if someone has your public key, then they can't retrieve your private key (and thus your funds); that's the basis of cryptography, which uses a trap-door function to ensure that you can only go from private to public key, and not vice-versa. But the problem is that we don't know what the future might bring. Except we do know that cryptography systems eventually get broken by the relentless advance of technology, so it's better not to put raw public keys on the 'net, to future-proof your transactions.
Classic Bitcoin transactions created P2PKH addresses that added an additional cryptographic step to protect public keys.
:book: What is a Legacy (P2PKH) address? This is a Legacy address of the sort used by the early Bitcoin network. We'll be using it in examples for the next few sections. It's called a Pay to PubKey Hash (or P2PKH) address because the address is a 160-bit hash of a public key. Using a hash of your public key as your address creates a two-step process where to spend funds you need to reveal both the private key and the public key, and it increases future security accordingly. This sort of address remains important for receiving funds from people with out-of-date wallet software.
As described more fully in §4.6: Creating a Segwit Transaction, the Block Size Wars of the late '10s resulted in a new sort of address: SegWit. This is the preferred sort of address currently, and should be fully integrated into Bitcoin-Core at this point, but nonetheless we're saving it for §4.6.
SegWit simply means "segregated witness" and it's a way of separating the transaction signatures out from the rest of the transaction to reduce transaction size. Some SegWit addresses will sneak into some of our examples prior to §4.6 as change addresses, which you'll see as addresses that begin with "tb". This is fine because the bitcoin-cli
entirely supports their usage. But we won't use them otherwise.
There are two addresses of this sort:
:book: What is a P2SH-SegWit (aka Nested SegWit) address? This is the first generation of SegWit. It wraps the SegWit address in a Script hash to ensure backward compatibility. The result creates transactions that are about 25%+ smaller (with corresponding reductions in transaction fees).
:book: What is a Bech32 (aka Native SegWit, aka P2WPKH) address? This is the second generation of SegWit. It's fully described in BIP 173. It creates transactions that are even smaller but more notably also has some advantages in creating addresses that are less prone to human error and have some implicit error-correction beyond that. It is not backward compatible like P2SH-SegWit was, and so some people may not be able to send to it.
There are other sorts of Bitcoin addresses, such as P2PK (which paid to a bare public key, and is deprecated because of its future insecurity) and P2SH (which pays to a Script Hash, and which is used by the first-generation Nested SegWit addresses; we'll meet it more fully in a few chapters).
Optional: Sign a Message
Sometimes you'll need to prove that you control a Bitcoin address (or rather, that you control its private key). This is important because it lets people know that they're sending funds to the right person. This can be done by creating a signature with the bitcoin-cli signmessage
command, in the form bitcoin-cli signmessage [address] [message]
. For example:
$ bitcoin-cli signmessage "moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B" "Hello, World"
HyIP0nzdcH12aNbQ2s2rUxLwzG832HxiO1vt8S/jw+W4Ia29lw6hyyaqYOsliYdxne70C6SZ5Utma6QY/trHZBI=
You'll get the signature as a return.
:book: What is a signature? A digital signature is a combination of a message and a private key that can then be unlocked with a public key. Since there's a one-to-one correspendence between the elements of a keypair, unlocking with a public key proves that the signer controlled the corresponding private key.
Another person can then use the bitcoin-cli verifymessage
command to verify the signature. He inputs the address in question, the signature, and the message:
$ bitcoin-cli verifymessage "moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B" "HyIP0nzdcH12aNbQ2s2rUxLwzG832HxiO1vt8S/jw+W4Ia29lw6hyyaqYOsliYdxne70C6SZ5Utma6QY/trHZBI=" "Hello, World"
true
If they all match up, then the other person knows that he can safely transfer funds to the person who signed the message by sending to the address.
If some black hat was making up signatures, this would instead produce a negative result:
$ bitcoin-cli verifymessage "FAKEV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B" "HyIP0nzdcH12aNbQ2s2rUxLwzG832HxiO1vt8S/jw+W4Ia29lw6hyyaqYOsliYdxne70C6SZ5Utma6QY/trHZBI=" "Hello, World"
error code: -3
error message:
Invalid address
Optional: Dump Your Wallet
It might seem dangerous having all of your irreplaceable private keys in a single file. That's what bitcoin-cli dumpwallet
is for. It lets you make a copy of your wallet.dat:
$ bitcoin-cli dumpwallet ~/mywallet.txt
The mywallet.txt
file in your home directory will have a long list of private keys, addresses, and other information. Mind you, you'd never want to put this data out in a plain text file on a Bitcoin setup with real funds!
You can then recover it with bitcoin-cli importwallet
.
$ bitcoin-cli importwallet ~/mywallet.txt
But note this requires an unpruned node!
$ bitcoin-cli importwallet ~/mywallet.txt
error code: -4
error message:
Importing wallets is disabled when blocks are pruned
Optional: View Your Private Keys
Sometimes, you might want to actually look at the private keys associated with your Bitcoin addresses. Perhaps you want to be able to sign a message or spend bitcoins from a different machine. Perhaps you just want to back up certain important private keys. You can also do this with your dump file, since it's human readable.
$ bitcoin-cli dumpwallet ~/mywallet.txt
{
"filename": "/home/standup/mywallet.txt"
}
More likely, you just want to look at the private key associated with a specific address. This can be done with the bitcoin-cli dumpprivkey
command.
$ bitcoin-cli dumpprivkey "moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B"
cTv75T4B3NsG92tdSxSfzhuaGrzrmc1rJjLKscoQZXqNRs5tpYhH
You can then save that key somewhere safe, preferably somewhere not connected to the internet.
You can also import any private key, from a wallet dump or an individual key dump, as follows:
$ bitcoin-cli importprivkey cW4s4MdW7BkUmqiKgYzSJdmvnzq8QDrf6gszPMC7eLmfcdoRHtHh
Again, expect this to require an unpruned node. Expect this to take a while, as bitcoind
needs to reread all past transactions, to see if there are any new ones that it should pay attention to.
:information_source: NOTE: Many modern wallets prefer mnemonic codes to generate the seeds necessary to create the private keys. This methodology is not used
bitcoin-cli
, so you won't be able to generate handy word lists to remember your private keys.
You've been typing that Bitcoin address you generated a lot, while you were signing messages and now dumping keys. If you think it's a pain, we agree. It's also prone to errors, a topic that we'll address in the very next section.
Summary: Setting Up Your Wallet
You need to create an address to receive funds. Your address is stored in a wallet, which you can back up. You can also do lots more with an address, like dumping its private key or using it to sign messages. But really, creating that address is all you need to do in order to receive Bitcoin funds.
What's Next?
Step back from "Understanding Your Bitcoin Setup" with Interlude: Using Command-Line Variables.
3.4: Receiving a Transaction
You're now ready to receive some money at the new address you set up.
Get Some Money
To do anything more, you need to get some money. On testnet this is done through faucets. Since the money is all pretend, you just go to a faucet, request some money, and it will be sent over to you. We suggest using the faucet at https://testnet-faucet.mempool.co/, https://bitcoinfaucet.uo1.net/, or https://testnet.coinfaucet.eu/en/. If they're not available for some reason, search for "bitcoin testnet faucet", and you should find others.
To use a faucet, you'll usually need to go to a URL and copy and paste in your address. Note that this is one of those cases where you won't be able to use command-line variables, alas. Afterward, a transaction will be created that sends money from the faucet to you.
:book: What is a transaction? A transaction is a bitcoin exchange. The owner of some bitcoins uses his private key to access those coins, then locks the transaction using the recipient's public key.
:link: TESTNET vs MAINNET: Sadly, there are no faucets in real life. If you were playing on the mainnet, you'd need to go and actually buy bitcoins at a bitcoin exchange or ATM, or you'd need to get someone to send them to you. Testnet life is much easier.
Verify Your Money
After you've requested your money, you should be able to verify it with the bitcoin-cli getbalance
command:
$ bitcoin-cli getbalance
0.00000000
But wait, there's no balance yet!?
Welcome to the world of Bitcoin latency. The problem is that your transaction hasn't yet been recorded in a block!
:book: What is a block? Transactions are transmitted across the network and gathered into blocks by miners. These blocks are secured with a mathematical proof-of-work, which proves that computing power has been expended as part of the block creation. It's that proof-of-work (multiplied over many blocks, each built atop the last) that ultimately keeps Bitcoin secure.
:book: What is a miner? A miner is a participant of the Bitcoin network who works to create blocks. It's a paying job: when a miner successfully creates a block, he is paid a one-time reward plus the fees for the transactions in his block. Mining is big business. Miners tend to run on special hardware, accelerated in ways that make it more likely that they'll be able to create blocks. They also tend to be part of mining pools, where the miners all agree to share out the rewards when one of them successfully creates a block.
Fortunately, bitcoin-cli getunconfirmedbalance
should still show your updated balance as long as the initial transaction has been created:
$ bitcoin-cli getunconfirmedbalance
0.01010000
If that's still showing a zero too, you're probably moving through this tutorial too fast. Wait a second. The coins should show up unconfirmed, then rapidly move to confirmed. Do note that a coin can move from unconfirmedbalance to confirmedbalance almost immediately, so make sure you check both. However, if your getbalance
and your getunconfirmedbalance
both still show zero in ten minutes, then there's probably something wrong with the faucet, and you'll need to pick another.
Gain Confidence in Your Money
You can use bitcoin-cli getbalance "*" [n]
, where you replace [n]
with an integer, to see if a confirmed balance is 'n' blocks deep.
:book: What is block depth? After a block is built and confirmed, another block is built on top of it, and another ... Because this is a stochastic process, there's some chance for reversal when a block is still new. Thus, a block has to be buried several blocks deep in a chain before you can feel totally confident in your funds. Each of those blocks tends to be built in an average of 10 minutes ... so it usually takes about an hour for a confirmed transaction to receive six blocks deep, which is the measure for full confidence in Bitcoin.
The following shows that our transactions have been confirmed one time, but not twice:
$ bitcoin-cli getbalance "*" 1
0.01010000
$ bitcoin-cli getbalance "*" 2
0.00000000
Obviously, every ten minutes or so this depth will increase.
Of course, on the testnet, no one is that worried about how reliable your funds are. You'll be able to spend your money as soon as it's confirmed.
Verify Your Wallet
The bitcoin-cli getwalletinfo
command gives you more information on the balance of your wallet:
$ bitcoin-cli getwalletinfo
{
"walletname": "",
"walletversion": 169900,
"balance": 0.01010000,
"unconfirmed_balance": 0.00000000,
"immature_balance": 0.00000000,
"txcount": 2,
"keypoololdest": 1592335137,
"keypoolsize": 999,
"hdseedid": "fdea8e2630f00d29a9d6ff2af7bf5b358d061078",
"keypoolsize_hd_internal": 1000,
"paytxfee": 0.00000000,
"private_keys_enabled": true,
"avoid_reuse": false,
"scanning": false
}
Discover Your Transaction ID
Your money came into your wallet via a transaction. You can discover that transactionid (txid) with the bitcoin-cli listtransactions
command:
$ bitcoin-cli listtransactions
[
{
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"category": "receive",
"amount": 0.01000000,
"label": "",
"vout": 1,
"confirmations": 1,
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
"blockheight": 1772396,
"blockindex": 73,
"blocktime": 1592600085,
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
"walletconflicts": [
],
"time": 1592599884,
"timereceived": 1592599884,
"bip125-replaceable": "no"
},
{
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"category": "receive",
"amount": 0.00010000,
"label": "",
"vout": 0,
"confirmations": 1,
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
"blockheight": 1772396,
"blockindex": 72,
"blocktime": 1592600085,
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
"walletconflicts": [
],
"time": 1592599938,
"timereceived": 1592599938,
"bip125-replaceable": "no"
}
]
This shows two transactions (8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9
) and (ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36
) for a specific amount (0.01000000
and 0.00010000
), which were both received (receive
) by the same address in our wallet (mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE
). That's bad key hygeine, by the way: you should use a new address for every single Bitcoin you ever receive. In this case, we got impatient because the first faucet didn't seem to be working.
You can access similar information with the bitcoin-cli listunspent
command, but it only shows the transactions for the money that you haven't spent. These are called UTXOs, and will be vitally important when you're sending money back out into the Bitcoin world:
$ bitcoin-cli listunspent
[
{
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
"vout": 0,
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"label": "",
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
"amount": 0.00010000,
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
"safe": true
},
{
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
"vout": 1,
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"label": "",
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
"amount": 0.01000000,
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
"safe": true
}
]
Note that bitcoins are not just a homogeneous mess of cash jammed into your pocket. Each individual transaction that you receive or that you send is placed into the immutable blockchain ledger, in a block. You can see these individual transactions when you look at your unspent money. This means that bitcoin spending isn't quite as anonymous as you'd think. Though the addresses are fairly private, transactions can be examined as they go in and out of addresses. This makes privacy vulnerable to statistical analysis. It also introduces some potential non-fungibility to bitcoins, as you can track back through series of transactions, even if you can't track a specific "bitcoin".
:book: Why are all of these bitcoin amounts in fractions? Bitcoins are produced slowly, and so there are relatively few in circulation. As a result, each bitcoin over on the mainnet is worth quite a bit (~ $9,000 at the time of this writing). This means that people usually work in fractions. In fact, the .0101 in Testnet coins would be worth about $100 if they were on the mainnet. For this reason, names have appeared for smaller amounts of bitcoins, including millibitcoins or mBTCs (one-thousandth of a bitcoin), microbitcoins or bits or μBTCs (one-millionth of a bitcoin), and satoshis (one hundred millionth of a bitcoin).
Examine Your Transaction
You can get more information on a transaction with the bitcoin-cli gettransaction
command:
$ bitcoin-cli gettransaction "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9"
{
"amount": 0.01000000,
"confirmations": 1,
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
"blockheight": 1772396,
"blockindex": 73,
"blocktime": 1592600085,
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
"walletconflicts": [
],
"time": 1592599884,
"timereceived": 1592599884,
"bip125-replaceable": "no",
"details": [
{
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"category": "receive",
"amount": 0.01000000,
"label": "",
"vout": 1
}
],
"hex": "0200000000010114d04977d1b0137adbf51dd5d79944b9465a2619f3fa7287eb69a779977bf5800100000017160014e85ba02862dbadabd6d204fcc8bb5d54658c7d4ffeffffff02df690f000000000017a9145c3bfb36b03f279967977ca9d1e35185e39917788740420f00000000001976a9141b72503639a13f190bf79acf6d76255d772360b788ac0247304402201e74bdfc330fc2e093a8eabe95b6c5633c8d6767249fa25baf62541a129359c202204d462bd932ee5c15c7f082ad7a6b5a41c68addc473786a0a9a232093fde8e1330121022897dfbf085ecc6ad7e22fc91593414a845659429a7bbb44e2e536258d2cbc0c270b1b00"
}
The gettransaction
command will detail transactions that are in your wallet, such as this one, that was sent to us.
Note that gettransaction
has two optional arguments:
$ bitcoin-cli help gettransaction
gettransaction "txid" ( include_watchonly verbose )
Get detailed information about in-wallet transaction <txid>
Arguments:
1. txid (string, required) The transaction id
2. include_watchonly (boolean, optional, default=true for watch-only wallets, otherwise false) Whether to include watch-only addresses in balance calculation and details[]
3. verbose (boolean, optional, default=false) Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)
By setting these two true or false, we can choose to include watch-only addresses in the output (which we don't care about) or look at more verbose output (which we do).
Here's what this data instead looks at when we set include_watchonly
to false
and verbose
to true
.
$ bitcoin-cli gettransaction "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9" false true
{
"amount": 0.01000000,
"confirmations": 3,
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
"blockheight": 1772396,
"blockindex": 73,
"blocktime": 1592600085,
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
"walletconflicts": [
],
"time": 1592599884,
"timereceived": 1592599884,
"bip125-replaceable": "no",
"details": [
{
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"category": "receive",
"amount": 0.01000000,
"label": "",
"vout": 1
}
],
"hex": "0200000000010114d04977d1b0137adbf51dd5d79944b9465a2619f3fa7287eb69a779977bf5800100000017160014e85ba02862dbadabd6d204fcc8bb5d54658c7d4ffeffffff02df690f000000000017a9145c3bfb36b03f279967977ca9d1e35185e39917788740420f00000000001976a9141b72503639a13f190bf79acf6d76255d772360b788ac0247304402201e74bdfc330fc2e093a8eabe95b6c5633c8d6767249fa25baf62541a129359c202204d462bd932ee5c15c7f082ad7a6b5a41c68addc473786a0a9a232093fde8e1330121022897dfbf085ecc6ad7e22fc91593414a845659429a7bbb44e2e536258d2cbc0c270b1b00",
"decoded": {
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
"hash": "d4ae2b009c43bfe9eba96dcd16e136ceba2842df3d76a67d689fae5975ce49cb",
"version": 2,
"size": 249,
"vsize": 168,
"weight": 669,
"locktime": 1772327,
"vin": [
{
"txid": "80f57b9779a769eb8772faf319265a46b94499d7d51df5db7a13b0d17749d014",
"vout": 1,
"scriptSig": {
"asm": "0014e85ba02862dbadabd6d204fcc8bb5d54658c7d4f",
"hex": "160014e85ba02862dbadabd6d204fcc8bb5d54658c7d4f"
},
"txinwitness": [
"304402201e74bdfc330fc2e093a8eabe95b6c5633c8d6767249fa25baf62541a129359c202204d462bd932ee5c15c7f082ad7a6b5a41c68addc473786a0a9a232093fde8e13301",
"022897dfbf085ecc6ad7e22fc91593414a845659429a7bbb44e2e536258d2cbc0c"
],
"sequence": 4294967294
}
],
"vout": [
{
"value": 0.01010143,
"n": 0,
"scriptPubKey": {
"asm": "OP_HASH160 5c3bfb36b03f279967977ca9d1e35185e3991778 OP_EQUAL",
"hex": "a9145c3bfb36b03f279967977ca9d1e35185e399177887",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"2N1ev1WKevSsdmAvRqZf7JjvDg223tPrVCm"
]
}
},
{
"value": 0.01000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 1b72503639a13f190bf79acf6d76255d772360b7 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE"
]
}
}
]
}
}
Now you can see the full information on the transaction, including all of the inputs ("vin") and all the outputs ("vout). One of the interesting things to note is that although we received .01 BTC in the transaction, another .01010143 was sent to another address. That was probably a change address, a concept that is explored in the next section. It is quite typical for a transaction to have multiple inputs and/or multiple outputs.
There is another command, getrawtransaction
, which allows you to look at transactions that are not in your wallet. However, it requires you to have unpruned node and txindex=1
in your bitcoin.conf
file. Unless you have a serious need for information not in your wallet, it's probably just better to use a Bitcoin explorer for this sort of thing ...
Optional: Use a Block Explorer
Even looking at the verbose information for a transaction can be a little intimidating. The main goal of this tutorial is to teach how to deal with raw transactions from the command line, but we're happy to talk about other tools when they're applicable. One of those tools is a block explorer, which you can use to look at transactions from a web browser in a much friendlier format.
Currently, our preferred block explorer is https://live.blockcypher.com/.
You can use it to look up transactions for an address:
https://live.blockcypher.com/btc-testnet/address/mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE/
You can also use it to look at individual transactions:
A block explorer doesn't generally provide any more information than a command line look at a raw transaction; it just does a good job of highlighting the important information and putting together the puzzle pieces, including the transaction fees behind a transaction — another concept that we'll be covering in future sections.
Summary: Receiving a Transaction
Faucets will give you money on the testnet. They come in as raw transactions, which can be examined with gettransaction
or a block explorer. Once you've receive a transaction, you can see it in your balance and your wallet.
What's Next?
For a deep dive into how addresses are described, so that they can be transferred or made into parts of a multi-signature, see §3.5: Understanding the Descriptor.
But if that's too in-depth, continue on to Chapter Four: Sending Bitcoin Transactions.
3.5: Understanding the Descriptor
:information_source: NOTE: This section has been recently added to the course and is an early draft that may still be awaiting review. Caveat reader.
You may have noticed a weird desc:
field in the listunspent
command of the previous section. Here's what's all about (and how it can be used to transfer addresses).
:warning: VERSION WARNING: This is an innovation from Bitcoin Core v 0.17.0 that had continued to be expanded through Bitcoin Core 0.20.0. Most of the commands in this section are from 0.17.0, but the updated
importmulti
that support descriptors is from 0.18.0.
Know about Transferring Addresses
Most of this course presumes that you're working entirely from a single node where you manage your own wallet, sending and receiving payments with the addresses created by that wallet. However, that's not necessarily how the larger Bitcoin ecosystem works. There, you're more likely to be moving addresses between wallets and even setting up wallets to watch over funds controlled by different wallets.
That's where descriptors come in. They're most useful if you're interacting with software other than Bitcoin Core, and really need to lean on this sort of compatibility function: see §6.1 for a real-world example of how having the capability of descriptors is critical.
Moving addresses between wallets used to focus on xpub
and xprv
, and those are still supported.
:book: What is xprv? An extended private key. This is the combination of a private key and a chain code. It's a private key that a whole sequence of children private keys can be derived from.
:book: What is xpub? An extended public key. This is the combination of a public key and a chain code. It's a public key that a whole sequence of children public keys can be derived from.
The fact that you can have a "whole sequence of children ... keys" reveals the fact that "xpub" and "xprv" aren't standard keys like we've been talking about so far. They're instead hierarchical keys that can be used to create whole families of keys, built on the idea of HD Wallets.
:book: What is an HD Wallet? Most modern wallets are built on BIP32: Hierarchical Deterministic Wallets. This is a hierarchical design where a single seed can be used to generate a whole sequence of keys. The entire wallet may then be restored from that seed, rather than requiring the restoring of every single private key.
:book: What is a Derivation Path? When you have hierarchical keys, you need to be able to define individual keys as descendents of a seed. For example
[0]
is the 0th key,[0/1]
is the first son of the 0th key,[1/0/1]
is the first grandson of the zeroth son of the 1st key. Some keys also contain a'
after the number, to show they're hardened, which protects them from a specific attack that can be used to derive anxprv
from anxpub
. You don't need to worry about the specifics, other than the fact that those'
s will cause you formatting troubles when working from the command line.
:information_source: NOTE: a derivation path defines a key, which means that a key represents a derivation path. They're equivalent. In the case of a descriptor, the derivation path lets
bitcoind
know where the key that follows in the descriptor came from!
xpubs
and xprvs
proved insufficient when the types of public keys multiplied under the SegWit expansion, thus the need for "output descriptors".
:book: What is an output descriptor? A precise description of how to derive a Bitcoin address from a combination of a function and one or more inputs to that function.
The introduction of functions into descriptors is what makes them powerful, because they can be used to transfer all sorts of addresses, from the Legacy addresses that we're working with now to the Segwit and multisig addresses that we'll meet down the road. An individual function matches a particular type of address and correlates with specific rules to generate that address.
Capture a Descriptor
Descriptors are visible in several commands such as listunspent
and getaddressinfo
:
$ bitcoin-cli getaddressinfo ms7ruzvL4atCu77n47dStMb3of6iScS8kZ
{
"address": "ms7ruzvL4atCu77n47dStMb3of6iScS8kZ",
"scriptPubKey": "76a9147f437379bcc66c40745edc1891ea6b3830e1975d88ac",
"ismine": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk",
"iswatchonly": false,
"isscript": false,
"iswitness": false,
"pubkey": "03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388",
"iscompressed": true,
"ischange": false,
"timestamp": 1592335136,
"hdkeypath": "m/0'/0'/18'",
"hdseedid": "fdea8e2630f00d29a9d6ff2af7bf5b358d061078",
"hdmasterfingerprint": "d6043800",
"labels": [
""
]
}
Here the descriptor is pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk
.
Understand a Descriptor
A descriptor is broken into several parts:
function([derivation-path]key)#checksum
Here's what that all means:
- Function. The function that is used to create an address from that key. In this cases it's
pkh
, which is the standard P2PKH legacy address that you met in §3.3: Setting Up Your Wallet. Similarly, a P2WSH SegWit address would usewsh
and a P2WPKH address would usewpkh
. - Derivation Path. This describes what part of an HD wallet is being exported. In this case it's a seed with the fingerprint
d6043800
and then the 18th child of the 0th child of the 0th child (0'/0'/18'
) of that seed. There may also be a further derivation after the key:function([derivation-path]key/more-derivation)#checksum
- It's worth noting here that if you ever get a derivation path without a fingerprint, you can make it up. It's just that if there's an existing one, you should match it, because if you ever go back to the device that created the fingerprint, you'll need to have the same one.
- Key. The key or keys that are being transferred. This could be something traditional like an
xpub
orxprv
, it could just be a public key for an address as in this case, it could be a set of addresses for a multi-signature, or it could be something else. This is the core data: the function explains what to do with it. - Checksum. Descriptors are meant to be human transferrable. This checksum makes sure you got it right.
See Bitcoin Core's Info on Descriptor Support for more information.
Examine a Descriptor
You can look at a descriptor with the getdescriptorinfo
RPC:
$ bitcoin-cli getdescriptorinfo "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk"
{
"descriptor": "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk",
"checksum": "4ahsl9pk",
"isrange": false,
"issolvable": true,
"hasprivatekeys": false
}
Note that it returns a checksum. If you're ever given a descriptor without a checksum, you can learn it with this command:
$ bitcoin-cli getdescriptorinfo "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)"
{
"descriptor": "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk",
"checksum": "4ahsl9pk",
"isrange": false,
"issolvable": true,
"hasprivatekeys": false
}
Besides giving you the checksum, this command also verifies the validity of the descriptor and provides useful information like whether a descriptor contains private keys.
One of the powers of a descriptor is being able to derive an address in a regular way. This is done with the deriveaddresses
RPC.
$ bitcoin-cli deriveaddresses "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk"
[
"ms7ruzvL4atCu77n47dStMb3of6iScS8kZ"
]
You'll note it loops back to the address we started with (as it should).
Import a Descriptor
But, the really important thing about a descriptor is that you can take it to another (remote) machine and import it. This is done with the importmulti
RPC using the desc
option:
remote$ bitcoin-cli importmulti '[{"desc": "pkh([d6043800/0'"'"'/0'"'"'/18'"'"']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk", "timestamp": "now", "watchonly": true}]'
[
{
"success": true
}
]
First, you'll note our first really ugly use of quotes. Every '
in the derivation path had to be replaced with '"'"'
. Just expect to have to do that if you're manipulating a descriptor that contains a derivation path. (The other option is to exchange the '
with a h
for hardened, but that will change you checksum, so if you prefer that for its ease of use, you'll need to get a new checksum with getdescriptorinfo
.)
Second, you'll note that we flagged this as watchonly
. That's because we know that it's a public key, so we can't spend with it. If we'd failed to enter this flag, importmulti
would helpfully have told us something like: Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.
.
:book: What is a watch-only address? A watch-only address allows you to watch for transactions related to an address (or to a whole family of addresses if you used an
xpub
), but not to spend funds on those addresses.
Using getaddressesbylabel
, we can now see that our address has correctly been imported into our remote machine!
remote$ bitcoin-cli getaddressesbylabel ""
{
"ms7ruzvL4atCu77n47dStMb3of6iScS8kZ": {
"purpose": "receive"
}
}
Summary: Understanding the Descriptor
Descriptors let you pass public keys and private keys among wallets, but more than that, they allow you to precisely and correctly to define addresses and to derive addresses of a lot of different sorts from a standardized description format.
:fire: What is the power of descriptors? Descriptors allow you to import and export seeds and keys. That's great if you want to move between different wallets. As a developer, they also allow you to build up the precise sort of addresses that you're interested in creating. For example, we use it in FullyNoded 2 to generate a multi-sig from three seeds.
We'll make real use of descriptors in §7.3, when we're importing addresses from a hardware wallet.
What's Next?
Advance through "bitcoin-cli" with Chapter Four: Sending Bitcoin Transactions.
Chapter Four: Sending Bitcoin Transactions
This chapter describes three different methods for sending bitcoins to normal P2PKH addresses from the command line, using only the bitcoin-cli interface.
Objectives for This Chapter
After working through this chapter, a developer will be able to:
- Decide How to Send Money Through Bitcoin
- Create a Raw Transaction
- Use Arithmetic to Calculate Fees
Supporting objectives include the ability to:
- Understand Transactions & Transaction Fees
- Understand Legacy & SegWit Transactions
- Use Basic Methods to Send Money
- Use Auto Fee Calculation Methods to Send Money
- Understand the Dangers of Raw Transactions
Table of Contents
- Section One: Sending Coins the Easy Way
- Section Two: Creating a Raw Transaction
- Section Three: Creating a Raw Transaction with Named Arguments
- Section Four: Sending Coins with Raw Transactions
- Section Five: Sending Coins with Automated Raw Transactions
- Section Six: Creating a SegWit Transaction
4.1: Sending Coins the Easy Way
The bitcoin-cli
offers three major ways to send coins: as a simple command; as a raw transaction; and as a raw transaction with calculation. Each has their own advantages and disadvantages. This first method for sending coins is also the simplest.
Set Your Transaction Fee
Before you send any money on the Bitcoin network, you should think about what transaction fees you're going to pay.
:book: What is a transaction fee? There's no such thing as a free lunch. Miners incorporate transactions into blocks because they're paid to do so. Not only do they get paid by the network for making the block, but they also get paid by transactors for including their transactions. If you don't pay a fee, your transaction might get stuck ... forever (or, until saved by some of the tricks in Chapter Five).
When you're using the simple and automated methods for creating transactions, as outlined here and in §4.5: Sending Coins with Automated Raw Transactions, Bitcoin will calculate transaction fees for you. This is done using Floating Fees, where the bitcoind
watches how long transactions are taking to confirm and automatically calculates for you what to spend.
You can help control this by putting rational values into your ~/.bitcoin/bitcoin.conf
. The following low-cost values would ensure that there was a minimum transaction fee of 10,000 satoshis per kByte of data in your transaction and request that the floating fees figure out a good amount to get your transaction somewhere into the next six blocks.
mintxfee=0.0001
txconfirmtarget=6
However, under the theory that you don't want to wait around while working on a tutorial, we've adopted the following higher values:
mintxfee=0.001
txconfirmtarget=1
You should enter these into ~/.bitcoin/bitcoin.conf
, in the main section, toward the top of the file or if you want to be sure you never use it elsewhere, under the [test]
section.
In order to get through this tutorial, we're willing to spend 100,000 satoshis per kB on every transaction (about $10!), and we want to get each transaction into the next block! (To put that in perspective, a typical transaction runs between .25 kB and 1 kB, so you'll actually be paying more like $2.50 than $10 ... if this were real money.)
After you've edited your bitcoin.conf file, you'll want to kill and restart bitcoind.
$ bitcoin-cli stop
$ bitcoind -daemon
Get an Address
You need somewhere to send your coins to. Usually, someone would send you an address, and perhaps give you a signature to prove they own that address. Alternatively, they might give you a QR code to scan, so that you can't make mistakes when typing in the address. In our case, we're going to send coins to n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
, which is a return address for an old Tesetnet faucet.
:book: What is a QR code? A QR code is just an encoding of a Bitcoin address. Many wallets will generate QR codes for you, while some sites will convert from an address to a QR code. Obviously, you should only accept a QR code from a site that you absolutely trust. A payer can use a bar-code scanner to read in the QR code, then pay to it.
Send the Coins
You're now ready to send some coins. This is actually quite simple via the command line. You just use bitcoin-cli sendtoaddress [address] [amount]
. So, to send a little coinage to the address n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
just requires:
$ txid=$(bitcoin-cli sendtoaddress n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi 0.001)
$ echo $txid
93250d0cacb0361b8e21030ac65bc4c2159a53de1075425d800b2d7a8ab13ba8
🙏 To help keep testnet faucets alive, try to use the return address of the same faucet you used in the previous chapter on receiving transactions.
Make sure the address you write in is where you want the money to go. Make double sure. If you make mistakes in Bitcoin, there's no going back.
You'll receive a txid back when you issue this command.
❕ You may end up with an error code if you don't have enough funds in your wallet to send the transaction. Depending on your current balance
bitcoin-cli getbalance
you may need to adjust the amount to be sent to account for the amount being sent along with the transaction fee. If your current balance is 0.001, then you could try sending 0.0001. Alternatively, it would be better to instead subtract the expected fee given in the error message from your current balance. This is good practice as many wallets expect you to calculate your own amount + fees when withdrawing, even among popular exchanges.
:warning: WARNING: The
bitcoin-cli
command actually generates JSON-RPC commands when it's talking to the bitcoind. They can be really picky. This is an example: if you list the bitcoin amount without the leading zero (i.e. ".1" instead of "0.1"), then bitcoin-cli will fail with a mysterious message.
:warning: WARNING: Even if you're careful with your inputs, you could see "Fee estimation failed. Fallbackfee is disabled." Fundamentally, this means that your local
bitcoind
doesn't have enough information to estimate fees. You should really never see it if you've waited for your blockchain to sync and set up your system with Bitcoin Standup. But if you're not entirely synced, you may see this. It also could be that you're not using a standardbitcoin.conf
: the entryblocksonly=1
will cause yourbitcoind
to be unable to estimate fees.
Examine Your Transaction
You can look at your transaction using your transaction id:
{
"amount": -0.00100000,
"fee": -0.00022200,
"confirmations": 0,
"trusted": true,
"txid": "93250d0cacb0361b8e21030ac65bc4c2159a53de1075425d800b2d7a8ab13ba8",
"walletconflicts": [
],
"time": 1592604194,
"timereceived": 1592604194,
"bip125-replaceable": "no",
"details": [
{
"address": "n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi",
"category": "send",
"amount": -0.00100000,
"vout": 1,
"fee": -0.00022200,
"abandoned": false
}
],
"hex": "0200000001e982921bb0189afc486e20bb05cc5825c71a0ba8868043ed04ece9ab0cb12a8e010000006a47304402200fc493a01c5c9d9574f7c321cee6880f7f1df847be71039e2d996f7f75c17b3d02203057f5baa48745ba7ab5f1d4eed11585bd8beab838b1ca03a4138516fe52b3b8012102fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9bafeffffff02e8640d0000000000160014d37b6ae4a917bcc873f6395741155f565e2dc7c4a0860100000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac780b1b00"
}
You can see not only the amount transferred (.001 BTC) but also a transaction fee (.000222 BTC), which is about a quarter of the .001 BTC/kB minimum fee that was set, which suggests that the transaction was about a quarter of a kB in size.
While you are waiting for this transaction to clear, you'll note that bitcoin-cli getbalance
shows that all of your money is gone (or, at least, all of your money from a single incoming transaction). Similarly, bitcoin-cli listunspent
will show that an entire transaction is gone, even if it was more than what you wanted to send. There's a reason for this: whenever you get money in, you have to send it all out together, and you have to perform some gymnastics if you actually want to keep some of it! Once again, sendtoaddress
takes care of this all for you, which means you don't have to worry about making change until you send a raw transaction. In this case, a new transaction will appear with your change when your spend is incorporated into a block.
Summary: Sending Coins the Easy Way
To send coins the easy way, make sure your transaction defaults are rationale, get an address, and send coins there. That's why they call it easy!
:fire: What is the power of sending coins the easy way?
The advantages. It's easy. You don't have to worry about arcane things like UTXOs. You don't have to calculate transaction fees by hand, so you're not likely to make mistakes that cost you large amounts of money. If your sole goal is to sit down at your computer and send some money, this is the way to go.
The disadvantages. It's high level. You have very little control over what's happening, and you can't do anything fancy. If you're planning to write more complex Bitcoin software or want a deeper understanding of how Bitcoin works, then the easy way is just a dull diversion before you get to the real stuff.
What's Next?
Continue "Sending Bitcoin Transactions" with §4.2 Creating a Raw Transaction.
Interlude: Using JQ
Creating a raw transaction revealed how more complex bitcoin-cli results can't easily be saved into command-line variables. The answer is JQ, which allows you to filter out individual elements from more complex JSON data.
Install JQ
JQ is available from a Github repository. Just download for Linux, OS X, or Windows, as appropriate.
Once you've downloaded the binary, you can install it on your system. If you're working on a Debian VPS as we suggest, your installation will look like this:
$ mv jq-linux64 jq
$ sudo /usr/bin/install -m 0755 -o root -g root -t /usr/local/bin jq
:book: What is JQ? The repository explains it best, saying "jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text."
Use JQ to Access a JSON Object Value by Key
Usage Example: Capture the hex from a signed raw transaction.
In the previous section, the use of signrawtransaction
offered an example of not being able to easily capture data into variables due to the use of JSON output:
$ bitcoin-cli signrawtransactionwithwallet $rawtxhex
{
"hex": "02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000",
"complete": true
}
Fortunately, JQ can easily capture data of that sort!
To use JQ, run jq
at the backend of a pipe, and always use the standard invocation of jq -r '.'
. The -r
tells JQ to produce raw output, which will work for command-line variables, while the .
tells jq to output. We protect that argument in ' '
because we'll need that protection later as our jq
invocations get more complex.
To capture a specific value from a JSON object, you just list the key after the .
:
$ bitcoin-cli signrawtransactionwithwallet $rawtxhex | jq -r '.hex'
02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000
With that tool in hand, you can capture information from JSON objects to command-line variables:
$ signedtx=$(bitcoin-cli signrawtransactionwithwallet $rawtxhex | jq -r '.hex')
$ echo $signedtx
02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000
You can then use those variables easily and without error:
$ bitcoin-cli sendrawtransaction $signedtx
3f9ccb6e16663e66dc119de1866610cc4f7a83079bfec2abf0598ed3adf10a78
Use JQ to Access Single JSON Object Values in an Array by Key
Usage Example: Capture the txid and vout for a selected UTXO.
Grabbing data out of a JSON object is easy, but what if that JSON object is in a JSON array? The listunspent
command offers a great example, because it'll usually contain a number of different transactions. What if you want to capture specific information from one of them?
When working with a JSON array, the first thing you need to do is tell JQ which index to access. For example, you might have looked through your transactions in listunspent
and decided that you wanted to work with the second of them. You use '.[1]'
to access that second element. The []
says that we're referencing a JSON array and the 1
says we want the 1st index.
$ bitcoin-cli listunspent | jq -r '.[1]'
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00022,
"confirmations": 9,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
}
You can then capture an individual value from that selected array by (1) using a pipe within the JQ arguments; and then (2) requesting the specific value afterward, as in the previous example. The following would capture the txid
from the 1st JSON object in the JSON array produced by listunspent
:
$ bitcoin-cli listunspent | jq -r '.[1] | .txid'
91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c
Carefully note how the ' 's
go around the whole JQ expression including the pipe.
This method can be used to fill in variables for a UTXO that you want to use:
$ newtxid=$(bitcoin-cli listunspent | jq -r '.[1] | .txid')
$ newvout=$(bitcoin-cli listunspent | jq -r '.[1] | .vout')
$ echo $newtxid
91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c
$ echo $newvout
0
Voila! We could now create a new raw transaction using our 1st UTXO as an input, without having to type in any of the UTXO info by hand!
Use JQ to Access Matching JSON Object Values in an Array by Key
Usage Example: List the value of all unspent UTXOs.
Instead of accessing a single, specific value in a specific JSON object, you could instead access all of a specific value across all the JSON objects. This is done with .[]
, where no index is specified. For example, this would list all unspent funds:
$ bitcoin-cli listunspent | jq -r '.[] | .amount'
0.0001
0.00022
Use JQ for Simple Calculations by Key
Usage Example: Sum the value of all unspent UTXOs.
At this point, you can start using JQ output for simple math. For example, adding up the values of those unspent transactions with a simple awk
script would give you the equivalent of getbalance
:
$ bitcoin-cli listunspent | jq -r '.[] | .amount' | awk '{s+=$1} END {print s}'
0.00032
$ bitcoin-cli getbalance
0.00032000
Use JQ to Display Multiple JSON Object Values in an Array by Multiple Keys
Usage Example: List usage information for all UTXOs.
JQ can easily capture individual elements from JSON objects and arrays and place those elements into variables. That will be its prime use in future sections. However, it can also be used to cut down huge amounts of information output by bitcoin-cli
into reasonable amounts of information.
For example, you might want to see a listing of all your UTXOs (.[]
) and get a listing of all of their most important information (.txid, .vout, .amount
):
$ bitcoin-cli listunspent | jq -r '.[] | .txid, .vout, .amount'
ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36
0
0.0001
91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c
0
0.00022
This makes it easy to decide which UTXOs to spend in a raw transaction, but it's not very pretty.
Fortunately, JQ also lets you be fancy. You can use {}
s to create new JSON objects (either for additional parsing or for pretty output). You also get to define the name of the new key for each of your values. The resulting output should be much more intuitive and less prone to error (though obviously, less useful for dumping info straight into variables).
The following example shows the exact same parsing of listunspent
, but with the each old JSON object rebuilt as a new, abridged JSON object, with all of the new values named with their old keys:
$ bitcoin-cli listunspent | jq -r '.[] | { txid: .txid, vout: .vout, amount: .amount }'
{
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
"vout": 0,
"amount": 0.0001
}
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"amount": 0.00022
}
You could of course rename your new keys as you see fit. There's nothing magic in the original names:
$ bitcoin-cli listunspent | jq -r '.[] | { tx: .txid, output: .vout, bitcoins: .amount }'
{
"tx": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
"output": 0,
"bitcoins": 0.0001
}
{
"tx": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"output": 0,
"bitcoins": 0.00022
}
Use JQ to Access JSON Objects by Looked-Up Value
Usage Example: Automatically look up UTXOs being used in a transaction.
The JQ lookups so far have been fairly simple: you use a key to look up one or more values in a JSON object or array. But what if you instead want to look up a value in a JSON object ... by another value? This sort of indirect lookup has real applicability when you're working with transactions built on existing UTXOs. For example, it can allow you to calculate the sum value of the UTXOs being used in a transaction, something that is vitally important.
This example uses the following raw transaction. Note that this is a more complex raw transaction with two inputs and two outputs. We'll learn about making those in a few sections; for now, it's necessary to be able to offer robust examples. Note that unlike our previous examples, this one has two objects in its vin
array and two in its vout
array.
$ bitcoin-cli decoderawtransaction $rawtxhex
{
"txid": "6f83a0b78c598de01915554688592da1d7a3047eacacc8a9be39f5396bf0a07e",
"hash": "6f83a0b78c598de01915554688592da1d7a3047eacacc8a9be39f5396bf0a07e",
"size": 160,
"vsize": 160,
"version": 2,
"locktime": 0,
"vin": [
{
"txid": "d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967295
},
{
"txid": "c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 1.00000000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 cfc39be7ea3337c450a0c77a839ad0e160739058 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914cfc39be7ea3337c450a0c77a839ad0e16073905888ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"mzTWVv2QSgBNqXx7RC56zEhaQPve8C8VS9"
]
}
},
{
"value": 0.04500000,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 166692bda9f25ced145267bb44286e8ee3963d26 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914166692bda9f25ced145267bb44286e8ee3963d2688ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"mhZQ3Bih6wi7jP1tpFZrCcyr4NsfCapiZP"
]
}
}
]
}
Retrieve the Value(s)
Assume that we know exactly how this transaction is constructed: we know that it uses two UTXOs as input. To retrieve the txid for the two UTXOs, we could use jq
to look up the transaction's .vin value, then reference the .vin's 0th array, then that array's .txid value. Afterward, we could do the same with the 1st array, then the same with the .vin's two .vout values. Easy:
$ usedtxid1=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .txid')
$ echo $usedtxid1
d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c
$ usedtxid2=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[1] | .txid')
$ echo $usedtxid2
c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b
$ usedvout1=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .vout')
$ echo $usedvout1
1
$ usedvout2=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[1] | .vout')
$ echo $usedvout2
1
However, it would be better to have a general case that automatically saved all the txids of our UTXOs.
We already know that we can access all of the .txid
s by using an .[]
array value. We can use that to build a general .txid lookup:
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
$ echo ${usedtxid[0]}
d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c
$ echo ${usedtxid[1]}
c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b
$ usedvout=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .vout'))
$ echo ${usedvout[0]}
1
$ echo ${usedvout[1]}
1
The only real trick here is how we saved the information using the bash shell. Rather than saving to a variable with $(command)
, we instead saved to an array with ($(command))
. We were then able to access the individual bash array elements with a ${variable[n]}
construction. We could instead access the whole array with ${variable[@]}
. (Yeah, no one ever said bash was pretty.)
:warning: WARNING: Always remember that a UTXO is a transaction plus a vout. We missed the vout the first time we wrote this JQ example, and it stopped working when we ended up with a situation where we'd been sent two
vouts
from the same transaction.
Retrieve the Related Object(s)
You can now use your saved txid
and vout
information to reference UTXOs in listunspent
. To find the information on the UTXOs being used by the raw transaction, you need to look through the entire JSON array ([]
) of unspent transactions. You can then choose (select
) individual JSON objects that include (contains
) the txids. You then select (select
) the transactions among those that also contains (contain
) the correct vout.
The use of another level of pipe is the standard methodology of JQ: you grab a set of data, then you whittle it down to all the relevant transactions, then you whittle it down to the vouts that were actually used from those transactions. However, the select
and contains
arguments are something new. They show off some of the complexity of JSON that goes beyond the scope of this tutorial; for now just know that this particular invocation will work to grab matching objects.
To start simply, this picks out the two UTXOs one at a time:
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${usedtxid[0]}'")) | select(.vout | contains('${usedvout[0]}'))'
{
"txid": "d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c",
"vout": 1,
"address": "miSrC3FvkPPZgqqvCiQycq7io7wTSVsAFH",
"scriptPubKey": "76a91420219e4f3c6bc0f6524d538009e980091b3613e888ac",
"amount": 0.9,
"confirmations": 6,
"spendable": true,
"solvable": true
}
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${usedtxid[1]}'")) | select(.vout | contains('${usedvout[1]}'))'
{
"txid": "c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b",
"vout": 1,
"address": "mzizSuAy8aL1ytFijds7pm4MuDPx5aYH5Q",
"scriptPubKey": "76a914d2b12da30320e81f2dfa416c5d9499d08f778f9888ac",
"amount": 0.4,
"confirmations": 5,
"spendable": true,
"solvable": true
}
A simple bash for-loop could instead give you all of your UTXOs:
$ for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout'))'; done;
{
"txid": "d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c",
"vout": 1,
"address": "miSrC3FvkPPZgqqvCiQycq7io7wTSVsAFH",
"scriptPubKey": "76a91420219e4f3c6bc0f6524d538009e980091b3613e888ac",
"amount": 0.9,
"confirmations": 7,
"spendable": true,
"solvable": true
}
{
"txid": "c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b",
"vout": 1,
"address": "mzizSuAy8aL1ytFijds7pm4MuDPx5aYH5Q",
"scriptPubKey": "76a914d2b12da30320e81f2dfa416c5d9499d08f778f9888ac",
"amount": 0.4,
"confirmations": 6,
"spendable": true,
"solvable": true
}
Note that we used yet another bit of array ugliness ${#usedtxid[*]}
to determine the size of the array, then accessed each value in the usedtxid
array and each value in the parallel usedvout
array, putting them into simpler variables for less-ugly access.
Use JSON for Simple Calculation by Value
Usage Example: Automatically calculate the value of the UTXOs used in a transaction.
You can now go one step further, and request the .amount (or any other JSON key-value) from the UTXOs you're retrieving.
This example repeats the usage the $usedtxid
and $usedvout
arrays that were set as follows:
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
$ usedvout=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .vout'))
The same for
script can be used to step through those arrays, but with an added pipe in the JQ that outputs the amount
value for each of the UTXOs selected.
$ for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout')) | .amount'; done;
0.9
0.4
At this point, you can also sum up the .amounts with an awk
script, to really see how much money is in the UTXOs that the transaction is spending:
$ for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout')) | .amount'; done | awk '{s+=$1} END {print s}'
1.3
Whew!
Use JQ for Complex Calculations
Usage Example: Calculate the fee for a transaction.
Figuring out the complete transaction fee at this point just requires one more bit of math: determining how much money is going through the .vout. That's a simple use of JQ where you just use awk
to sum up the value
of all the vout
information:
$ bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vout [] | .value' | awk '{s+=$1} END {print s}'
1.045
To complete the transaction fee calculation, you subtract the .vout .amount (1.045) from the .vin .amount (1.3).
To do this, you'll need to install bc
:
$ sudo apt-get install bc
Putting it all together creates a complete calculator in just five lines of script:
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
$ usedvout=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .vout'))
$ btcin=$(for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout')) | .amount'; done | awk '{s+=$1} END {print s}')
$ btcout=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vout [] | .value' | awk '{s+=$1} END {print s}')
$ echo "$btcin-$btcout"| /usr/bin/bc
.255
And that's also a good example of why you double-check your fees: we'd intended to send a transaction fee of 5,000 satoshis, but sent 255,000 satoshis instead. Whoops!
:warning: WARNING: The first time we wrote up this lesson, we genuinely miscalculated our fee and didn't see it until we ran our fee calculator. It's that easy, then your money is gone. (The example above is actually from our second iteration of the calculator, and that time we made the mistake on purpose.)
For more JSON magic (and if any of this isn't clear), please read the JSON Manual and the JSON Cookbook. We'll be regularly using JQ in future examples.
Make Some New Aliases
JQ code can be a little unwieldy, so you should consider adding some longer and more interesting invocations to your ~/.bash_profile.
Any time you're looking through a large mass of information in a JSON object output by a bitcoin-cli
command, consider writing an alias to strip it down to just what you want to see.
alias btcunspent="bitcoin-cli listunspent | jq -r '.[] | { txid: .txid, vout: .vout, amount: .amount }'"
Run The Transaction Fee Script
The Fee Calculation Script is available in src-code directory. You can download it and save it as txfee-calc.sh
.
:warning: WARNING: This script has not been robustly checked. If you are going to use it to verify real transaction fees you should only do it as a triple-check after you've already done all the math yourself.
Be sure the permissions on the script are right:
$ chmod 755 txfee-calc.sh
You can then run the script as follows:
$ ./txfee-calc.sh $rawtxhex
.255
You may also want to create an alias:
alias btctxfee="~/txfee-calc.sh"
Summary: Using JQ
JQ makes it easy to extract information from JSON arrays and objects. It can also be used in shell scripts for fairly complex calculations that will make your life easier.
What's Next?
Continue "Sending Bitcoin Transactions" with §4.3 Creating a Raw Transaction with Named Arguments.
4.2 Creating a Raw Transaction
You're now ready to create Bitcoin raw transactions. This allows you to send money but to craft the transactions as precisely as you want. This first section focuses on a simple one-input, one-output transaction. This sort of transaction isn't actually that useful, because you're rarely going to want to send all of your money to one person (unless you're actually just forwarding it on, such as if you're moving things from one wallet to another). Thus, we don't label this section as a way to send money. It's just a foundational stepping stone to actually sending money with a raw transaction.
Understand the Bitcoin Transaction
Before you dive into actually creating raw transactions, you should make sure you understand how a Bitcoin transaction works. It's all about the UTXOs.
:book: What is a UTXO? When you receive cash in your Bitcoin wallet, it appears as an individual transaction. Each of these transactions is called a Unspent Transaction Output (UTXO). It doesn't matter if various payments were made to the same address or to multiple addresses: each incoming transaction remains distinct in your wallet as a UTXO.
When you create a new outgoing transaction, you gather together one or more UTXOs, each of which represents a blob of money that you received. You use these as inputs for a new transaction. Together their amount must equal what you want to spend or more. Then, you generate one or more outputs, which give the money represented by the inputs to one or more people. This creates new UTXOs for the recipients, which may then use those to fund future transactions.
Here's the trick: all of the UTXOs that you gather are spent in full! That means that if you want to send just part of the money in a UTXO to someone else, then you also have to generate an additional output that sends the rest back to you! For now, we won't worry about that, but the use of a change address will be vital when moving on from the theory of this chapter to more practical transactions.
List Your Unspent Transactions
In order to create a new raw transaction, you must know what UTXOs you have on-hand to spend. You can determine this information with the bitcoin-cli listunspent
command:
$ bitcoin-cli listunspent
[
{
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
"vout": 0,
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"label": "",
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
"amount": 0.00010000,
"confirmations": 20,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
"safe": true
},
{
"txid": "61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a",
"vout": 1,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00050000,
"confirmations": 3,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
},
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00022000,
"confirmations": 3,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
}
]
This listing shows three different UTXOs, worth .0001, .0005 and .00022 BTC. Note that each has its own distinct txid and remains distinct in the wallet, even the last two, which were sent to the same address.
When you want to spend a UTXO, it's not sufficient to just know the transaction id. That's because each transaction can have multiple outputs! Remember that first chunk of money that the faucet sent us? In the transaction, some money went to us and some went to someone else. The txid
refers to the overall transaction, while a vout
says which of multiple outputs you've received. In this list, each of these transactions is the 0th vout
of a previous transaction, but that doesn't have to be the case.
So, txid+vout=UTXO. This will be the foundation of any raw transaction.
Write a Raw Transaction with One Output
You're now ready to write a simple, example raw transaction that shows how to send the entirety of a UTXO to another party. As noted, this is not necessarily a very realistic real-world case.
:warning: WARNING: It is very easy to lose money with a raw transaction. Consider all instructions on sending bitcoins via raw transactions to be very, very dangerous. Whenever you're actually sending real money to other people, you should instead use one of the other methods explained in this chapter. Creating raw transactions is extremely useful if you're writing bitcoin programs, but only when you're writing bitcoin programs. (For example: in writing this example for one version of this tutorial, we accidentally spent the wrong transaction, even though it had about 10x as much value. Almost all of that was lost to the miners.)
Prepare the Raw Transaction
For best practices, we'll start out each transaction by carefully recording the txids and vouts that we'll be spending.
In this case, we're going to spend the one worth .00050000 BTC because it's the only one with a decent value.
$ utxo_txid="61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a"
$ utxo_vout="1"
You should similarly record your recipient address, to make sure you have it right. We're again sending some money back to the TP faucet:
$ recipient="n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
As always, check your variables carefully, to make sure they're what you expect!
$ echo $utxo_txid
61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a
$ echo $utxo_vout
1
$ echo $recipient
n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
That recipient is particularly important, because if you mess it up, your money is gone! (And as we already saw, choosing the wrong transaction can result in lost money!) So triple check it all.
Understand the Transaction Fee
Each transaction has a fee associated with. It's implicit when you send a raw transaction: the amount that you will pay as a fee is always equal to the amount of your input minus the amount of your output. So, you have to decrease your output a little bit from your input to make sure that your transaction goes out.
:warning: WARNING: This is the very dangerous part of raw transactions!! Because you automatically expend all of the amount in the UTXOs that you use, it's critically important to make sure that you know: (1) precisely what UTXOs you're using; (2) exactly how much money they contain; (3) exactly how much money you're sending out; and (4) what the difference is. If you mess up and you use the wrong UTXO (with more money than you thought) or if you send out too little money, the excess is lost. Forever. Don't make that mistake! Know your inputs and outputs precisely. Or better, don't use raw transactions except as part of a carefully considered and triple-checked program.
:book: How much should you spend on transaction fees? Bitcoin Fees has a nice live assessment. It says that the "fastest and cheapest transaction fee is currently 42 satoshis/byte" and that "For the median transaction size of 224 bytes, this results in a fee of 9,408 satoshis".
Currently Bitcoin Fees suggests a transaction fee of about 10,000 satoshis, which is the same as .0001 BTC. Yes, that's for the mainnet, not the testnet, but we want to test out things realistically, so that's what we're going to use.
In this case, that means taking the .0005 BTC in the UTXO we're selected, reducing it by .0001 BTC for the transaction fee, and sending the remaining .0004 BTC. (And this is an example of why micropayments don't work on the Bitcoin network, because a $1 or so transaction fee is pretty expensive when you're sending $4, let alone if you were trying to make a micropayment of $0.50. But that's always why we have Lightning.)
:warning: WARNING: The lower that you set your transaction fee, the longer before your transaction is built into a block. The Bitcoin Fees site lists expected times, from an expected 0 blocks, to 22. Since blocks are built on average every 10 minutes, that's the difference between a few minutes and a few hours! So, choose a transaction fee that's appropriate for what you're sending. Note that you should never drop below the minimum relay fee, which is .0001 BTC.
Write the Raw Transaction
You're now ready to create the raw transaction. This uses the createrawtransaction
command, which might look a little intimidating. That's because the createrawtransaction
command doesn't entirely shield you from the JSON RPC that the bitcoin-cli uses. Instead, you are going to input a JSON array to list the UTXOs that you're spending and a JSON object to list the outputs.
Here's the standard format:
$ bitcoin-cli createrawtransaction
'''[
{
"txid": "'$your_txid'",
"vout": '$your_vout'
}
]'''
'''{
"'$your_recipient'": bitcoin_amount
}'''
Yeah, there are all kinds of crazy quotes there, but trust that they'll do the right thing. Use '''
to mark the start and end of the JSON array and the JSON object. Protect normal words like "this"
, but you don't need to protect normal numbers: 0
. If they're variables, insert single quotes, like "'$this_word'"
and '$this_num'
. (Whew. You'll get used to it.)
Here's a command that creates a raw transaction to send your $utxo to your $recipient
$ rawtxhex=$(bitcoin-cli createrawtransaction '''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' '''{ "'$recipient'": 0.0004 }''')
$ echo $rawtxhex
02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f3610100000000ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000
Verify Your Raw Transaction
You should next verify your rawtransaction with decoderawtransaction
to make sure that it will do the right thing.
$ bitcoin-cli decoderawtransaction $rawtxhex
{
"txid": "dcd2d8f0ec5581b806a1fbe00325e1680c4da67033761b478a26895380cc1298",
"hash": "dcd2d8f0ec5581b806a1fbe00325e1680c4da67033761b478a26895380cc1298",
"version": 2,
"size": 85,
"vsize": 85,
"weight": 340,
"locktime": 0,
"vin": [
{
"txid": "61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.00040000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 e7c1345fc8f87c68170b3aa798a956c2fe6a9eff OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
]
}
}
]
}
Check the vin
. Are you spending the right transaction? Does it contain the expected amount of money? (Check with bitcoin-cli gettransaction
and be sure to look at the right vout
.) Check your vout
. Are you sending the right amount? Is it going to the right address? Finally, do the math to make sure the money balances. Does the value of the UTXO minus the amount being spent equal the expected transaction fee?
:information_source: NOTE - SEQUENCE: You may note that each input has a sequence number, set here to 4294967295, which is 0xFFFFFFFF. This is the last frontier of Bitcoin transactions, because it's a standard field in transactions that was originally intended for a specific purpose, but was never fully implemented. So now there's this integer sitting around in transactions that could be repurposed for other uses. And, in fact, it has been. As of this writing there are three different uses for the variable that's called
nSequence
in the Bitcoin Core code: it enables RBF,nLockTime
, and relative timelocks. If there's nothing weird going on,nSequence
will be set to 4294967295. Setting it to a lower value signals that special stuff is going on.
Sign the Raw Transaction
To date, your raw transaction is just something theoretical: you could send it, but nothing has been promised. You have to do a few things to get it out onto the network.
First, you need to sign your raw transaction:
$ bitcoin-cli signrawtransactionwithwallet $rawtxhex
{
"hex": "02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000",
"complete": true
}
$ signedtx="02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000"
Note that we captured the signed hex by hand, rather than trying to parse it out of the JSON object. A software package called "JQ" could do better, as we'll explain in an upcoming interlude.
Send the Raw Transaction
You've now got a ready-to-go raw transaction, but it doesn't count until you actually put it on the network, which you do with the sendrawtransaction
command. You'll get back a txid:
$ bitcoin-cli sendrawtransaction $signedtx
a1fd550d1de727eccde6108c90d4ffec11ed83691e96e119d842b3f390e2f19a
You'll immediately see that the UTXO and its money have been removed from your wallet:
$ bitcoin-cli listunspent
[
{
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
"vout": 0,
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
"label": "",
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
"amount": 0.00010000,
"confirmations": 23,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
"safe": true
},
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00022000,
"confirmations": 6,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
}
]
$ bitcoin-cli getbalance
0.00032000
Soon listtransactions
should show a confirmed transaction of category 'send".
{
"address": "n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi",
"category": "send",
"amount": -0.00040000,
"vout": 0,
"fee": -0.00010000,
"confirmations": 1,
"trusted": true,
"txid": "a1fd550d1de727eccde6108c90d4ffec11ed83691e96e119d842b3f390e2f19a",
"walletconflicts": [
],
"time": 1592608574,
"timereceived": 1592608574,
"bip125-replaceable": "no",
"abandoned": false
}
You can see that it matches the txid
and the recipient
address. Not only does it show the amount
sent, but it also shows the transaction fee
. And, it's already received a confirmation, because we offered a fee that would get it swept up into a block quickly.
Congratulations! You're now a few satoshis poorer!
Summary: Creating a Raw Transaction
When money comes into your Bitcoin wallet, it remains as distinct amounts, called UTXOs. When you create a raw transaction to send that money back out, you use one or more UTXOs to fund it. You then can create a raw transaction, sign it, and send it on the Bitcoin network. However, this is just a foundation: you'll usually need to create a raw transaction with multiple outputs to actually send something on the bitcoin network!
What's Next?
Step Back from "Sending Bitcoin Transactions" with Interlude: Using JQ.
4.3 Creating a Raw Transaction with Named Arguments
It can sometimes be daunting to figure out the right order for the arguments to a bitcoin-cli command. Fortunately, you can use named arguments as an alternative.
:warning: VERSION WARNING: This is an innovation from Bitcoin Core v 0.14.0. If you used our setup scripts, that's what you should have, but double-check your version if you have any problems. There is also a bug in the
createrawtransaction
command's use of named arguments that will presumably be fixed in 0.14.1.
Create a Named Argument Alias
To use a named argument you must run bitcoin-cli
with the -named
argument. If you plan to do this regularly, you'll probably want to create an alias:
alias bitcoin-cli="bitcoin-cli -named"
As usual, that's for your ease of use, but we'll continue using the whole commands to maintain clarity.
Test Out a Named Argument
To learn what the names are for the arguments of a command, consult bitcoin-cli help
. It will list the arguments in their proper order, but will now also give names for each of them.
For example, bitcoin-cli help getbalance
lists these arguments:
- dummy [used to be account]
- minconf
- include_watchonly
- avoid_reuse
The following shows a traditional, unintuitive usage of getbalance
using the minimum confirmation argument:
$ bitcoin-cli getbalance "*" 1
With named arguments, you can clarify what you're doing, which also minimizes mistakes:
$ bitcoin-cli -named getbalance minconf=1
Test Out a Raw Transaction
Here's what the commands for sending a raw transaction would look like with named arguments:
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
$ recipient="n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.00001 }''')
$ bitcoin-cli -named decoderawtransaction hexstring=$rawtxhex
{
"txid": "2b59c31bc232c0399acee4c2a381b564b6fec295c21044fbcbb899ffa56c3da5",
"hash": "2b59c31bc232c0399acee4c2a381b564b6fec295c21044fbcbb899ffa56c3da5",
"version": 2,
"size": 85,
"vsize": 85,
"weight": 340,
"locktime": 0,
"vin": [
{
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
"vout": 0,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.00001000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 e7c1345fc8f87c68170b3aa798a956c2fe6a9eff OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
]
}
}
]
}
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
e70dd2aa13422d12c222481c17ca21a57071f92ff86bdcffd7eaca71772ba172
Voila! You've sent out another raw transaction, but this time using named arguments for clarity and to reduce errors.
:warning: VERSION WARNING: There is where the bug in Bitcoin Core 0.14 shows up: the 'inputs' argument for 'createrawtransaction' is misnamed 'transactions'. So, if you're on Bitcoin Core 0.14.0, substitute the named argument 'inputs' with 'transactions' for this and future examples. However, as of Bitcoin Core 0.14.1, this code should work as shown.
Summary: Creating a Raw Transaction with Named Arguments
By running bitcoin-cli
with the -named
flag, you can use named arguments rather than depending on ordered arguments. bitcoin-cli help
will always show you the right name for each argument. This can result in more robust, easier-to-read, less error-prone code.
These docs will use named arguments for all future examples, for clarity and to establish best practices. However, it will also show all arguments in the correct order. So, if you prefer not to use named args, just strip out the '-named' flag and all of the "name="s and the examples should continue to work correctly.
What's Next?
Continue "Sending Bitcoin Transactions" with §4.4: Sending Coins with Raw Transactions.
Interlude: Using Curl
bitcoin-cli
is ultimately just a wrapper. It's a way to interface with bitcoind
from the command line, providing simplified access to its many RPC commands. But RPC can, of course, be accessed directly. That's what this interlude is about: directly connecting to RPC with the curl
command.
It won't be used much in the future chapters, but it's an important building block that you can see as an alternative access to bitcoind
is you so prefer.
Know Your Curl
curl
, short for "see URL", is a command-line tool that allows you to directly access URLs in a programmatic way. It's an easy way to interact with servers like bitcoind
that listen to ports on the internet and that speak a variety of protocols. Curl is also available as a library for many programming languages, such as C, Java, PHP, and Python. So, once you know how to work with Curl, you'll have a strong foundation for using a lot of different API.
In order to use curl
with bitcoind
, you must know three things: the standard format, the user name and password, and the correct port.
Know Your Format
The bitcoin-cli
commands are all linked to RPC commands in bitcoind
. That makes the transition from using bitcoin-cli
to using curl
very simple. In fact, if you look at any of the help pages for bitcoin-cli
, you'll see that they list not only the bitcoin-cli
commands, but also parallel curl
commands. For example, here is bitcoin-cli help getmininginfo
:
$ bitcoin-cli help getmininginfo
getmininginfo
Returns a json object containing mining-related information.
Result:
{ (json object)
"blocks" : n, (numeric) The current block
"currentblockweight" : n, (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)
"currentblocktx" : n, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)
"difficulty" : n, (numeric) The current difficulty
"networkhashps" : n, (numeric) The network hashes per second
"pooledtx" : n, (numeric) The size of the mempool
"chain" : "str", (string) current network name (main, test, regtest)
"warnings" : "str" (string) any network and blockchain warnings
}
Examples:
> bitcoin-cli getmininginfo
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getmininginfo", "params": []}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
And there's the curl
command, at the end of the help screen! This somewhat lengthy command has four major parts: (1) a listing of your user name; (2) a --data-binary
flag; (3) a JSON object that tells bitcoind
what to do, including a JSON array of parameters; and (4) an HTTP header that includes the bitcoind
URL.
When you are working with curl
, most of these arguments to curl
will stay the same from command to command; only the method
and params
entries in the JSON array will typically change. However, you need to know how to fill in your username and your URL address in order to make it work in the first place!
Whenever you're unsure about how to curl an RPC command, just look at the bitcoin-cli help and go from there.
Know Your User Name
In order to speak with the bitcoind
port, you need a user name and password. These were created as part of your initial Bitcoin setup, and can be found in ~/.bitcoin/bitcoin.conf
.
For example, here's our current setup:
$ cat ~/.bitcoin/bitcoin.conf
server=1
dbcache=1536
par=1
maxuploadtarget=137
maxconnections=16
rpcuser=StandUp
rpcpassword=8eaf562eaf45c33c3328bc66008f2dd1
rpcallowip=127.0.0.1
debug=tor
prune=550
testnet=1
mintxfee=0.001
txconfirmtarget=1
[test]
rpcbind=127.0.0.1
rpcport=18332
[main]
rpcbind=127.0.0.1
rpcport=8332
[regtest]
rpcbind=127.0.0.1
rpcport=18443
Our user name is StandUp
and our password is 8eaf562eaf45c33c3328bc66008f2dd1
.
WARNING: Clearly, it's not very secure to have this information in a plain text file. As of Bitcoin Core 0.12, you can instead omit the
rpcpassword
from yourbitcoin.conf
file, and havebitcoind
generate a new cookie whenever it starts up. The downside of this is that it makes use of RPC commands by other applications, such as the ones detailed in this chapter, more difficult. So, we're going to stick with the plainrpcuser
andrpcpassword
information for now, but for production software, consider moving to cookies.
The secure way to RPC with bitcoind
is as follows:
$ curl --user StandUp --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
Enter host password for user 'bitcoinrpc':
As noted, you will be prompted for your password.
:link: TESTNET vs MAINNET: Testnet uses a URL with port 18332 and mainnet uses a URL with port 8332. Take a look in your
bitcoin.conf
, it's all laid out there.
The insecure way to do so is as follows:
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
WARNING: Entering your password on the command line may put your password into the process table and/or save it into a history. This is even less recommended than putting it in a file, except for testing on testnet. If you want to do it anywhere else, make sure you know what you're doing!
Know Your Command & Parameters
With all of that in hand, you're ready to send off standard RPC commands with curl
... but you still need to know how to incorporate the two elements that tend to change in the curl
command.
The first is method
, which is the RPC method being used. This should generally match the command names you've been feeding into bitcoin-cli
for ages.
The second is params
, which is a JSON array of parameters. These are the same as the arguments (or named arguments) that you've been using. They're also the most confusing part of curl
, in large part because they're a structured array rather than a simple list.
Here's what some parameter arrays will look like:
[]
— An empty array["000b4430a7a2ba60891b01b718747eaf9665cb93fbc0c619c99419b5b5cf3ad2"]
— An array with data["'$signedhex'"]
— An array with a variable[6, 9999999]
— An array with two parameters{}
- An empty object[''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]'', ''{ "'$recipient'": 0.298, "'$changeaddress'": 1.0}'']
— An array with an array containing an object and a bare object
Get Information
You can now send your first curl
command by accessing the getmininginfo
RPC:
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
{"result":{"blocks":1772428,"difficulty":10178811.40698772,"networkhashps":91963587385939.06,"pooledtx":61,"chain":"test","warnings":"Warning: unknown new rules activated (versionbit 28)"},"error":null,"id":"curltest"}
Note that we provided the method, getmininginfo
, and the parameter, []
, but that everything else was the standard curl
command line.
WARNING: If you get a result like "Failed to connect to 127.0.0.1 port 8332: Connection refused", be sure that a line like
rpcallowip=127.0.0.1
is in your ~/.bitcoin/bitcoin.conf. If things still don't work, be sure that you're allowing access to port 18332 (or 8332) from localhost. Our standard setup from Chapter Two: Creating a Bitcoin-Core VPS should do all of this.
The result is another JSON array, which is unfortunately ugly to read if you're using curl
by hand. Fortunately, you can clean it up simply by piping it through jq
:
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 295 100 218 100 77 72666 25666 --:--:-- --:--:-- --:--:-- 98333
{
"result": {
"blocks": 1772429,
"difficulty": 10178811.40698772,
"networkhashps": 90580030969896.44,
"pooledtx": 4,
"chain": "test",
"warnings": "Warning: unknown new rules activated (versionbit 28)"
},
"error": null,
"id": "curltest"
}
You'll see a bit of connectivity reporting as the data is downloaded, then when that data hits jq
, everything will be output in a correctly indented form. (We'll be omitting the download information in future examples.)
Manipulate Your Wallet
Though you're accessing bitcoind
directly, you'll still get access to wallet functionality, because that's largely stored in bitcoind
itself.
Look Up Addresses
Use the getaddressesbylabel
RPC to list all of your current addresses:
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getaddressesbylabel", "params": [""] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
{
"result": {
"mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE": {
"purpose": "receive"
},
"mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff": {
"purpose": "receive"
},
"moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B": {
"purpose": "receive"
},
"mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d": {
"purpose": "receive"
},
"tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6": {
"purpose": "receive"
},
"tb1qmtucvjtga68kgrvkl7q05x4t9lylxhku7kqdpr": {
"purpose": "receive"
}
},
"error": null,
"id": "curltest"
}
This is our first example of a real parameter, ""
. This is the required label
parameter for getaddressesbylabel
, but all of our addresses are under the default label, so nothing special was required here.
The result is a list of all the addresses that have been used by this wallet ... some of which presumably contain funds.
Look Up Funds
Use the listunspent
RPC to list the funds that you have available:
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listunspent", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
{
"result": [
{
"txid": "e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d",
"vout": 1,
"address": "mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h",
"scriptPubKey": "76a91432db726320e4ad170c9c1ee83cd4d8a243c3435988ac",
"amount": 0.0009,
"confirmations": 4,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/1'/2']02881697d252d8bf181d08c58de1f02aec088cd2d468fc5fd888c6e39909f7fabf)#p6k7dptk",
"safe": true
},
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00022,
"confirmations": 19,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
}
],
"error": null,
"id": "curltest"
}
This is almost exactly the same output that you receive when you type bitcoin-cli listunspent
, showing how closely tied the two interfaces are. If no cleanup or extra help is needed, then bitcoin-cli
just outputs the RPC. Easy!
Create an Address
After you know where your funds are, the next step in crafting a transaction is to get a change address. By now you've probably got the hang of this, and you know that for simple RPC commands, all you need to do is adjust the method
is the curl
command:
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getrawchangeaddress", "params": ["", "legacy"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
{
"result": "mrSqN37TPs89GcidSZTvXmMzjxoJZ6RKoz",
"error": null,
"id": "curltest"
}
WARNING: The parameters order is important when you are sending RPC commands using curl. For example here, if we had sent
"params": ["legacy"]
instead of"params": ["", "legacy"]
, we would get abech32
address with a label of"legacy"
instead of alegacy
address, so pay attention to the order.
At this point, we can even revert to our standard practice of saving results to variables with additional help from jq
:
$ changeaddress=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getrawchangeaddress", "params": ["", "legacy"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result')
$ echo $changeaddress
mqdfnjgWr2r3sCCeuTDfe8fJ1CnycF2e6R
No need to worry about the downloading info. It'll go to STDERR
and be displayed on your screen, while the results go to STDOUT
and are saved in your variable.
Create a Transaction
You're now ready to create a transaction with curl
.
Ready Your Variables
Just as with bitcoin-cli
, in order to create a transaction by curling RPC commands, you should first save your variables. The only change here is that curl
creates a JSON object that includes a result
key-value, so you always need to pipe through the .result
tag before you do anything else.
This example sets up our variables for using the 1.2985 BTC in funds listed in the first unspent transaction above:
$ utxo_txid=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listunspent", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result | .[0] | .txid')
$ utxo_vout=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listunspent", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result | .[0] | .vout')
$ recipient=mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf
$ changeaddress=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getrawchangeaddress", "params": ["legacy"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result')
$ echo $utxo_txid
e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d
$ echo $utxo_vout
1
$ echo $recipient
mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf
$ echo $changeaddress
n2jf3MzeFpFGa7wq8rXKVnVuv5FoNSJZ1N
Create the Transaction
The transaction created with curl
is very similar to the transaction created with bitcoin-cli
, but with a few subtle differences:
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "createrawtransaction", "params": [''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]'', ''{ "'$recipient'": 0.0003, "'$changeaddress'": 0.0005}'']}' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
{
"result": "02000000010d6acd0356db222ca3a7ee7fa1e3044316223ceec1f64b58aeb2e0de921007e70100000000ffffffff0230750000000000001976a914ac19d3fd17710e6b9a331022fe92c693fdf6659588ac50c30000000000001976a9147021efec134057043386decfaa6a6aa4ee5f19eb88ac00000000",
"error": null,
"id": "curltest"
}
The heart of the transaction is, of course, the params
JSON array, which we're putting to full use for the first time.
Note that the entire params
is lodged in []
s to mark the parameters array.
We've also varied up the quoting from how things worked in bitcoin-cli
, to start and end each array and object within the params
array with ''
instead of our traditional '''
. That's because the entire set of JSON arguments already has a '
around it. As usual, just take a look at the bizarre shell quoting and get used to it.
However, there's one last thing of note in this example, and it can be maddening if you miss it. When you executed a createrawtransaction
command with bitcoin-cli
the JSON array of inputs and the JSON object of outputs were each distinct parameters, so they were separated by a space. Now, because they're part of that params
JSON array, they're separated by a comma (,
). Miss that and you'll get a parse error
without much additional information.
WARNING: Ever having troubles debugging your
curl
? Add the argument--trace-ascii /tmp/foo
. Full information on what's being sent to the server will be saved in/tmp/foo
(or whatever file name you provide).
Having verified that things work, you probably want to save the hex code into a variable:
$ hexcode=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "createrawtransaction", "params": [''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]'', ''{ "'$recipient'": 0.0003, "'$changeaddress'": 0.0005}'']}' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result')
Sign and Send
Signing and sending your transaction using curl
is an easy use of the signrawtransactionwithwallet
and sendrawtransaction
RPC:
$ signedhex=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "signrawtransactionwithwallet", "params": ["'$hexcode'"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result | .hex')
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "sendrawtransaction", "params": ["'$signedhex'"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
{
"result": "eb84c5008038d760805d4d9644ace67849542864220cb2685a1ea2c64176b82d",
"error": null,
"id": "curltest"
}
Summary: Accessing Bitcoind with Curl
Having finished this section, you may feel that accessing bitcoind
via curl
is very much like accessing it through bitcoin-cli
... but more cumbersome. And, you'd be right. bitcoin-cli
has pretty complete RPC functionality, so anything that you do through curl
you can probably do through bitcoin-cli
. Which is why we're going to continue concentrating on bitcoin-cli
following this digression.
But there are still reasons you'd use curl
instead of bitcoin-cli
:
What is the power of curl? Most obviously, curl
takes out one level of indirection. Instead of working with bitcoin-cli
which sends RPC commands to bitcoind
, you're sending those RPC commands directly. This allows for more robust programming, because you don't have to worry about what unexpected things that bitcoin-cli
might do or how it might change over time. However, you're also taking your first steps toward using a more comprehensive programming language than the poor options offered by a shell script. As you'll see in the last few chapters of this, you might actually see curl libraries are other functions to access the RPC commands in a variety of programming languages: but that's still a long ways away.
What's Next?
Learn one more way to "Send Bitcoin Transactions" with §4.5 Sending Coins with Automated Raw Transactions.
4.4: Sending Coins with Raw Transactions
As noted at the start of this chapter, the bitcoin-cli
interface offers three major ways to send coins. §4.1 talked about sending them the first way, using the sendtoaddress
command. Since then, we've been building details on how to send coins a second way, with raw transactions. §4.2 taught how to create a raw transaction, an Interlude explained JQ, and §4.3 demonstrated named arguments.
We can now put those together and actually send funds using a raw transaction.
Create a Change Address
Our sample raw transaction in section §4.2 was very simplistic: we sent the entirety of a UTXO to a new address. More frequently, you'll want to send someone an amount of money that doesn't match a UTXO. But, you'll recall that the excess money from a UTXO that's not sent to your recipient just becomes a transaction fee. So, how do you send someone just part of a UTXO, while keeping the rest for yourself?
The solution is to send the rest of the funds to a second address, a change address that you've created in your wallet specifically to receive them:
$ changeaddress=$(bitcoin-cli getrawchangeaddress legacy)
$ echo $changeaddress
mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h
Note that this uses a new function: getrawchangeaddress
. It's largely the same as getnewaddress
but is optimized for use as a change address in a raw transaction, so it doesn't do things like make entries in your address book. We again selected the legacy
address, instead of going with the default of bech32
, simply for consistency. This is a situation where it would have been entirely safe to generate a default Bech32 address, just by using bitcoin-cli getrawchangeaddress
, because it would being sent and received by you on your Bitcoin Core node which fully supports this. But, hobgoblins; we'll shift this over to Bech32 as well in §4.6.
You now have an additional address inside your wallet, so that you can receive change from a UTXO! In order to use it, you'll need to create a raw transaction with two outputs.
Pick Sufficient UTXOs
Our sample raw transaction was simple in another way: it assumed that there was enough money in a single UTXO to cover the transaction. Often this will be the case, but sometimes you'll want to create transactions that spends more money than you have in a single UTXO. To do so, you must create a raw transaction with two (or more) inputs.
Write a Real Raw Transaction
To summarize: creating a real raw transaction to send coins will sometimes require multiple inputs and will almost always require multiple outputs, one of which is a change address. We'll be creating that sort of more realistic transaction here, in a new example that shows a real-life example of sending funds via Bitcoin's second methodology, raw transactions.
We're going to use our 0th and 2nd UTXOs:
$ bitcoin-cli listunspent
[
[
{
"txid": "0619fecf6b2668fab1308fbd7b291ac210932602a6ac6b8cc11c7ae22c43701e",
"vout": 1,
"address": "mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d",
"label": "",
"scriptPubKey": "76a914ad1ed1c5971b2308f89c1362d4705d020a40e8e788ac",
"amount": 0.00899999,
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/4']03eae28c93035f95a620dd96e1822f2a96e0357263fa1f87606a5254d5b9e6698f)#wwnfx2sp",
"safe": true
},
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00022000,
"confirmations": 15,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
},
{
"txid": "0df23a9dba49e822bbc558f15516f33021a64a5c2e48962cec541e0bcc79854d",
"vout": 0,
"address": "mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d",
"label": "",
"scriptPubKey": "76a914ad1ed1c5971b2308f89c1362d4705d020a40e8e788ac",
"amount": 0.00100000,
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/4']03eae28c93035f95a620dd96e1822f2a96e0357263fa1f87606a5254d5b9e6698f)#wwnfx2sp",
"safe": true
}
]
In our example, we're going to send .009 BTC, which is (barely) larger than either of our UTXOs. This requires combining them, then using our change address to retrieve the unspent funds.
Set Up Your Variables
We already have $changeaddress
and $recipient
variables from previous examples:
$ echo $changeaddress
mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h
$ echo $recipient
n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
We also need to record the txid and vout for each of our two UTXOs. Having identified the UTXOs that we want to spend, we can use our JQ techniques to make sure accessing them is error free:
$ utxo_txid_1=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
$ utxo_vout_1=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
$ utxo_txid_2=$(bitcoin-cli listunspent | jq -r '.[2] | .txid')
$ utxo_vout_2=$(bitcoin-cli listunspent | jq -r '.[2] | .vout')
Write the Transaction
Writing the actual raw transaction is surprisingly simple. All you need to do is include an additional, comma-separated JSON object in the JSON array of inputs and an additional, comma-separated key-value pair in the JSON object of outputs.
Here's the example. Note the multiple inputs after the inputs
arg and the multiple outputs after the outputs
arg.
$ rawtxhex2=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' } ]''' outputs='''{ "'$recipient'": 0.009, "'$changeaddress'": 0.0009 }''')
We were very careful figuring out our money math. These two UTXOs contain 0.00999999 BTC. After sending 0.009 BTC, we'll have .00099999 BTC left. We chose .00009999 BTC the transaction fee. To accommodate that fee, we set our change to .0009 BTC. If we'd messed up our math and instead set our change to .00009 BTC, that additional BTC would be lost to the miners! If we'd forgot to make change at all, then the whole excess would have disappeared. So, again, be careful.
Fortunately, we can triple-check with the btctxfee
alias from the JQ Interlude:
$ ./txfee-calc.sh $rawtxhex2
.00009999
Finish It Up
You can now sign, seal, and deliver your transaction, and it's yours (and the faucet's):
$ signedtx2=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex2 | jq -r '.hex')
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx2
e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d
Wait
As usual, your money will be in flux for a while: the change will be unavailable until the transaction actually gets confirmed and a new UTXO is given to you.
But, in 10 minutes or less (probably), you'll have your remaining money back and fully spendable again. For now, we're still waiting:
$ bitcoin-cli listunspent
[
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00022000,
"confirmations": 15,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
}
]
And the change will eventuall arrive:
[
{
"txid": "e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d",
"vout": 1,
"address": "mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h",
"scriptPubKey": "76a91432db726320e4ad170c9c1ee83cd4d8a243c3435988ac",
"amount": 0.00090000,
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/1'/2']02881697d252d8bf181d08c58de1f02aec088cd2d468fc5fd888c6e39909f7fabf)#p6k7dptk",
"safe": true
},
{
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
"vout": 0,
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
"label": "",
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
"amount": 0.00022000,
"confirmations": 16,
"spendable": true,
"solvable": true,
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
"safe": true
}
]
This also might be a good time to revisit a blockchain explorer, so that you can see more intuitively how the inputs, outputs, and transaction fee are all laid out: e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d.
Summary: Sending Coins with Raw Transactions
To send coins with raw transactions, you need to create a raw transaction with one or more inputs (to have sufficient funds) and one or more outputs (to retrieve change). Then, you can follow your normal procedure of using createrawtransaction
with named arguments and JQ, as laid out in previous sections.
:fire: What is the power of sending coins with raw transactions?
The advantages. It gives you the best control. If your goal is to write a more intricate Bitcoin script or program, you'll probably use raw transactions so that you know exactly what's going on. This is also the safest situation to use raw transactions, because you can programmatically ensure that you don't make mistakes.
The disadvantages. It's easy to lose money. There are no warnings, no safeguards, and no programmatic backstops unless you write them. It's also arcane. The formatting is obnoxious, even using the easy-to-use
bitcoin-cli
interface, and you have to do a lot of lookup and calculation by hand.
What's Next?
See another alternative way to input commands with Interlude: Using Curl.
Or, you prefer to skip what's frankly a digression, learn one more way to "Send Bitcoin Transactions" with §4.5 Sending Coins with Automated Raw Transactions.
4.5: Sending Coins with Automated Raw Transactions
This chapter lays out three ways to send funds via Bitcoin's cli interface. §4.1 described how to do so with a simple command, and §4.4 detailed how to use a more dangerous raw transaction. This final section splits the difference by showing how to make raw transactions simpler and safer.
Let Bitcoin Calculate For You
The methodology for automated raw transactions is simple: you create a raw transaction, but you use the fundrawtransaction
command to ask the bitcoind to run the calculations for you.
In order to use this command, you'll need to ensure that your ~/.bitcoin/bitcoin.conf file contains rational variables for calculating transaction fees. Please see §4.1: Sending Coins The Easy Way for more information on this.
For very conservative numbers, we suggested adding the following to the bitcoin.conf
:
mintxfee=0.0001
txconfirmtarget=6
To keep the tutorial moving along (and more generally to move money fast) we suggested the following:
mintxfee=0.001
txconfirmtarget=1
Create a Bare Bones Raw Transaction
To use fundrawtransaction
you first need to create a bare-bones raw transaction that lists no inputs and no change address. You'll just list your recipient and how much you want to send them, in this case $recipient
and 0.0002
BTC.
$ recipient=n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
$ unfinishedtx=$(bitcoin-cli -named createrawtransaction inputs='''[]''' outputs='''{ "'$recipient'": 0.0002 }''')
Fund Your Bare Bones Transaction
You then tell bitcoin-cli
to fund that bare-bones transaction:
$ bitcoin-cli -named fundrawtransaction hexstring=$unfinishedtx
{
"hex": "02000000012db87641c6a21e5a68b20c226428544978e6ac44964d5d8060d7388000c584eb0100000000feffffff02204e0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac781e0000000000001600140cc9cdcf45d4ea17f5227a7ead52367aad10a88400000000",
"fee": 0.00022200,
"changepos": 1
}
That provides a lot of useful information, but once you're confident with how it works, you'll want to use JQ to save your hex to a variable, as usual:
$ rawtxhex3=$(bitcoin-cli -named fundrawtransaction hexstring=$unfinishedtx | jq -r '.hex')
Verify Your Funded Transaction
It seems like magic, so the first few times you use fundrawtransaction
, you'll probably want to verify it.
Running decoderawtransaction
will show that the raw transaction is now laid out correctly, using one or more of your UTXOs and sending excess funds back to a change address:
$ bitcoin-cli -named decoderawtransaction hexstring=$rawtxhex3
{
"txid": "b3b4c2057dbfbef6690e975ede92fde805ddea13c730f58401939a52c9ac1b99",
"hash": "b3b4c2057dbfbef6690e975ede92fde805ddea13c730f58401939a52c9ac1b99",
"version": 2,
"size": 116,
"vsize": 116,
"weight": 464,
"locktime": 0,
"vin": [
{
"txid": "eb84c5008038d760805d4d9644ace67849542864220cb2685a1ea2c64176b82d",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 0.00020000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 e7c1345fc8f87c68170b3aa798a956c2fe6a9eff OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
]
}
},
{
"value": 0.00007800,
"n": 1,
"scriptPubKey": {
"asm": "0 a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
"hex": "0014a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
"reqSigs": 1,
"type": "witness_v0_keyhash",
"addresses": [
"tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r"
]
}
}
]
}
One thing of interest here is the change address, which is the second vout
. Note that it's a tb1
address, which means that it's Bech32; when we gave Bitcoin Core the total ability to manage our change, it did so using its default address type, Bech32, and it worked fine. That's why our change to SegWit addresses in §4.6 really isn't that big of a deal, but there are some gotchas for wider usage, which we'll talk about there.
Though we saw the fee in the fundrawtransaction
output, it's not visible here. However, you can verify it with the txfee-calc.sh
JQ script created in the JQ Interlude:
$ ~/txfee-calc.sh $rawtxhex3
.000222
Finally, you can use getaddressinfo
to see that the generated change address really belongs to you:
$ bitcoin-cli -named getaddressinfo address=tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r
{
"address": "tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r",
"scriptPubKey": "0014a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
"ismine": true,
"solvable": true,
"desc": "wpkh([d6043800/0'/1'/10']038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec5)#zpv26nar",
"iswatchonly": false,
"isscript": false,
"iswitness": true,
"witness_version": 0,
"witness_program": "a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
"pubkey": "038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec5",
"ischange": true,
"timestamp": 1592335137,
"hdkeypath": "m/0'/1'/10'",
"hdseedid": "fdea8e2630f00d29a9d6ff2af7bf5b358d061078",
"hdmasterfingerprint": "d6043800",
"labels": [
]
}
Note the ismine
results.
Send Your Funded Transaction
At this point you can sign and send the transaction as usual.
$ signedtx3=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex3 | jq -r '.hex')
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx3
8b9dd66c999966462a3d88d6ac9405d09e2aa409c0aa830bdd08dbcbd34a36fa
In several minutes, you'll have your change back:
$ bitcoin-cli listunspent
[
{
"txid": "8b9dd66c999966462a3d88d6ac9405d09e2aa409c0aa830bdd08dbcbd34a36fa",
"vout": 1,
"address": "tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r",
"scriptPubKey": "0014a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
"amount": 0.00007800,
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "wpkh([d6043800/0'/1'/10']038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec5)#zpv26nar",
"safe": true
}
]
Summary: Sending Coins with Automated Raw Transactions
If you must send funds with raw transactions then fundrawtransaction
gives you a nice alternative where fees, inputs, and outputs are calculated for you, so you don't accidentally lose a bunch of money.
:fire: What is the power of sending coins with automated raw transactions?
The advantages. It provides a nice balance. If you're sending funds by hand and
sendtoaddress
doesn't offer enough control for whatever reason, you can get some of the advantages of raw transactions without the dangers. This methodology should be used whenever possible if you're sending raw transactions by hand.
The disadvantages. It's a hodge-podge. Though there are a few additional options for the
fundrawtransaction
command that weren't mentioned here, your control is still limited. You'd probably never want to use this method if you were writing a program where the whole goal is to know exactly what's going on.
What's Next?
Complete your "Sending of Bitcoin Transactions" with §4.6: Creating a Segwit Transaction.
4.6: Creating a SegWit Transaction
:information_source: NOTE: This section has been recently added to the course and is an early draft that may still be awaiting review. Caveat reader.
Once upon a time, the Bitcoin heavens shook with the blocksize wars. Fees were skyrocketing, and users were worried about scaling. The Bitcoin Core developers were reluctant to simply increase the blocksize, but they came upon a compromise: SegWit, the Segregated Witness. Segregated Witness is a fancy way of saying "Separated Signature". It creates new sorts of transactions that remove signatures to the end of the transaction. By combining this with increased block sizes that only are visible to upgraded nodes, SegWit resolved the scaling problems for Bitcoin at the time (and also resolved a nasty malleability bug that had previously made even better scaling with layer-2 protocols like Lightning impractical).
The catch? SegWit uses different addresses, some of which are compatible with older nodes, and some of which are not.
:warning: VERSION WARNING: SegWit was introduced in BitCoin 0.16.0 with what was described at the time as "full support". With that said, there were some flaws in its integration with
bitcoin-cli
at the time which prevented signing from working correctly on new P2SH-SegWit addresses. The non-backward-compatible Bech32 address was also introduced in Bitcoin 0.16.0 and was made the default addresstype in Bitcoin 0.19.0. All of this functionality should now fully work with regard tobitcoin-cli
functions (and thus this tutorial).
The catch comes in interacting with the wider world. Everyone should be able to send to a P2SH-SegWit address because it was purposefully built to support backward compatibility by wrapping the SegWit functionality in a Bitcoin Script. The same isn't true for Bech32 addresses: if someone tells you that they're unable to send to your Bech32 address, this is why, and you need to generate a
legacy
or P2SH-SegWit address for their usage. (Many sites, particularly exchanges, can also not generate or receive on SegWit addresses, particularly Bech32 addresses, but that's a whole different issue and doesn't affect your usage of them.)
Understand a SegWit Transaction
In classic transactions, signature (witness) information was stored toward the middle of the transaction, while in SegWit transactions, it's at the bottom. This goes hand-in-hand with the blocksize increases that were introduced in the SegWit upgrade. The blocksize was increased from 1M to a variable amount based on how many SegWit transactions are in a block, starting as low as 1M (no SegWit transactions) and going as high as 4M (all SegWit transactions). This variable size was created to accomodate classic nodes, so that everything remains backward compatible. If a classic node sees a SegWit transaction, it throws out the witness information (resulting in a smaller sized block, under the old 1M limit), while if a new node sees a SegWit transaction, it keeps the witness information (resulting in a larger sized block, up to the new 4M limit).
So that's the what and how of SegWit transactions. Not that you need to know any of it to use them. Most transactions on the Bitcoin network are now SegWit. They're what you're going to natively use for more transactions and receipts of money. The details are no more relevant at this point than the details of how most of Bitcoin works.
Create a SegWit Address
You create a SegWit address the same way as any other address, with the getnewaddress
and the getrawchangeaddress
commands.
If you need to create an address for someone who can't send to the newer Bech32 addresses, then use the p2sh-segwit
addresstype:
$ bitcoin-cli -named getnewaddress address_type=p2sh-segwit
2N5h2r4karVqN7uFtpcn8xnA3t5cbpszgyN
Seeing an address with a "2" prefix means that you did it right.
:link: TESTNET vs MAINNET: "3" for Mainnet.
However, if the person you're interacting with has a fully mature client, they'll be able to send to a Bech32 address, which you create using the commands in the default way:
$ bitcoin-cli getnewaddress
tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6
As we've already seen, change addresses generated from within bitcoin-cli
interact fine with Bech32 addresses, so there's no point in using the legacy
flag there either:
$ bitcoin-cli getrawchangeaddress
tb1q05wx5tyadm8qe83exdqdyqvqqzjt3m38vfu8ff
Here, note that the unique "tb1" prefix denoted Bech32.
:link: TESTNET vs MAINNET: "bc1" for mainnet.
Bitcoin-cli doesn't care which address type you're using. You can run a command like listaddressgroupings
and it will freely mix addresses of the different types:
$ bitcoin-cli listaddressgroupings
[
[
[
"mfsiRhxbQxcD7HLS4PiAim99oeGyb9QY7m",
0.01000000,
""
]
],
[
[
"mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
0.00000000,
""
],
[
"tb1q6dak4e9fz77vsulk89t5z92l2e0zm37yvre4gt",
0.00000000
]
],
[
[
"mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
0.00022000,
""
]
],
[
[
"mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h",
0.00000000
],
[
"mqjrdY5raxKzXQf5t2VvVvzhvFAgersu9B",
0.00000000
],
[
"mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d",
0.00000000,
""
],
[
"tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r",
0.00007800
]
],
[
[
"mpVLL7iqPr4d7BJkEG54mcdm7WmrAhaW6q",
0.01000000,
""
]
],
[
[
"tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6",
0.01000000,
""
]
]
]
Send a SegWit Transaction The Easy Way
So how do you send a Segwit transaction? Exactly like any other transaction. It doesn't matter if the UTXO is SegWit, the address is SegWit, or some combination thereof. You can expect bitcoin-cli
to do the right thing. Though you can tell the differences via the addresses, they don't matter for interacting with things at the bitcoin-cli
or RPC level. (And this is one of the advantages of using the command line and the RPC interface, as suggested in this tutorial: experts have already done the hard work for you, including things like how to send to both legacy and Bech32 addresses. You just get to use that functionality to your own advantage.)
Here's an example of sending to a SegWit address, the easy way:
$ bitcoin-cli sendtoaddress tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx 0.005
854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42
If you look at your transaction, you can see the use of the Bech32 address:
$ bitcoin-cli -named gettransaction txid="854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42" verbose=true
{
"amount": -0.00500000,
"fee": -0.00036600,
"confirmations": 0,
"trusted": true,
"txid": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
"walletconflicts": [
],
"time": 1592948795,
"timereceived": 1592948795,
"bip125-replaceable": "no",
"details": [
{
"address": "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
"category": "send",
"amount": -0.00500000,
"vout": 1,
"fee": -0.00036600,
"abandoned": false
}
],
"hex": "0200000002114d5a4c3b847bc796b2dc166ca7120607b874aa6904d4a43dd5f9e0ea79d4ba010000006a47304402200a3cc08b9778e7b616340d4cf7841180321d2fa019e43f25e7f710d9a628b55c02200541fc200a07f2eb073ad8554357777d5f1364c5a96afe5e77c6185d66a40fa7012103ee18c598bafc5fbea72d345329803a40ebfcf34014d0e96aac4f504d54e7042dfeffffffa71321e81ef039af490251379143f7247ad91613c26c8f3e3404184218361733000000006a47304402200dd80206b57beb5fa38a3c3578f4b0e40d56d4079116fd2a6fe28e5b8ece72310220298a8c3a1193ea805b27608ff67a2d8b01e347e33a4222edfba499bb1b64a31601210339c001b00dd607eeafd4c117cfcf86be8efbb0ca0a33700cffc0ae0c6ee69d7efeffffff026854160000000000160014d591091b8074a2375ed9985a9c4b18efecfd416520a1070000000000160014751e76e8199196d454941c45d1b3a323f1433bd6c60e1b00",
"decoded": {
"txid": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
"hash": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
"version": 2,
"size": 366,
"vsize": 366,
"weight": 1464,
"locktime": 1773254,
"vin": [
{
"txid": "bad479eae0f9d53da4d40469aa74b8070612a76c16dcb296c77b843b4c5a4d11",
"vout": 1,
"scriptSig": {
"asm": "304402200a3cc08b9778e7b616340d4cf7841180321d2fa019e43f25e7f710d9a628b55c02200541fc200a07f2eb073ad8554357777d5f1364c5a96afe5e77c6185d66a40fa7[ALL] 03ee18c598bafc5fbea72d345329803a40ebfcf34014d0e96aac4f504d54e7042d",
"hex": "47304402200a3cc08b9778e7b616340d4cf7841180321d2fa019e43f25e7f710d9a628b55c02200541fc200a07f2eb073ad8554357777d5f1364c5a96afe5e77c6185d66a40fa7012103ee18c598bafc5fbea72d345329803a40ebfcf34014d0e96aac4f504d54e7042d"
},
"sequence": 4294967294
},
{
"txid": "33173618421804343e8f6cc21316d97a24f7439137510249af39f01ee82113a7",
"vout": 0,
"scriptSig": {
"asm": "304402200dd80206b57beb5fa38a3c3578f4b0e40d56d4079116fd2a6fe28e5b8ece72310220298a8c3a1193ea805b27608ff67a2d8b01e347e33a4222edfba499bb1b64a316[ALL] 0339c001b00dd607eeafd4c117cfcf86be8efbb0ca0a33700cffc0ae0c6ee69d7e",
"hex": "47304402200dd80206b57beb5fa38a3c3578f4b0e40d56d4079116fd2a6fe28e5b8ece72310220298a8c3a1193ea805b27608ff67a2d8b01e347e33a4222edfba499bb1b64a31601210339c001b00dd607eeafd4c117cfcf86be8efbb0ca0a33700cffc0ae0c6ee69d7e"
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 0.01463400,
"n": 0,
"scriptPubKey": {
"asm": "0 d591091b8074a2375ed9985a9c4b18efecfd4165",
"hex": "0014d591091b8074a2375ed9985a9c4b18efecfd4165",
"reqSigs": 1,
"type": "witness_v0_keyhash",
"addresses": [
"tb1q6kgsjxuqwj3rwhkenpdfcjccalk06st9z0k0kh"
]
}
},
{
"value": 0.00500000,
"n": 1,
"scriptPubKey": {
"asm": "0 751e76e8199196d454941c45d1b3a323f1433bd6",
"hex": "0014751e76e8199196d454941c45d1b3a323f1433bd6",
"reqSigs": 1,
"type": "witness_v0_keyhash",
"addresses": [
"tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"
]
}
}
]
}
}
In fact, both of the vouts
use Bech32 addresses: your recipient and the automatically generated change address.
But when we backtrack our vin
, we discover that came from a legacy address. Because it doesn't matter:
$ bitcoin-cli -named gettransaction txid="33173618421804343e8f6cc21316d97a24f7439137510249af39f01ee82113a7"
{
"amount": 0.01000000,
"confirmations": 43,
"blockhash": "00000000000000e2365d2f814d1774b063d9a04356f482010cdfdd537b1a24bb",
"blockheight": 1773212,
"blockindex": 103,
"blocktime": 1592937103,
"txid": "33173618421804343e8f6cc21316d97a24f7439137510249af39f01ee82113a7",
"walletconflicts": [
],
"time": 1592936845,
"timereceived": 1592936845,
"bip125-replaceable": "no",
"details": [
{
"address": "mpVLL7iqPr4d7BJkEG54mcdm7WmrAhaW6q",
"category": "receive",
"amount": 0.01000000,
"label": "",
"vout": 0
}
],
"hex": "020000000001016a66efa334f06e2c54963e48d049a35d7a1bda44633b7464621cae302f35174a0100000017160014f17b16c6404e85165af6f123173e0705ba31ec25feffffff0240420f00000000001976a914626ab1ca41d98f597d18d1ff8151e31a40d4967288acd2125d000000000017a914d5e76abfe5362704ff6bbb000db9cdfa43cd2881870247304402203b3ba83f51c1895b5f639e9bfc40124715e2495ef2c79d4e49c0f8f70fbf2feb02203d50710abe3cf37df4d2a73680dadf3cecbe4f2b5d0b276dbe7711d0c2fa971a012102e64f83ee1c6548bcf44cb965ffdb803f30224459bd2e57a5df97cb41ba476b119b0e1b00"
}
Send a SegWit Transaction The Hard Way
You can similarly fund a transaction with a Bech32 address with no difference to the techniques you've learned so far. Here's an exactly of doing so with a complete raw transaction:
$ changeaddress=$(bitcoin-cli getrawchangeaddress)
$ echo $changeaddress
tb1q4xje3mx9xn7f8khv7p69ekfn0q72kfs8x3ay4j
$ bitcoin-cli listunspent
[
...
{
"txid": "003bfdca5578c0045a76768281f05d5e6f57774be399a76f387e2a0e99e4e452",
"vout": 0,
"address": "tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6",
"label": "",
"scriptPubKey": "0014a226e1dfd08537b02de04f667a49bd46f9b9f578",
"amount": 0.01000000,
"confirmations": 5,
"spendable": true,
"solvable": true,
"desc": "wpkh([d6043800/0'/0'/5']0327dbe2d58d9ed2dbeca28cd26e18f48aa94c127fa6fb4b60e4188f6360317640)#hd66hknp",
"safe": true
}
]
$ recipient=tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[2] | .txid')
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[2] | .vout')
$ echo $utxo_txid $utxo_vout
003bfdca5578c0045a76768281f05d5e6f57774be399a76f387e2a0e99e4e452 0
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.002, "'$changeaddress'": 0.007 }''')
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
e02568b706b21bcb56fcf9c4bb7ba63fdbdec1cf2866168c4f50bc0ad693f26c
It all works exactly the same as other sorts of transactions!
Recognize the New Descriptor
If you look at the desc
field, you'll note that the SegWit address has a different style descriptor than those encountered in §3.5: Understanding the Descriptor. A legacy descriptor described in that section looked like this: pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk
. Our new SegWit descriptor instead looks like this: wpkh([d6043800/0'/0'/5']0327dbe2d58d9ed2dbeca28cd26e18f48aa94c127fa6fb4b60e4188f6360317640)#hd66hknp"
.
The big thing to note is that function has changed. It was previously pkh
, which is a standard P2PKH hashed public-key address. The SegWit address is instead wpkh
, which means that it's a P2WPKH native SegWit address. This underlines the :fire: power of descriptors. They describe how to create an address from a key or other information, with the functions unambiguously defining how to make the address based on its type.
Summary: Creating a SegWit Transaction
There's really no complexity to creating SegWit transactions. Internally, they're structured differently from legacy transactions, but from the command line there's no difference: you just use an address with a different prefix. The only thing to watch for is that some people may not be able to send to a Bech32 address if they're using obsolete software.
:fire: What the power of sending coins with SegWit?
The Advantages. SegWit transactions are smaller, and so will be cheaper to send than legacy transactions due to lower fees. Bech32 doubles down on this advantage, and also creates addresses that are harder to foul up when transcribing — and that's pretty important, given that user error is one of the most likely ways to lose your bitcoins.
The Disadvantages. SegWit addresses may not be supported by obsolete Bitcoin software. In particular, people may not be able to send to your Bech32 address.
What's Next?
Advance through "bitcoin-cli" with Chapter Five: Controlling Bitcoin Transactions.