I tested Elements (part 1) — setup and first transactions

Louis Singer
ON-X Blockchain (Chain-Accelerator)
8 min readMar 11, 2020

The Elements project: https://blockstream.com/elements/

Elements code tutorial overview: https://elementsproject.org/elements-code-tutorial/overview.

This series of articles aims to document the Elements project, a Bitcoin sidechain with awesome new features. In the first part, we will see:

  • How to install Bitcoin and Elements.
  • Send our first transaction.

I used a Debian 10 system for that set of articles. If you used a VM make sure that your machine has at least 1.5 GB of memory and 12 GB of storage.

1. Install requirements on Debian 10

We need build tools, git, Haskell Platform and a Nix shell for the next tutorials.

⚠ The dependencies are quite heavy (a few Gigas). If you are on a VM, plan enough disk space.

su
apt-get update && apt-get upgrade
apt-get install git build-essential libtool autotools-dev autoconf pkg-config libssl-dev libboost-all-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler imagemagick librsvg2-bin libqrencode-dev autoconf openssl libssl-dev libevent-dev libminiupnpc-dev jq haskell-platform xz-utils autotools-dev automake g++ gpp pkg-config libdb++-dev libboost-all-dev libncurses-dev make
apt-get update --fix-missing
exit

Setup the project directory

Open the ~/.elementsProject using nano .

nano ~/.elementsProject

Put the following lines inside your ~/.elementsProject.

# add lines in with your configuration
export PROJECT_USER=$USER
export PROJECT_DIR="/opt/project"
export DB4_INSTALL_PATH="/opt"
export BDB_PREFIX="/opt/db4"
export PROJECT_ELEMENTS_DIR="$PROJECT_DIR/elements"
export PROJECT_BITCOIN_DIR="$PROJECT_DIR/bitcoin"
export PROJECT_SIMPLICITY_DIR="$PROJECT_DIR/simplicity"
export PROJECT_HAL_DIR="$PROJECT_DIR/hal"

Load it:

$ source ~/.elementsProject
# su
# source ~/.elementsProject
# exit

Install Berkeley DB

Elements and Bitcoin require Berkeley DB 4.8. As this dependency is not available on official repositories, Elements provides a script to install it.

$ cd $PROJECT_DIR
$ git clone https://github.com/ElementsProject/elements.git
$ cd $PROJECT_ELEMENTS_DIR
# su
# cd $PROJECT_ELEMENTS_DIR
# ./contrib/install_db4.sh $DB4_INSTALL_PATH
# exit

Install the Bitcoin’s Simplicity branch

$ cd $PROJECT_DIR
$ git clone https://github.com/roconnor-blockstream/bitcoin.git

Then, move into the newly created bitcoin folder and switch to the branch simplicity. The Berkeley prefix may change depending where do you install bd4.

$ cd $PROJECT_BITCOIN_DIR
$ git checkout simplicity
$ ./autogen.sh
S ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" --disable-dependency-tracking --with-gui=no --disable-test --disable-bench
$ su
# make
# exit

The binaries are inside the src folder. We can directly launch a regtest node:

$ cd $PROJECT_BITCOIN_DIR
$ alias btc="$PROJECT_BITCOIN_DIR/src/./bitcoin-cli -regtest"
$ alias btcd="$PROJECT_BITCOIN_DIR/src/./bitcoind -regtest"
$ btcd -daemon
Bitcoin Core starting

Install the Simplicity library

$ cd $PROJECT_DIR
$ git clone https://github.com/ElementsProject/simplicity.git

We also need the bech32-1.0.2 Haskell library, there also some dependencies. Use the cabal package manager to install it:

$ cabal update
$ cabal install bech32-1.0.2
$ cabal install unification-fd cereal lens-family-2.0.0 SHA MemoTrie

Move inside the simplicity directory to move on the commit used by Russel’O’Connor for the first transaction. We’ll use this version.

$ cd $PROJECT_SIMPLICITY_DIR
$ git checkout 2867955c0c93418f45ffe8ea0a7b1277b785fdc4

Install HAL

HAL is a rust utility and uses Cargo to be installed. If you do not have Rust and Cargo installed on your computer, run the following command, and follow the installation instructions:

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env

Create a new folder for Hal run the commands to install HAL :.

$ mkdir $PROJECT_HAL_DIR && cd $PROJECT_HAL_DIR
$ wget https://github.com/stevenroose/hal/releases/download/v0.6.1/hal-0.6.1-vendored.tar.gz
$ tar xzf hal-0.6.1-vendored.tar.gz
$ cargo install hal

Install Nix and create a Nix Environment

We’ll also use a nix-shell for our working environments. Install Nix on a Debian based system is very simple. Open a terminal and just launch the official installation script:

$ su
# mkdir -m 0755 /nix && chown $PROJECT_USER /nix
# exit
$ curl https://nixos.org/nix/install | sh
$ . /home/$PROJECT_USER/.nix-profile/etc/profile.d/nix.sh

Create a Nix environment inside the simplicity cloned repository launch the following nix-shell command.

$ cd $PROJECT_SIMPLICITY_DIR 
$ nix-shell -p "(import ./default.nix {}).haskellPackages.ghcWithPackages (pkgs: with pkgs; [Simplicity bech32])"
[nix-shell:/opt/project]$ exit
$ alias simplicityenv="cd $PROJECT_SIMPLICITY_DIR && nix-shell -p \"(import ./default.nix {}).haskellPackages.ghcWithPackages (pkgs: with pkgs; [Simplicity bech32])\""

It will create our working environment. We use the default.nix configuration file and we have imported our two Haskell packages: Simplicity and bech32 .

At this stage, you’re inside a nix environment in the simplicity folder.

Install Elements

Build Elements instructions: https://github.com/ElementsProject/elements/blob/master/doc/build-unix.md

We cloned https://github.com/ElementsProject/elements.git. Finally, we can build and install Elements with the following commands (still in the elements folder and with superuser rights).

⚠ The make command may take a lot of time (and use a lot of memory).

$ cd $PROJECT_ELEMENTS_DIR
$ ./autogen.sh
S ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" --disable-dependency-tracking --with-gui=no --disable-test --disable-bench
$ su
# make
# make install
# exit

Verify the install:

which elementsd
> /usr/local/bin/elementsd

Save your shortcuts

Add the following lines inside your ~/.elementsProject.

# add alias
alias btc="$PROJECT_BITCOIN_DIR/src/./bitcoin-cli -regtest"
alias btcd="$PROJECT_BITCOIN_DIR/src/./bitcoind -regtest"
alias simplicityenv="cd $PROJECT_SIMPLICITY_DIR && nix-shell -p \"(import ./default.nix {}).haskellPackages.ghcWithPackages (pkgs: with pkgs; [Simplicity bech32])\""

Load it:

$ source ~/.elementsProject
# su
# source ~/.elementsProject
# exit

Save your personas

Add the following lines inside your ~/.elementsProject.

# add personas
export USER_BITCOIN_DIR="$HOME/bitcoindir"
export USER_ALICE_DIR="$HOME/alice"
export USER_BOB_DIR="$HOME/bob"

Load it:

$ source ~/.elementsProject
# su
# source ~/.elementsProject
# exit

Create personas:

# Move inside tutorial assets folder
cd $PROJECT_ELMENTS_DIR/contrib/assets_tutorial
# Copy configuration files$ mkdir $USER_BITCOIN_DIR
$ cp ./bitcoin.conf $BITCOIN_DIR/bitcoin.conf
$ mkdir $USER_ALICE_DIR
$ cp ./elements1.conf $USER_ALICE_DIR/elements.conf
$ mkdir $USER_BOB_DIR
$ cp ./elements2.conf $USER_BOB_DIR/elements.conf

Add the following lines inside your ~/.elementsProject.

# add alias
alias b-dae="btcd -datadir=$BITCOIN_DIR"
alias b-cli="btc -datadir=$BITCOIN_DIR"
alias alice-dae="elementsd -datadir=$USER_ALICE_DIR"
alias alice-cli="elements-cli -datadir=$USER_ALICE_DIR"
alias bob-dae="elementsd -datadir=$USER_BOB_DIR"
alias bob-cli="elements-cli -datadir=$USER_BOB_DIR"

We need to generate addresses. To achieve that, we will use the getnewaddress command. Let’s generate three addresses:

  • ALICE_MINER_ADDRESS : the address that will receive the fees collected when creating a new block.
  • ALICE_RECEIVER_ADDRESS : an address attached to node 1.
  • BOB_RECEIVER_ADDRESS : an address attached to node 2.

Each node controls a wallet. A wallet has several bitcoin addresses. When we use getnewaddress with alice-cli , we’ll get an address attached to the first node wallet. If we use the command with bob-cli , the address will be attached to the second node.

Add the following lines inside your ~/.elementsProject.

# add alias
alias b-dae="btcd -datadir=$BITCOIN_DIR"
alias b-cli="btc -datadir=$BITCOIN_DIR"
alias alice-dae="elementsd -datadir=$USER_ALICE_DIR"
alias alice-cli="elements-cli -datadir=$USER_ALICE_DIR"
alias bob-dae="elementsd -datadir=$USER_BOB_DIR"
alias bob-cli="elements-cli -datadir=$USER_BOB_DIR"

Start your environnement

Create and add the following lines inside your ~/elementsEnv.sh.

# add alias
source ~/.elementsProject
b-dae
alice-dae
bob-dae

Now you can start daemons and save your personas addresses:

$ cd $HOME
$ chmod +x elementsEnv.sh
$ ./elementsEnv.sh
# miners addresses
$ ALICE_MINER_ADDRESS=$(alice-cli getnewaddress)
$ echo "ALICE_MINER_ADDRESS=$ALICE_MINER_ADDRESS" >> ~/.elementsProject
# receivers addresses
$ ALICE_RECEIVER_ADDRESS=$(alice-cli getnewaddress)
$ echo "ALICE_RECEIVER_ADDRESS=$ALICE_RECEIVER_ADDRESS" >> ~/.elementsProject
$ BOB_RECEIVER_ADDRESS=$(bob-cli getnewaddress)
$ echo "BOB_RECEIVER_ADDRESS=$BOB_RECEIVER_ADDRESS" >> ~/elementsProject

Final files:

https://github.com/crypto-hackathons/ElementsInstall/tree/master

2. Send our first transaction

First, let’s see the wallet information of our two Elements nodes. To achieve that we’ll use getwalletinfo .

alice-cli getwalletinfo
bob-cli getwalletinfo

This is what you get for the wallet alice:

{
"walletname": "",
"walletversion": 169900,
"balance": {
"bitcoin": 21000000.00000000
},
"unconfirmed_balance": {
"bitcoin": 0.00000000
},
"immature_balance": {
"bitcoin": 0.00000000
},
"txcount": 1,
"keypoololdest": 1583423600,
"keypoolsize": 1000,
"keypoolsize_hd_internal": 1000,
"paytxfee": 0.00000000,
"hdseedid": "6cf040791881800d03b9f940be96a6e93526f054",
"private_keys_enabled": true
}

You can see there’s 21000000 BTC on this wallet. This is a value initialized in the configuration files for testing purposes. And the second wallet (node e2) has the same balance. This value is initialized in the elements.conf files. It represents the coinbase, the initial amount of Bitcoins, that “anyone-can-spend”. Our first transaction consists to transfer half of these funds to a generated address.

Elements networks, like Bitcoin networks, require funds to have a maturity of at least 100 blocks to be spendable. 100 blocks are for consensus but the node won't broadcast early in fear of being banned so it waits until 102. We will send our 21 million BITCOIN to a first address. Then we will make them available by generating 102 blocks (100 for the consensus + 2 for security).

We will divide the “anyone-can-spend” bitcoins between the two nodes. So We’re going to execute two transactions:

  • First transfer all the coinbase (21 million BTC) to the ALICE_RECEIVER_ADDRESS.
  • Then transfer the half of the amount (10,5 million BTC) to the BOB_RECEIVER_ADDRESS.

Send the coinbase to the RECEIVER1

Let’s use the sendtoaddress command.

alice-cli sendtoaddress $ALICE_RECEIVER_ADDRESS 21000000 "" "" true

Note that I use alice-cli to transfer the 21 million bitcoins. However, I could have done the same thing with bob-cli because anyone can spend the coinbase.

This command creates a transaction. Here our transaction said: send 21000000 BTC to the $ALICE_RECEIVER_ADDRESS address. See the whole command’s reference here: https://chainquery.com/bitcoin-cli/sendtoaddress.

If all goes well, the command returns the ID of the transaction created. This is my transaction ID:

9a3ffa4926f9abde8e5ca62feabad72f4b5316698005cbf2bb5685b2b0e24756

Then let’s generate 102 new blocks. Thus our bitcoins will become spendable.

alice-cli generatetoaddress 102 $ALICE_MINER_ADDRESS

The command generatetoaddress generates 102 blocks and sends the rewards to the $MINER . The references of the command can be found here: https://chainquery.com/bitcoin-cli/generatetoaddress

generatetoaddress returns an array of block hashes (the newly created ones). You probably get something like this:

# An array of 102 hashes["492adc2be3b6798ebe57fef0f01e98264ee29e539b8967fbd6b0d3ef2715babe",
"49ea2519716df48cdb0522c286dac4aa4fe04392699450bd9c602ffa88769a1f",
...
...
...
...
...
"68bb08b1c0db463c39a13c6d3543c1c7e715bfc6340ff8954337cf8d13a6e3cd",
"59c8396f1f8b52825c776b6f42b5d3ed5ef90cad11cf2a2258aff28bfa6f9088"]

Wejust generated 102 blocks. We can see with the command alice-cli listtransactions that a new transaction has appeared of the category “generate”:

{
"address": "XKHEwgFnqUXjNCmZeCYfTdhU8U7kuJZ2Bt",
"category": "generate",
"amount": 0.00003260,
"amountblinder": "0000000000000000000000000000000000000000000000000000000000000000",
"asset": "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23",
"assetblinder": "0000000000000000000000000000000000000000000000000000000000000000",
"label": "",
"vout": 0,
"confirmations": 102,
"generated": true,
"blockhash": "492adc2be3b6798ebe57fef0f01e98264ee29e539b8967fbd6b0d3ef2715babe",
"blockindex": 0,
"blocktime": 1583919304,
"txid": "c930d567ff88c8bc7412252498b0838421ab0ae7f5a44b0c463230c21038549d",
"walletconflicts": [],
"time": 1583919304,
"timereceived": 1583919304,
"bip125-replaceable": "no"
}

Now we are able to send half of the amount to a second address: BOB_RECEIVER_ADDRESS.

Send 10,5 millions of BTC from node 1 (ALICE_RECEIVER_ADDRESS) to node 2 (BOB_RECEIVER_ADDRESS)

alice-cli sendtoaddress $BOB_RECEIVER_ADDRESS 10500000 "" "" false

Again, you get the ID of the transaction created, which can be found with the command alice-cli listtransactions.

Then, let’s generate the blocks to complete the transaction.

alice-cli generatetoaddress 102 $ALICE_MINER_ADDRESS

Check wallets balance

To verify if everything has worked correctly, let’s use getwalletinfo .

alice-cli getwalletinfo
bob-cli getwalletinfo

You can see that each wallet balance has now 10,5 bitcoins.

{
"walletname": "",
"walletversion": 169900,
"balance": {
"bitcoin": 10500000
}
,
"unconfirmed_balance": {
"bitcoin": 0
},
"immature_balance": {
"bitcoin": 0
},
"txcount": 5,
"keypoololdest": 1583925379,
"keypoolsize": 1000,
"keypoolsize_hd_internal": 999,
"paytxfee": 0,
"hdseedid": "8192d0025e30d13792e014ed71e815594bedb961",
"private_keys_enabled": true
}

Congratulations! Your nodes are working properly!

This is the end of this tutorial, don’t forget to stop the daemons with :

b-cli stop
alice-cli stop
bob-cli stop

3. Bonus & Tips

A small bonus section that references some handy tips and commands.

Find docs and references

Get the general information about the blockchain to which your node is connected with getblockchaininfo

alice-cli getblockchaininfo

Directly get the wallet balance with getbalance

# get the node 1 balance
alice-cli getbalance

Get the distribution of the wallet’s bitcoins on the different addresses with listaddressgroupings

# get addresses of node 1 wallet
alice-cli listaddressgroupings

Working with JSON using jq

Clients often return JSON as results. jq is a CLI tool letting to handle JSON. Using as Bash pipe, it can be useful for handling results from Elements CLI commands.

# select txcount from getwalletinfo JSON result
alice-cli getwalletinfo | jq '.txcount'

--

--