Operators guide
Currently, the domain chain does not support syncing from other operator nodes; it needs to be deterministically derived from the consensus chain block by block.
Check the list of the available domains:
In order to participate in block production, operator needs to register on a specific domain.
Any account with the minimum operator stake can become an operator.
To check the list of available domains:
- Proceed to PolkadotJS
- Make sure to select the correct network at the top-left corner.
- Go to Developer -> Chain state
- Select
domains
underselected state query
and choosedomainRegistry
- Exclude
option
- Click on
+
to query the chain state. - Review the list of available domains
تلميح
In the example above the number 3 corresponds to the domainId. The example is not Stake Wars specific, the operator is responsible for finding out the correct domain ID they want to operate on. Stake Wars are using the domain with ID 1.
Create operator key (recommended way)
An operator needs a key pair to participate in bundle production.
- curl
- UI (using Docker)
- Start a node on a developer chain by running
./target/release/subspace-node --chain dev -- --domain-id 0 --keystore-path tmp/keystore --rpc-cors all
You can use any chain to generate a keypair, we recommend using a dev
chain for simplicity.
You can adjust the --keystore-path
if you prefer to generate the keys in a different location.
- Open another terminal and use the
curl
command to make an RPC call to your node. This will generate a new key in the--keystore-path
location you specified earlier.
- 🖼️ Windows
- 🍎 macOS
- 🐧 Ubuntu
curl.exe -X POST http://127.0.0.1:9945 `
-H "Content-Type: application/json;charset=utf-8" `
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"author_rotateKeys",
"params": []
}'
curl -X POST http://127.0.0.1:9945 \
-H "Content-Type: application/json;charset=utf-8" \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"author_rotateKeys",
"params": []
}'
curl -X POST http://127.0.0.1:9945 \
-H "Content-Type: application/json;charset=utf-8" \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"author_rotateKeys",
"params": []
}'
- Make sure to have Docker installed.
You can run
docker -v
in the terminal of your choice to make sure it's installed. - Start a developer node by running
./target/release/subspace-node --chain dev -- --domain-id 0 --keystore-path tmp/keystore --rpc-cors all
You can use any chain to generate a keypair, we recommend using a dev
chain for simplicity.
You can adjust the --keystore-path
if you prefer to generate the keys in a different location.
- Start a local polkadot interface portal by running a docker contrainer.
docker run --rm -it --name polkadot-ui -e WS_URL=ws://0.0.0.0:9945 -p 80:80 jacogr/polkadot-js-apps:latest
- Proceed to the browswer and type
localhost
in the search bar. You should be taken to the polkadot portal.
Navigate to
developer
->rpc calls
Select
author
incall the selected endpoint
and pick arotateKeys()
in the dropdown.
Press on
Submit RPC call
.You will see a newly generated key on the screen. The key will also be written in a
keystore
location you specified earlier.
You will use this key in order to register an operator later.
You have successfully generated an operator key, congratulations!
Start the domain operator node
The domain operator node is running with an embedded consensus node, thus you need to specify the args for both the consensus node and the domain operator node:
subspace-node [consensus-chain-args] -- [domain-args]
Example:
Start a node as operator on gemini-3g
chain:
You need to wipe (purge-chain
) and sync your node from genesis block, since you need to sync both consensus and domain chains.
You do not need to wipe any existing plots.
Ensure you replace your_domain_id
with your domain identifier in the command and your_operator_id
with your operator_id. If your keystore is located in a different folder, adjust the --keystore-path
accordingly. Setting --base-path
is optional.
You can ignore setting up your_operator_id
while you're syncing your node. Make sure to set it after syncing and registration.
Stake Wars are using the domain Nova with ID 1.
- 🖼️ Windows
- 🍎 macOS
- 🐧 Ubuntu
- 🐋 Docker
target/production/subspace-node `
--chain gemini-3g `
--name your_node_name `
--base-path your_path_to_node_data `
-- `
--domain-id your_domain_id `
--chain gemini-3g `
--operator-id your_operator_id `
--bootnodes /ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp `
--bootnodes /ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1 `
--bootnodes /ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7 `
--listen-addr /ip4/0.0.0.0/tcp/40333 `
--keystore-path /keystore
target/production/subspace-node \
--chain gemini-3g \
--name your_node_name \
--base-path your_path_to_node_data \
-- \
--domain-id your_domain_id \
--chain gemini-3g \
--operator-id your_operator_id \
--bootnodes /ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp \
--bootnodes /ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1 \
--bootnodes /ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7 \
--listen-addr /ip4/0.0.0.0/tcp/40333 \
--keystore-path /keystore
target/production/subspace-node \
--chain gemini-3g \
--name your_node_name \
--base-path your_path_to_node_data \
-- \
--domain-id your_domain_id \
--chain gemini-3g \
--operator-id your_operator_id \
--bootnodes /ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp \
--bootnodes /ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1 \
--bootnodes /ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7 \
--listen-addr /ip4/0.0.0.0/tcp/40333 \
--keystore-path /keystore
version: "3.7"
services:
node:
# Replace snapshot-DATE with the latest release (like snapshot-2022-apr-29)
# For running on Aarch64 add -aarch64 after DATE
image: ghcr.io/subspace/node:snapshot-DATE
volumes:
# Replace path/to/keystore with your actual path to keystore.
- /path/to/keystore:/keystore:ro
# Instead of specifying volume (which will store data in /var/lib/docker), you can
# alternatively specify path to the directory where files will be stored, just make
# sure everyone is allowed to write there
- node-data:/var/subspace:rw
# - /path/to/subspace-node:/var/subspace:rw
ports:
# If port 30333 or 30433 is already occupied by another Substrate-based node, replace all
# occurrences of 30333 or 30433 in this file with another value
- "0.0.0.0:30333:30333/udp"
- "0.0.0.0:30333:30333/tcp"
- "0.0.0.0:30433:30433/udp"
- "0.0.0.0:30433:30433/tcp"
- "0.0.0.0:40333:40333/udp"
- "0.0.0.0:40333:40333/tcp"
restart: unless-stopped
command: [
"--chain", "gemini-3g",
"--base-path", "/var/subspace",
"--port", "30333",
"--dsn-listen-on", "/ip4/0.0.0.0/udp/30433/quic-v1",
"--dsn-listen-on", "/ip4/0.0.0.0/tcp/30433",
# Replace INSERT_YOUR_ID with your node ID (will be shown in telemetry)
"--name", "INSERT_YOUR_ID",
"--",
# Replace INSERT_YOUR_DOMAIN_ID with domain ID you want to be operator on
"--domain-id", "INSERT_YOUR_DOMAIN_ID",
# Replace INSERT_YOUR_OPERATOR_ID with your operator ID
"--operator-id", "INSERT_YOUR_OPERATOR_ID",
"--listen-addr", "/ip4/0.0.0.0/tcp/40333",
"--bootnodes", "/ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp",
"--bootnodes", "/ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1",
"--bootnodes", "/ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7",
"--keystore-path", "/keystore"
]
healthcheck:
timeout: 5s
# If node setup takes longer than expected, you want to increase interval and retries number.
interval: 30s
retries: 60
volumes:
node-data:
You should see the node start successfully and begin syncing.
To view the stored node information navigate to:
- 🖼️ Windows
- 🍎 macOS
- 🐧 Ubuntu
C:\Users\Alice\AppData\Local
/Users/Alice/Library/Application Support
$HOME/.local/share
Register an operator on domain
It's crucial to fully sync your node before registering as an operator. Please follow the commands in the Start the domain operator node section and only register as an operator once your node is fully synced. If many operators are registered but their nodes are still syncing or offline, it can adversely affect the speed of block production in the domain.
Prefer a video? Expand for our installation video using PolkadotJS interface.
Register an operator using Subspace Staking interface (recommended)
- Proceed to the Subspace Staking portal and connect your wallet.
- Select the wallet you would like to connect. Both Subwallet and PolkadotJS wallets are supported.
- Enter your password to give an access to your wallet.
- Select the account you'd like to use form the dropdown menu. You will see both available and locked (staked) token balances for each account.
5. Proceed to the
Stake as a pool operator
tab.
6. Select the
domainId
you would like to be registered on. Enter the Minimum Operator Stake
, Amount to Stake
, Nomination Tax
and Signing key
and then click Next
.
Make sure to use the signing key generated on the previous Create operator key step.
- Approve the request in the pop-up window.
8. Congratulations, you're now registered as an operator!
It can take up to 10 minutes for the operator to be registered and appear on the page. You can check if the operator was created successfully by following the steps.
You can view some additional actions by clicking on action
next to your operator.
You can increase your stake, withdraw some stake and de-register your operator from there.
Register an operator using PolkadotJS interface
Alternatively, you can use PolkadotJS to register an operator on the domain. To register an operator on the domain:
- Proceed to PolkadotJS
- Make sure to select the correct network at the top-left corner.
- Navigate to Developer -> Extrinsics.
- Select the account you want to use in
using the selected account
. - Select
domains
undersubmit the following extrinsic
and chooseregisterOperator(domainID, amount, config)
in the dropdown. - Enter the
domainId
to be registered on. - Enter the desired staking amount in the
amount
field. - Put your public signing key at the
signingKey
field.
In the example below, 1 TSSC is selected for staking. 18 zeros are added because of the u128
type, so make sure to put 1000000000000000000 instead.
Make sure to use the signing key generated on the previous Create operator key step
- Enter
minimumNominatorStake
- in the example, it's set to1 TSSC
. - Enter
nominatorTax
- in the example, it's set to5%
. - Sign and submit the transaction to register an operator.
Make sure to select Submit Transaction since the transaction needs to be signed.
Once registered, the operator has to wait until the domain epoch is complete to start operating for the domain, participate in bundle production, and receive rewards.
Once the domain epoch is finished, the operator can produce bundles from the new epoch.
Any operator can add more stake by using the same functionality.
Checking your operatorId
There are two ways to check your operatorId:
- You can use PolkadotJS Network Explorer.
2. Browse the recent events and you should see domains.OperatorRegistered event.
3. Click on the dropdown arrow to view the domainId and operatorId.
Alternatively, you can use Subscan which is a little easier to navigate for this job.
- Navigate to Subspace Subscan portal.
- Click on
Blockchain
->Extrinsics
.
- Scroll to the bottom of the page to view all recent events, search for
register_operator
event.
Click on
Extrinsic ID
for the desired event.Scroll to
Parameters
and ensure thatsigning_key
corresponds to your signing key.
- Scroll to
Events
and click on dropdown arrow fordomains(OperatorRegistered)
.
- Inspect and remember your
domain_id
.
Embedded Docs
The following command can be used to explore all parameters and subcommands:
target/production/subspace-node --help
Build from source
If you prefer to build from the source rather using existing builds, the domain operator node is embedded within the subspace-node
binary, please refer to Subspace node for how to build from source.
Operator deregistration
To deregister an operator on the domain and have your tokens released:
Only account who registered an operator can deregister it. Make sure to use the same wallet / account to sign the transaction for deregistration.
Operator deregistration using Subspace Staking interface (recommended)
- Proceed to the Subspace Staking portal and connect your wallet.
- Select the wallet you would like to connect. Make sure to select the wallet you registered your operator with. Both Subwallet and PolkadotJS wallets are supported.
- Enter your password to give an access to your wallet.
- Click on
Manage your stake
.
- Click on
Action
button next to an operator you would like to deregister and selectderegister
.
- Approve the request in the pop-up window.
- Congratulations, your operator was deregistered.
It can take up to 10 minutes for the operator to be deregistered and disappeared from the page. You can check if the operator was deregistered successfully on the Subspace Subscan portal.
Operator deregistration using PolkadotJS
Alternatively, you can use the PolkadotJS portal to deregister operator.
- Proceed to PolkadotJS
- Make sure to select the correct network at the top-left corner.
- Select the account you want to use in
using the selected account
. - Select
domains
undersubmit the following extrinsic
and choosederegisterOperator(operatorId)
in the dropdown.
- Your tokens and tokens of operator
Nominators
will be released after thelockingPeriod
. - To check the locking period you can go to
Developer
->Chain state
->Constants
. - Select
domains
underselected contant query
and choosestakeWithdrawalLockingPeriod
. - Click on
+
to run the query.
Number 256 above corresponds to the number of the domain blocks, and not the consensus chain blocks.
Operator Stake Withdrawal
Operator stake withdrawal works similarly to Nominator stake withdrawal. Refer to this section to withdraw your stake.
Create operator key (alternative, less secure way):
An operator needs a key pair to participate in bundle production. You can create a key using the following command:
target/production/subspace-node key generate --scheme sr25519
Back up the key. Take the public key (hex)
of the Keypair. The public key is part of the operator config we will be using later on Staking portal or PolkadotJS portal.
Insert key to Keystore:
The key generated above needs to be added to the Keystore so that the operator node can use it to participate in bundle production.
To insert the key, use the following command:
target/production/subspace-node key insert \
--suri "<Secret phrase>" --key-type oper --scheme sr25519 --keystore-path /keystore
The command above assumes /keystore
as the keystore location.
suri
is the secret phrase of the operator key.
tmp
folder on linux based systems will be emptied upon the system reboot. Make sure to store the keypair in a secure and permanent location.
Switch domains
Any Operator can switch domain they operate on anytime. In order to switch domain:
- Proceed to PolkadotJS
- Make sure to select the correct network at the top-left corner.
- Select the account you want to use in
using the selected account
. - Select
domains
undersubmit the following extrinsic
and chooseswitchDomain(operatorId, newDomainId)
in the dropdown. - Add your
operatorId
andnewDomainId
to the corresponding fields.
Only the account who registered Operator can swith the domain.
Stake of your Nominators won't be released, but will be moved to the new domain as well.
Useful commands
Running both validator (farmer) and operator nodes at the same time
To run both operator and validator at the same time, provide requrired flags for both roles when starting your node.
- 🖼️ Windows
- 🍎 macOS
- 🐧 Ubuntu
- 🐋 Docker
target/production/subspace-node `
--chain gemini-3g `
--blocks-pruning 256 `
--state-pruning archive `
--no-private-ipv4 `
--validator `
--name your_node_name `
-- `
--domain-id your_domain_id `
--operator-id your_operator_id `
--keystore-path /keystore `
--listen-addr /ip4/0.0.0.0/tcp/40333 `
--bootnodes /ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp `
--bootnodes /ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1 `
--bootnodes /ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7
target/production/subspace-node \
--chain gemini-3g \
--blocks-pruning 256 \
--state-pruning archive \
--no-private-ipv4 \
--validator \
--name your_node_name \
-- \
--domain-id your_domain_id \
--operator-id your_operator_id \
--keystore-path /keystore \
--listen-addr /ip4/0.0.0.0/tcp/40333 \
--bootnodes /ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp \
--bootnodes /ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1 \
--bootnodes /ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7
target/production/subspace-node \
--chain gemini-3g \
--blocks-pruning 256 \
--state-pruning archive \
--no-private-ipv4 \
--validator \
--name your_node_name \
-- \
--domain-id your_domain_id \
--operator-id your_operator_id \
--keystore-path /keystore \
--listen-addr /ip4/0.0.0.0/tcp/40333 \
--bootnodes /ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp \
--bootnodes /ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1 \
--bootnodes /ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7
version: "3.7"
services:
node:
# Replace snapshot-DATE with the latest release (like snapshot-2022-apr-29)
# For running on Aarch64 add -aarch64 after DATE
image: ghcr.io/subspace/node:snapshot-DATE
volumes:
# Replace path/to/keystore with your actual path to keystore.
- /path/to/keystore:/keystore:ro
# Instead of specifying volume (which will store data in /var/lib/docker), you can
# alternatively specify path to the directory where files will be stored, just make
# sure everyone is allowed to write there
- node-data:/var/subspace:rw
# - /path/to/subspace-node:/var/subspace:rw
ports:
# If port 30333 or 30433 is already occupied by another Substrate-based node, replace all
# occurrences of 30333 or 30433 in this file with another value
- "0.0.0.0:30333:30333/udp"
- "0.0.0.0:30333:30333/tcp"
- "0.0.0.0:30433:30433/udp"
- "0.0.0.0:30433:30433/tcp"
- "0.0.0.0:40333:40333/udp"
- "0.0.0.0:40333:40333/tcp"
restart: unless-stopped
command: [
"--chain", "gemini-3g",
"--base-path", "/var/subspace",
"--blocks-pruning", "256",
"--state-pruning", "archive-canonical",
"--port", "30333",
"--dsn-listen-on", "/ip4/0.0.0.0/udp/30433/quic-v1",
"--dsn-listen-on", "/ip4/0.0.0.0/tcp/30433",
"--rpc-cors", "all",
"--rpc-methods", "unsafe",
"--rpc-external",
"--no-private-ipv4",
"--validator",
"--name", "INSERT_YOUR_ID",
"--",
# Replace INSERT_YOUR_DOMAIN_ID with domain ID you want to be operator on
"--domain-id", "INSERT_YOUR_DOMAIN_ID",
# Replace INSERT_YOUR_OPERATOR_ID with your operator ID
"--operator-id", "INSERT_YOUR_OPERATOR_ID",
"--keystore-path", "/keystore",
"--listen-addr", "/ip4/0.0.0.0/tcp/40333",
"--bootnodes", "/ip4/3.87.28.170/tcp/40333/p2p/12D3KooWGHtULvhdKMZtzigSK1438uWXPj9rBQHVzTaKMWv1WRXp",
"--bootnodes", "/ip4/140.82.45.36/tcp/40333/p2p/12D3KooWJxB2PVzyNqZywoCWAMLGhKr2LCbFMXbAPzUPQZon7yt1",
"--bootnodes", "/ip4/167.179.116.135/tcp/40333/p2p/12D3KooWHsRae3ip2uQAUPtpMcStHGGw777SJT3nu9maFmtsGry7",
# Replace INSERT_YOUR_ID with your node ID (will be shown in telemetry)
]
healthcheck:
timeout: 5s
# If node setup takes longer than expected, you want to increase interval and retries number.
interval: 30s
retries: 60
farmer:
depends_on:
node:
condition: service_healthy
# Replace snapshot-DATE with latest release (like snapshot-2022-apr-29)
# For running on Aarch64 add -aarch64 after DATE
image: ghcr.io/subspace/farmer:snapshot-DATE
volumes:
# Instead of specifying volume (which will store data in /var/lib/docker), you can
# alternatively specify path to the directory where files will be stored, just make
# sure everyone is allowed to write there
- farmer-data:/var/subspace:rw
# - /path/to/subspace-farmer:/var/subspace:rw
ports:
# If port 30533 is already occupied by something else, replace all
# occurrences of 30533 in this file with another value
- "0.0.0.0:30533:30533/udp"
- "0.0.0.0:30533:30533/tcp"
restart: unless-stopped
command: [
"farm",
"--node-rpc-url", "ws://node:9944",
"--listen-on", "/ip4/0.0.0.0/udp/30533/quic-v1",
"--listen-on", "/ip4/0.0.0.0/tcp/30533",
# Replace WALLET_ADDRESS with your Polkadot.js wallet address
"--reward-address", "WALLET_ADDRESS",
# Replace PLOT_SIZE with plot size in gigabytes or terabytes, for example 100G or 2T (but leave at least 60G of disk space for node and some for OS)
"path=/var/subspace,size=PLOT_SIZE",
]
volumes:
node-data:
farmer-data:
You should see the node start successfully and begin syncing.
Switching to another server
To ensure the minimum downtime during your switch, we propose the following:
- Sync a new operator node using a throwaway key. You can generate a new key, just not insert it into your keystore.
- Stop the original node and rename the keystore (or whatever you feel comfortable doing to prevent you accidentally starting the original node up with the original signing key).
- Update the keystore on the new node with the original signing key.
- Restart the new operator node.