Configure
Disclaimer: Canopy is alpha-stage software. While documentation and guides are provided to assist users, they come with no warranties, guarantees, or assurances of reliability. Users are solely responsible for any issues that may arise, including but not limited to the loss of funds. Please proceed with caution.
Configure
The Canopy software is designed with simplicity in mind and configuration is meant to be minimal while giving node runners power to adapt the software to the needs of the deployers or Nested Chains.
➩ This section details the configuration of Canopy nodes, and while Canopy is meant to be hassle free, the intended audience is Validator and RPC providers.
Data Directory
The data directory of a Canopy node contains the application level files that Canopy requires to function.
💡 The default location of a Canopy data directory is $USERHOME/.canopy
or simply ~/.canopy
.
$ ls ~/.canopy
> book.json config.json keystore.json polls.json validator_key.json
canopy/ genesis.json heap1.out heap2.out logs proposals.json
Contents
book.json: the 'peer address book' of the Canopy node. This file contains addresses of 'potential peers' a node may connect to. This file is auto-populated by the P2P module of Canopy and is not meant to be manually edited, especially while the software is running.
config.json: the configuration file of the Canopy node. All configuration is handled in this single file. This file is loaded once upon startup, modifying this file during active operation is currently safe but changes are not reflected until the node is restarted.
keystore.json: the local store of encrypted private keys that may be utilized by the pre-packaged 1️⃣ web wallet, 2️⃣ command line interface, or 3️⃣ admin rpc. Importantly, this file is not critical for Validator operation, storing the validator key in this file does not change node behavior.
polls.json: this file is used to store non-critical 'on-chain' governance polling information parsed from blocks. If this file is modified or corrupted, it may lead to incorrect displays in the prepackaged web-wallet but otherwise does not affect consensus or any other critical component of node operation.
validator_key.json: the ⚠️ plain-text BDN (BLS) private key of the
operator
of the node. The security model of Canopy presumes there is no unauthorized access to the server. However, due to the non-custodial design of Canopy, theoutput
private key (cold / off server) is what holds custody over staked tokens and rewards. Meaning, unauthorized access to the operator key allowsunauthorized pausing
,unauthorized unstaking
, or P2P spoofing as a Validator, but does not copromise staked funds or rewards. As a result, little to no funds should be kept in the operator address.canopy/: the nested directory where the badgerDB blockchain data is stored. Conveniently, Canopy includes data of transactions, blocks, state, and sparse merkle tree in a single database. Writes to the database are guarenteed to be atomic by badger so corruption events should be minimal if any. Live snapshotting this data while the software is running is not officially supported, but
rsync
(or similar) may be used to quickly copy data across servers if needed when the software is stopped. If provided a snapshot from a trusted party, this is likely the directory that should be replaced.genesis.json: the json encoded version of the starting state of the blockchain. This file is interpreted and injected into the database by the software - allowing an 'agreed upon' starting point of the blockchain. Testnet, Mainnet, Canarynet and other Nested Chains will all have unique genesis files. If
invalid block hash
or similar error logs are seen when syncingheight 1
- it's often due to an incorrect genesis.json file or incorrectchain_id
configuration.heap1.out / heap2.out: debug memory profiling files are generated automatically. Heap1 is created at startup and Heap2 is replaced every 10 seconds. These files will likely be removed in the future - but allow the development team to easily debug OOM situations. These files are overwritten at restart, so save them accordingly.
logs/: the sub-directory of gzipped logs. Logs are automatically directed to stdout, the web wallet, the admin rpc, and are saved in this directory. While the Canopy software auto-rotates and compresses logs, this directory should be periodically monitored for uncontrolled growth (especially during alpha and beta phases). Inclusion of the appopriate gzipped log file or log output is often a minimum requirement for debugging requests.
proposals.json: the local voting configuration of the Canopy node for governance proposals. This file is only applicable to active Validators, as it configures a Validator to allow a proposal transaction to be included in a block (or not). This file is not meant to be manually edited, especially while the software is running. This file may be safely edited using the prepackaged web wallet under the governance section.
Config.json
Configuration of a Canopy Validator is handled using a single config.json file.
➩ The config.json
file is located in the data directory
(default ~/.canopy) of the Canopy node and is loaded once upon startup.
This file is able to be edited during software operation, but requires a restart to apply any changes.
{
"logLevel": "debug",
"chainId": 1,
"sleepUntil": 0,
"rootChain": [
{
"chainId": 1,
"url": "http://localhost:50002"
},
{
"chainId": 2,
"url": "http://localhost:40002"
}
],
"runVDF": true,
"headless": false,
"walletPort": "50000",
"explorerPort": "50001",
"rpcPort": "50002",
"adminPort": "50003",
"rpcURL": "http://localhost:50002",
"adminRPCUrl": "http://localhost:50003",
"rootChainPollMS": 333,
"timeoutS": 3,
"dataDirPath": "/root/.canopy",
"dbName": "canopy",
"inMemory": false,
"networkID": 1,
"listenAddress": "0.0.0.0:9001",
"externalAddress": "tcp://canopy-rocks.io",
"maxInbound": 21,
"maxOutbound": 7,
"trutedPeersIDs": null,
"dialPeers": ["def02e9b054428f198e89179685a48b227f1c189966d4db002f24f8155c5119c
bb9387146889b5dc4a260184f20d5ecd@tcp://canopy-does-rock.io:9001"],
"bannedPeersIDs": null,
"bannedIPs": null,
"electionTimeoutMS": 200,
"electionVoteTimeoutMS": 200,
"proposeTimeoutMS": 1000,
"proposeVoteTimeoutMS": 1000,
"precommitTimeoutMS": 200,
"precommitVoteTimeoutMS": 200,
"commitTimeoutMS": 200,
"roundInterruptTimeoutMS": 0,
"maxTotalBytes": 10000000,
"maxTransactionCount": 5000,
"individualMaxTxSize": 4000,
"dropPercentage": 35
}
logLevel:
Configures the level of specifity in logs
DEBUG: (color: BLUE | highest specificity), good for checkout out issues
INFO: (color: GREEN | medium specificity), good for most use-cases
WARN: (color: YELLOW | low specificity), only outputs potential problems
ERROR: (color: RED | minimum specificity), only outputs software issues
chainId:
The unique identifier of the chain (1=CNPY, 2=CNRY, etc) within a network
1: CNPY
2: CNRY
💡 An incorrect chainId
may result in the inability to connect to peers, sync, or error output like unequal block-hash
.
sleepUntil:
A Unix timestamp (in microseconds) that instructs the software to pause execution until the specified time. This allows validators to coordinate and begin operation simultaneously—useful for restarting networks or synchronizing genesis events.
rootChain
An array of chainId | url
objects that specify the RPC endpoint of the root chain.
The root chain is a fundamental part of the Canopy architecture. It defines the validator set and provides critical information needed for a chain to operate as a validator.
The root chain plays a central role in Canopy’s recursive architecture—essential to understanding how Canopy enables scalable and modular Web3 infrastructure. Refer to the documentation for deeper context.
For simplicity, you can think of the root chain as the "parent" chain responsible for:
Determining the active validator set
Providing configuration and coordination data
Serving as the chain where validators stake to participate in consensus for nested chains
A chain may designate itself as its root chain. This is known as chain independence.
Validators stake on the root chain to perform consensus operations for nested chains. They may also stake on nested chains to be "on-deck" for future independence, though this currently plays a more economic/preparatory role.
The Canopy software connects to the root chain over WebSockets using an upgraded JSON-RPC protocol, enabling fast and reliable access to validator-critical information.
Best Practices for a root chain RPC node:
Must be trusted
Should have low latency
Although the field accepts an array, only one root chain is active at a time. The array allows for:
Seamless root switching
Future graduation to independence
runVDF:
Boolean to enable or disable the proof-of-age verifiable delay function. As a Validator of a root chain, this should be true
.
If the Nested Chain
relies on some other fork-choice mechanism (like Checkpointing) then this may be disabled.
headless:
Disable the pre-packaged web wallet and block explorer of the Canopy software. This is useful for those who utilize the CLI only for operation - though it is encouraged for production deployments to use the front ends provided.
walletPort:
The rpcURL:port where the pre-packaged web wallet is hosted by the sofware.
View it in browser, behind a reverse proxy is recommended
Default: 50000
explorerPort:
The rpcURL:port where the pre-packaged block explorer is hosted by the sofware.
View it in browser, behind a reverse proxy is recommended
Default: 50001
rpcPort:
The rpcURL:port where the JSON RPC API is hosted by the software.
See the JSON RPC Specification for more details.
Default: 50002
adminPort
The rpcURL:port where the administrator JSON RPC API is hosted by the software
See the JSON RPC Specification for more details.
Default: 50003
rpcURL
The url where the RPC is hosted by the software. This URL is utilized by the prepackaged web wallet and block explorer to connect to the local node.
Default: http://localhost
adminRPCURL
The url where the admin RPC is hosted by the software. This URL is utilized by the prepackaged web wallet to connect to the local node.
Default: http://localhost
⚠️ HTTPS is required for production as passwords are sent plain-text
timeoutS
The RPC request timeout duration in seconds.
Default: 3
dataDirPath
The path of the data directory - default is $USERHOME/.canopy
NOTE: Datadirectory path is expiremental and requires the
--data-dir=<PATH>
flag as the software doesn't know where to look for the config.json file.
dbName
Modify the name of the database folder inside the data directory.
Changing between software runs will create a brand new database from scratch, resulting in a resync.
Default: canopy
inMemory
Debug only: run the blockchain database completely in memory and don't persist anything to disk
networkID
The unique identifier of the network (1=MAINNET, 2=TESTNET, etc). Each network has many chainIds within it.
1: mainnet
2:testnet
NOTE: chain id is 1 tier below network id. Network ID is
mainnet
ortestnet
whereaschainId
is the sovereign chains within the network (like CNPY or CNRY). This allows for future proof partitions of chain ids.
💡 An incorrect networkId
may result in the inability to connect to peers, sync, or error output like unequal block-hash
.
listenAddress
The TCP listening address for the peer-to-peer module.
Importantly, the port must correspond with the chainId
with the following formula:
:9000 + chainId
This enables multi-committee setups under a single netURL
Default for CNPY: 0.0.0.0:9001
externalAddress
The TCP URL where peers may discover this node. This URL is displayed within peer's address book and is exchanged with PEX events.
➪ This must be configured or no inbound peers will ever be able to be established.
Example: tcp://canopy-rocks.io (which firewall maps to the listenAddress)
maxInbound
The upper bound of inbound peers (peers that dialed this node)
The minimum appropriate ratio of inbound:outbound is 3:1. 4:1 or 5:1 is even healthier for the network.
Default: 21
maxOutbound
The upper bound of outbound peers (peers that this node dials)
The minimum appropriate ratio of inbound:outbound is 3:1. 4:1 or 5:1 is even healthier for the network.
Default: 7
trutedPeersIDs
A string array of hex-encoded
public keys that will be allowed to surpass limits and will never be dropped due to a bad peer reputation.
Example: ["def02e9b054428f198e89179685a48b227f1c189966d4db002f24f8155c5119c bb9387146889b5dc4a260184f20d5ecd"]
dialPeers
A string array of peers to dial with exponential backoff upon startup.
Format is publicKey@externalAddress
Example: ["def02e9b054428f198e89179685a48b227f1c189966d4db002f24f8155c5119c bb9387146889b5dc4a260184f20d5ecd@tcp://canopy-rocks.io"]
bannedPeersIDs
A string array of hex-encoded
public keys that will not be allowed to connect to this node.
Example: ["def02e9b054428f198e89179685a48b227f1c189966d4db002f24f8155c5119c bb9387146889b5dc4a260184f20d5ecd"]
bannedIPs
A string array of IPV4 addresses
that will not be allowed to connect to this node.
Example: ["8.8.8.8"]
newHeightTimeoutMS
The amount of time in milliseconds wait taken after starting a new height. This allows processing like Committing
the previous quorum certificate to storage.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
electionTimeoutMS
The amount of time in milliseconds wait taken after starting the election phase. This allows time for Validators to annouce themselves as leader candidates.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
electionVoteTimeoutMS
The amount of time in milliseconds wait taken after starting the election vote phase. This allows time for replicas to vote for who they believe is the leader.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
proposeTimeoutMS
The amount of time in milliseconds wait taken after starting the propose phase. This allows time for the leader to create and send a block proposal.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
proposeVoteTimeoutMS
The amount of time in milliseconds wait taken after starting the propose vote phase. This allows time for replicas to vote on the leaders' proposal.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
precommitTimeoutMS
The amount of time in milliseconds wait taken after starting the precommit phase. This allows time for the leader to send a proof of proposal approval to the replicas.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
precommitVoteTimeoutMS
The amount of time in milliseconds wait taken after starting the precommit vote phase. This allows time for the replicas time to vote on the proof of proposal approval.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
commitTimeoutMS
The amount of time in milliseconds wait taken after starting the commit phase. This allows time for the leader to communicate the 'commit' command to replicas.
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
roundInterruptTimeoutMS (deprecated)
Round interrupt now relies onmsLeftInRound
⚠️ This value should not be modified once a genesis event takes place. It determines block timing
maxTotalBytes
The total amount of bytes allowed in the unconfirmed transaction memory pool (mempool)
5-10x block size recommended as a minimum
maxTransactionCount
The maximum count of individual transactions allowed in the unconfirmed transaction memory pool (mempool)
individualMaxTxSize
The maximum number of bytes allowed in an individual transaction in the unconfirmed transaction memory pool (mempool)
dropPercentage
The percentage of unconfirmed transaction memory pool (mempool) that is dropped when the mempool overflows. Lowest fee transactions dropped first
prometheusAddress
The address of prometheus metric collection
Default: 0.0.0.0:9090
Last updated