Custom Testnets
Custom Testnets in Zebra enable testing consensus rule changes on a public, configured Testnet independent of the default public Zcash Testnet.
Zebra’s Testnet can be configured with custom:
- Network upgrade activation heights,
- NSM reissuance heights,
- Network names,
- Network magics,
- Slow start intervals,
- Genesis hashes, and
- Target difficulty limits.
It’s also possible to disable Proof-of-Work validation by setting disable_pow to true so that blocks can be mined onto the chain without valid Equihash solutions, nor block hashes below their target difficulties.
Configuring any of those Testnet parameters except the network name with non-default values will result in an incompatible custom Testnet. Incompatible Testnets will fail to successfully complete peer handshakes with one another, or could provide one another with invalid blocks or invalid mempool transactions. Peer node connections that consistently provide invalid blocks or mempool transactions should be considered misbehaving peer connections and dropped.
All of these parameters are optional, if they are all omitted or set to their default values, Zebra will run on the default public Testnet.
Use a distinct network magic for each incompatible custom Testnet, even if their human-readable names are the same. Public DNS seed hostnames are rejected for incompatible Testnets regardless of case, trailing dots, or port.
Custom Testnet state, non-finalized backups, and peer caches use
<lowercase-name>-<eight-digit-hex-magic> storage names. Existing unsuffixed custom
Testnet caches are not reused: resynchronize the custom network after upgrading.
Mainnet, public Testnet, and Regtest keep their existing storage names. Reserved
network names are checked case-insensitively.
To test NU7 reserve reissuance, configure a NU7 activation height and
network.testnet_parameters.initial_nsm_value_balance. Omission of
network.testnet_parameters.nsm_reissuance_height uses ZIP 237’s
scheduled-issuance crossover, not NU7 activation. Some short custom schedules
have no crossover. Set an explicit height for accelerated tests, as in the
Regtest example.
Existing private chains that started reissuance at NU7 must explicitly retain
that height or restart from before activation with the new schedule.
Public NU7 activation heights remain unset.
Public Mainnet and Testnet use their historical pre-NU6 shortfalls: 36,858,445,520 and 55,768,414,957 zatoshis respectively. Testnets using public Testnet magic inherit the public seed when it is omitted, regardless of their name or checkpoints. An explicit matching public seed is normalized away, preserving the public Testnet identity and state directory. Regtest and Testnets with other magic default to zero. Explicit seed settings override these defaults; a zero-seed network cannot use public Testnet magic. An isolated chain copied from public Testnet must configure its historical seed explicitly.
To disable funding streams, set network.testnet_parameters.funding_streams = []
and remove both legacy pre_nu6_funding_streams and post_nu6_funding_streams
fields. Combining either legacy field with an empty list is a configuration error,
on both Testnet and Regtest. Omitting the list retains the requested legacy payouts
or, when no legacy fields are present, the network defaults.
The legacy post_nu6_funding_streams field uses post-NU6 defaults even when
pre_nu6_funding_streams is omitted.
Regtest skips public DNS seeders before resolving initial peers. Explicitly configured local peers remain supported.
Usage
In order to use a custom Testnet, Zebra must be configured to run on Testnet with non-default Testnet parameters. If the node is meant to mine blocks, it will need a [mining] section, and if it’s meant to mine blocks with non-coinbase transactions, it will also need the [rpc] section so the send_raw_transaction RPC method is available.
Relevant parts of the configuration file with practical Testnet parameters:
[mining]
miner_address = 't27eWDgjFYJGVXmzrXeVjnb5J3uXDM9xH9v'
[network]
network = "Testnet"
# No peers
initial_testnet_peers = []
[network.testnet_parameters]
network_name = "ConfiguredTestnet_1"
# Custom consensus parameters require a network magic distinct from public Testnet.
network_magic = [0, 1, 0, 255]
slow_start_interval = 0
target_difficulty_limit = "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
disable_pow = true
# Configured activation heights must be greater than 0, and less than
# 2^31. Block height 0 is reserved for the Genesis network upgrade in Zebra.
#
# Network upgrades must be activated in the order that they were added to Zcash,
# configuring the activation heights of recent network upgrades will activate
# any omitted prior network upgrades at the same height.
#
# For example, configuring the activation height of NU6 to block height 1 without
# configuring any other network upgrade activation heights will set the
# activation heights of BeforeOverwinter, Overwinter, Sapling, Blossom,
# Heartwood, Canopy, and NU5 at block height 1 as well.
[network.testnet_parameters.activation_heights]
NU6 = 1
# This section may be omitted if it's not necessary to
# add transactions to Zebra's mempool
[rpc]
listen_addr = "0.0.0.0:18232"
Relevant parts of the configuration file with some Mainnet parameters1:
[mining]
# The Mainnet address prefixes are reserved, all custom Testnets currently
# use the default public Testnet's address prefixes.
miner_address = 't27eWDgjFYJGVXmzrXeVjnb5J3uXDM9xH9v'
[network]
network = "Testnet"
# No peers
initial_testnet_peers = []
[network.testnet_parameters]
# The Mainnet, Testnet, and Regtest network names are reserved.
network_name = "ConfiguredTestnet_2"
# The Mainnet and Regtest network magics are reserved.
network_magic = [0, 1, 0, 255]
slow_start_interval = 20_000
genesis_hash = "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08"
# Note that setting `disable_pow` to `false` with this target difficultly
# limit will make it very difficult to mine valid blocks onto the chain and
# is not recommended.
target_difficulty_limit = "0008000000000000000000000000000000000000000000000000000000000000"
disable_pow = false
# Note that these activation heights are not recommended unless copying the
# Mainnet best chain and checkpoints to a custom Testnet. Custom Testnets will
# only try to use the Testnet checkpoints (if the checkpoint file's genesis hash
# matches the expected network genesis hash), so the Mainnet checkpoints will need
# to be copied into the Testnet checkpoints file as well.
[network.testnet_parameters.activation_heights]
BeforeOverwinter = 1
Overwinter = 347_500
Sapling = 419_200
Blossom = 653_600
Heartwood = 903_000
Canopy = 1_046_400
NU5 = 1_687_104
NU6 = 2_726_400
"NU6.1" = 3_146_400
"NU6.2" = 3_364_600
"NU6.3" = 3_428_143
# NU7 has no scheduled activation height yet; this is an example value.
NU7 = 3_500_000
# This section may be omitted if it's not necessary to
# add transactions to Zebra's mempool
[rpc]
listen_addr = "0.0.0.0:18232"
Caveats and Restrictions
There are a few caveats:
- Configured network upgrade activation heights must be above the genesis block height, which is reserved for Zebra’s
Genesisnetwork upgrade, and must not be above Zebra’s max block height of2^31 - 12. - While it’s possible to activate Canopy and later network upgrades after height 1, Zebra cannot currently produce pre-Canopy block templates, so the
getblocktemplateRPC method and Zebra’s internal miner which depends on thegetblocktemplatemethod won’t work until Canopy is activated. An alternative block source will be required to mine pre-Canopy blocks onto Zebra’s chain. - Incompatible Testnets must configure a network magic distinct from public Testnet and use their own initial peers. Public Testnet magic is rejected even with an empty initial peer list, and the default public seeds are also rejected3.
- If the genesis hash is configured, a genesis block will need to be copied into the custom Testnet state or submitted via the
submitblockRPC method, Zebra cannot currently generate genesis blocks. See theCreateGenesisBlock()function inzcashd/src/chainparams.cppfor use cases that require a new genesis block.
There are also a few other restrictions on these parameters:
- The network name must:
- not be any of the reserved network names:
Testnet,Mainnet, andRegtest, - contain only alphanumeric characters and underscores, and
- be shorter than the
MAX_NETWORK_NAME_LENGTHof30.
- not be any of the reserved network names:
- The network magic must not be any of the reserved network magics:
[36, 233, 39, 100]and[170, 232, 63, 95], these are theMainnetandRegtestnetwork magics respectively. - The network upgrade activation heights must be in order, such that the activation height for every network upgrade is at or above the activation height of every preceding network upgrade.
- The configured subsidy schedule must stay within the 21-million-ZEC cap through the maximum supported height. Early spacing upgrades during slow start can violate this bound; accelerated test networks can set
slow_start_interval = 0. - Configured NSM reissuance requires a post-NU7 halving interval with a positive integer reissuance coefficient. Configured funding streams also require a nonzero address-change interval.
Comparison To Mainnet and Default Public Testnet Consensus Rules
Aside from the configurable parameters, custom Testnets in Zebra validate the same consensus rules as Testnet.
Differences Between Mainnet and Testnet Consensus Rules
Zebra’s Testnet validates almost all of the same consensus rules as Mainnet, the differences are:
- Constants defined in the
zcash_protocol::consensus::Parameterstrait, which includes but may not be limited to:- Zcash address prefixes (see
NetworkConstants), and coin type, which is133onMainnetor1elsewhere. - Network upgrade activation heights.
- Zcash address prefixes (see
- Constants defined in Zebra:
PoWLimitdefined in the Zcash protocol specification, or target difficulty limit, which is2^243 - 1on Mainnet and2^251 - 1on the default Testnet.- Expected genesis block hash.
- Number of funding streams, which is 48 on Mainnet and 51 on Testnet.
- The first block subsidy halving height, which is
1,046,400(Canopy activation) on Mainnet and1,116,000on Testnet
- The Testnet minimum difficulty rule, validated by the
difficulty_threshold_and_time_are_valid()function inzebra_state::service::checkand applied to block templates by theadjust_difficulty_and_time_for_testnet()function inzebra_state::service::read::difficulty, both of which use theAdjustedDifficulty::expected_difficulty_threshold()method inzebra_state::service::check::difficultyto calculate the expected difficulty. - Max block time is always enforced on Mainnet, but only enforced after block height
653,606on Testnets (block times later than the median block time + a constant are rejected while this rule is enforced, this is part of the block header consensus rules in the Zcash specification).
Configuring More Testnet Parameters To Match Mainnet Consensus Rules
The Mainnet Zcash address prefixes, coin type, network name, and network magic should remain reserved for Mainnet.
The network upgrade activation heights, target difficulty limit, slow start interval, and genesis hash of a custom Testnet could currently be configured in Zebra to match Mainnet.
The remaining consensus differences between Mainnet and Testnet could be made configurable in Zebra so that they could be configured to match Mainnet.
Differences Between Custom Testnets and Regtest
Zebra’s Regtest network is a special case of a custom Testnet that:
- Won’t make remote peer connections4,
- Skips Proof-of-Work validation,
- Uses a reserved network magic and network name,
- Activates network upgrades up to and including Canopy at block height 1,
- Tries to closely match the
zcashdRegtest parameters, and - Expects the Regtest genesis hash.
Once Zebra’s internal miner can mine Equihash solutions with configurable parameters, Zebra’s Regtest should validate Proof-of-Work with the zcashd Regtest Equihash parameters unless it’s disabled in its configuration, and custom Testnets should allow for configuring their Equihash parameters as well.
In the future, Zebra may also allow for disabling peers on custom Testnets so that the only unique parameters of Zebra’s Regtest will be the network name and magic.
Peer Connections In Custom Testnets
Aside from the network name, configuring any Testnet parameters in Zebra will result in an incompatible custom Testnet such that it cannot use the default initial Testnet peers.
In the absence of a configurable Zcash DNS seeder, Zebra nodes on custom Testnets will need to know the exact hostname or IP address of other Zebra nodes on the same custom Testnet to make peer connections.
Zebra nodes on custom Testnets reject peer connections using a different network magic or network protocol version. Nodes that reuse the same non-public magic can still have incompatible consensus parameters, so configure every peer in a custom network consistently.
Footnotes
-
Only the network upgrade activation heights, target difficulty limit, slow start interval, and genesis hash of a custom Testnet may currently be configured in Zebra to match Mainnet, other differences between Mainnet and Testnet consensus rules still remain with any custom Testnet configuration. More parameters may become configurable in the future, but the Mainnet Zcash address prefixes, coin type, network name, and network magic should remain reserved only for Mainnet. ↩
-
Zebra’s max on-disk serialized block height is currently
2^24 - 1, the max block height of2^31 - 1can only be represented in-memory, so while an activation height of2^31 - 1is valid, Zebra’s best chain would not currently be able to reach that activation height. ↩ -
Consensus-affecting parameters include network upgrade heights, subsidy and funding schedules, slow start, genesis, Proof-of-Work rules, and the temporary Orchard disabling height. Changing only the network name does not affect consensus compatibility. ↩
-
Zebra won’t make remote outbound peer connections on Regtest, but currently still listens for remote inbound peer connections, which will be rejected unless they use the Regtest network magic, and Zcash nodes using the Regtest network magic should not be making outbound peer connections. It may be updated to skip initialization of the peerset service altogether so that it won’t listen for peer connections at all when support for isolated custom Testnets is added. ↩