Shoestring Local Build

December 30, 2023

Symbol Shoestring is the successor to Symbol Bootstrap. It is strongly recommended to use Shoestring for all new node deployments. Bootstrap is no longer supported and might stop working in the future.

Shoestring makes it very simple to deploy a testnet or mainnet node. Less documented is how to use it with a locally built Catapult client. In this guide, we'll use Shoestring to run Catapult built from sources that connects to testnet. This is very convenient for development.

This guide assumes that you have already built Catapult on your local machine following the build instructions.

Step 1 - Prepare CA Key

Every node requires a main (or CA) private key, which is used to sign its root certificate and identify the node. This identity is required to be unique across the network. The balance associated with this main account affects the likelihood of a node being selected as a peer and its weighting in certain operations, like time synchronization. The intuition is that nodes with larger balances are more likely to be trustworthy because they have more invested in the network.

Nevertheless, there is no balance requirement for a node. The only difference between a low balance node and a high balance node is the likelihood of selection for certain operations. Otherwise, they behave exactly the same. In fact, this difference is wholly external to them.

Shoestring expects the CA private key to be present in a PEM file. Let's create a setup directory and prepare a CA private key.

mkdir setup && cd setup

We can easily generate a new (random) CA private key using openssl:

openssl genpkey -algorithm ed25519 -outform PEM -out ca.key.pem

Alternatively, we can use Shoestring to generate one from an existing private key and optionally password protect it (using --ask-pass):

python3 -m shoestring pemtool --ask-pass --output ca.key

In either case, you can inspect the contents of the resulting ca.key.pem file by using openssl:

openssl pkey -in ca.key.pem -text -noout

This will print out both the private key and public key to the console. If you only want to see the public key, replace -text with -text_pub.

Step 2 - Prepare Shoestring Configuration

We need to run the Shoestring init command to download a configuration template for the network we want. Since we will be connecting to the testnet (codenamed sai), we need to specify that as the package name:

python3 -m shoestring init --package sai sai.ini

Since our ultimate goal is to run our locally built Catapult, many of the settings irrelevant. The only settings we need to modify are the ones in the node section:

  • features - Features supported by the local node
    • PEER is minimal node for synchronizing
    • API adds broker process and REST
    • HARVESTER configures node to harvest
    • VOTER configures node to vote
  • apiHttps - For local development, set this to false
  • caCommonName - Enter CA certificate name (can be anything you want)
  • nodeCommonName - Enter Node certificate name (can be anything you want)

We also need to add an overrides file to indicate the local host will be used. Create a local-overrides.ini file and enter the following:

[node.localnode]

host = 127.0.0.1

Step 3 - Run Shoestring Setup

Finally, we can run Shoestring setup!

python3 -m shoestring setup \
    --package sai \
    --directory ./output \
    --ca-key-path ./setup/ca.key.pem \
    --config ./setup/sai.ini \
    --overrides ./setup/local-overrides.ini

Importantly, --package is set to sai, which is the testnet to which we want to connect. All Shoestring output will be created under --directory.

⚠️ The directory specified via --directory must exist and must be empty! Generally, it's recommended to fully purge that directory before each run, like this:

rm -rf output && mkdir output

Finally, we're specifying paths to the CA private key (--ca-key-path) as well as the configuration files (--config and --overrides) we created earlier.

ℹ️ If you are using a password protected CA file, Shoestring will prompt for the password multiple times. This is normal, albeit a little annoying.

Step 4 - Update Catapult User Configuration

In order to use a locally built node, we need to adjust the paths in output/userconfig/resources/config-user.properties.

ℹ️ Shoestring makes everything in resources read-only. This is normally fine for deployments - everything should be properly configured via Shoestring - and prevents accidental overwrites. During development, it's fine to make some of these writable. In fact, we need to make config-user.properties writable!

Let's make the following changes:

seedDirectory = /path/to/output/seed
certificateDirectory = /path/to/output/keys/cert
dataDirectory = /path/to/output/data
pluginsDirectory = ..
votingKeysDirectory = /path/to/output/keys/voting

ℹ️ /path/to/output/ should be the full path to the output directory created earlier. While relative paths may work in certain situations, it's generally recommended to use full paths for these settings.

Alternatively, you could set these in your overrides file (local-overrides.ini) under the section user.storage. If you're routinely resetting your node, this makes the configuration much easier.

Step 5 - Running

Now, let's see if we can run our catapult.server process! 🍀

Go back to the client/catapult/_build directory, and run the following command:

./bin/catapult.server /path/to/output/userconfig

Watch the output for a log like this:

 <important> (extensions::NemesisBlockLoader.cpp@54)
      nemesis network id: Testnet
      nemesis public key: 76E94661562762111FF7E592B00398554973396D8A4B922F3E3D139892F7C35C
 nemesis generation hash: 96FAA65899ED0EF309D17D7456C052BB2D7618B239C03BEDDCCBDEC6D82CBC0F

This log indicates that your node has successfully booted. It should start talking with peers and syncing imminently.

As a quick check, you should notice the little endian number stored in data/index.dat increasing:

hexdump -C data/index.dat

This is the locally confirmed block height. As long as it's not one, everything is working! Congratulations! 🎉