Author: Matt Henderson @dafacto

This document details migrating from a public/private Spacemesh node setup to a single node managing four postdata sets, using the new “1:n” feature of go-spacemesh version 1.4, on a 2023 Mac mini.


Spacemesh wizard @Earl in Discord recommends backing up the following before migrating from version 1.3 to 1.4:

Overview of the process

Here’s an outline of the process, followed by the contents of my specific configuration files. (The Spacemesh documentation for all the below can be found here, though I found it a bit difficult to follow, as it’s more generic in nature.)

  1. Quit any running go-spacemesh nodes.
  2. Download and install the latest 1.4+ release binaries. Note that the release includes both the go-spacemesh binary that runs your node, and the post service binary that manages your postdata.
  3. Add grpc-post-listener on port 9094 in your startup scripts, modifying the port of any other listeners that conflict with that port. This allows go-spacemesh to communicate with post service processes, each of which does the proving for a particular postdata set.
  4. Modify your poet-server configurations to include “pubkeys”. (See examples below.)
  5. Remove any direct private peers from your public node configuration, if you’re migrating from a private/public node setup like me.
  6. Configure your public node configuration to not smesh! (See examples below.)
  7. Configure each private node to use your public node configuration. (This in preparation for the next step.)
  8. Start every node you have, running 1.4, and let it sync. This will:
    1. Migrate the node to 1.4, creating some new files, new databases and run some migrations on others. It’s important that each node has been migrated to 1.4 before running the merge tool discussed in a later step.
    2. It will also backup your key.bin file in your postdata folder to key.bin.bak, move and rename the original to local.key in a new identities folder in your node’s node-data folder.
  9. Shutdown each node, find all those local.key files in those identities folders, and rename them to something corresponding to your particular nodes. In my case, I ended up with node1.key, node2.key, node3.key and node4.key. Important!if you leave your main node key named local.key the migration will not work!
  10. Use the new merge-nodes utility delivered with go-spacemesh to merge all your nodes into one, e.g. Here I’m merging node2 into node1: ./merge-node --from ~/Spacemesh/node2/node-data --to ~/Spacemesh/node1/node-data. This will move/consolidate all those node.key files into the identities directory of your future single node. (I used node1 as my eventual master, single node.)
  11. Modify your node startup script to remove all smeshing parameters, since the node itself will no longer be smeshing, but rather the multiple service processes you’ll run. (See below.)
  12. Create multiple startup scripts to start a separate services process for each postdata set you have. (See example below.)
  13. After confirming you’ve made all the right configuration changes, you can start go-spacemesh on a single node, and then start your four service processes.

At this point you’re finished! You have one node running, communicating with multiple service processes, smeshing multiple postdata sets!

Let’s now look at my specific configurations, so you can see some real-world examples.

Configuration files

This is the script that I run to start my node. You’ll see that instead of leaving it named node1, I simply renamed it node.


/Users/mhenders/Spacemesh/app/go-spacemesh \
--config /Users/mhenders/Spacemesh/node/config/config.json \
--listen /ip4/ \
-d /Users/mhenders/Spacemesh/node/node-data \
--filelock /Users/mhenders/Spacemesh/node/lock/spacemesh.lock \
--grpc-public-listener \
--grpc-private-listener \
--grpc-post-listener \

go-spacemesh config.json

  "main": {
    "layer-duration": "5m",
    "layers-per-epoch": 4032,
    "poet-servers": [
        "address": "",
        "pubkey": "AHlrgUZq5dFqK2oa2C9qVq4qIE2beJ/mG7sryynfqx0="
        "address": "",
        "pubkey": "8SatjpHxbrfeIKTFSAFcZklxPnhUElloRvAUAy1xOxo="
        "address": "",
        "pubkey": "givyUYkXx4kVe7gOngNEeIA4YrNBPojB7lAH1RLA62c="
        "address": "",
        "pubkey": "C7/aEeZ716W17Z/Gz1GHtCVEcK8IN2JXrhVyIF43aEA="
    "logging": {
        "p2p": "error"
    "poet": {
        "phase-shift": "288h",
        "cycle-gap": "24h",
        "grace-period": "2h"
    "p2p": {
        "min-peers": 30,
        "low-peers": 60,
        "high-peers": 100,
        "bootnodes": [
        "direct": []
    "smeshing": {
        "smeshing-start": false,
    "post": {
        "post-k3": 1

Here’s one of the four scripts, that start four post services, one for each postdata set I have.


/Users/mhenders/Spacemesh/app/service \
--threads 0 \
--address=http://localhost:9094 \
--dir /Volumes/smesh1/postdata \
--nonces 288 \


On the Mac, you need to create a LaunchAgent, which goes in ~/Library/LaunchAgents/, to control your post services, just like you should have one to control the launch of go-spacemesh. This will launch them all on machine startup, and relaunch them if they ever crash. This is similar to systemd on Linux machines.

You pretty much need to use the LaunchControl app for Mac, to load and run your launch agents, making the process much easier than manually managing them.

I have four service launch agents, one for each script.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">


I use the Mac app Keyboard Maestro to monitor my setup once per hour. Here’s what that looks like, collapsing the macro contents into the highest level groups:

This Keyboard Maestro macro writes all monitoring data to a file that I can inspect at any time, and is configured to email me if anything is wrong.


Here’s what my directory system looks like, after finishing this migration.

Thanks to @nj, @fastmat, @flare, @hakehardware, @earl and others for helping me get all this figured out!

If you have any questions, I’m @dafacto in Discord, or ping me on Twitter.