Compare commits

...

15 Commits

Author SHA1 Message Date
Gustavo Valverde 649738d66f
Merge 5f835a19e0 into d84d7356dd 2024-04-27 02:05:47 -05:00
Arya d84d7356dd
add(consensus): Adds `disable_pow` and `genesis_hash` fields, converts `equihash::Solution` to an enum (#8421)
* minor cleanup and rename

* Adds an empty NetworkParameters struct to Network::Testnet variant, updates production code.

* Updates tests

* Adds `NetworkKind` and uses it instead of `Network` in `HistoryTreeParts` and `transparent::Address`

* Adds a [network.testnet_parameters] section to the config, uses `NetworkKind` as zebra_network::Config::network field type, and converts 'Network' to `NetworkKind` before serializing

* Applies some suggestions from code review

* Applies suggestions from code review

* returns b58 prefix constants directly to remove From<NetworkKind> impl for zcash_primitives::consensus::Network

* Applies more suggestions from code review.

* moves conversions to zcash_primitives::consensus::Network to where they're used.

* Apply suggestions from code review

Co-authored-by: Marek <mail@marek.onl>

* rename `network` variables and method names typed as NetworkKind to `network_kind`

* use only test block heights for the network associated with them

* Applies more suggestions from code review.

* Rename `NetworkParameters` to `Parameters` and move it a new `testnet` module

* adds activation heights field

* updates stored test config, adds a quicker test for checking that stored configs can be parsed, adds an intermediate representation of activation heights

* implement Parameters for Network

* Passes &Network directly instead of converting to zp_consensus::Network where there were conversions

* fixes a bad merge (removes a network conversion in zcash_note_encryption)

* Adds a test for the Parameters impl for zebra_chain::Network

* fixes doc links

* - Makes the `activation_heights` config field optional by adding a #[serde(default)]
- Panics if a non-zero activation height is provided for the `Genesis` network upgrade
- Always sets the `Genesis` and `BeforeOverwinter` network upgrade activation heights to 0 and 1, `BeforeOverwinter` could be overwritten by a later network upgrade
- Makes the `activation_heights` field on `Parameters` private, adds/uses an accessor method instead, and adds a builder struct and `build()` method

* small refactor of activation_heights() method

* check that activation heights are in the right order

* Updates `NetworkUpgrade::activation_height()` to return the height of the next NetworkUpgrade if it doesn't find the activation height of `&self`

* checks that the miner address is of TestnetKind on Regtest and update assertion message

* Adds a DNetworkUpgradeActivationHeights struct for better control over how activation heights can be configured

* moves all ordered network upgrades to a constant, adds a no_duplicates test, moves struct with activation heights outside deserialization impl and accepts it in `ParametersBuilder::activation_heights()` instead of a Vec

* panics if any network upgrades are configured to activate at Height(0) because it's reserved for Genesis

* Simplifies the `ParametersBuilder::activation_heights()` method and removes an unnecessary test.

* Adds Sapling HRPs as fields on testnet params. (#8398)

* Applies suggestions from code review.

* Update zebra-chain/src/parameters/network_upgrade.rs

Co-authored-by: Marek <mail@marek.onl>

* Adds `network_name` field and accessor method on `Parameters`, uses it in the `Display` impl for `Network`

* Removes unnecessary `.filter()`

* adds constraints on valid network names and a test

* adds config field for setting network name, adds "with_" prefix to ParameterBuilder setter methods

* Adds `MainnetKind`, `TestnetKind`, and `RegtestKind` to reserved network names

* updates stored test configs and fixes `network_name()` docs

* Adds a `new_regtest()` method on `Network` and `testnet::Parameters`, updates config deserialization to return an error if the initial_testnet_peers include any default initial peers AND contain configured activation heights

* Updates `activates_network_upgrades_correctly` test to check Regtest activation heights (and default Mainnet/Testnet)

* Refactors if-let & match statement into general match statement, removes constraint against including `testnet_parameters` field/section in the config when using `Mainnet` or `Regtest`

* Removes outdated TODO

* Restores `testnet_parameters` section of the latest stored config.

* Adds `with_sapling_hrps()` method and uses it to set the Regtest HRPs in `new_regtest()`.

Adds a test for Sapling HRP validation

* Checks that default Mainnet/Testnet/Regtest Sapling HRPs pass validation in `with_sapling_hrps()`

* Uses the correct constant in test

* Adds `is_regtest()` methods

* Adds genesis hash methods and fields to `testnet::Parameters` and its builder

* Copies Regtest genesis block from zcashd

* moves genesis hash check to Network.checkpoint_list()

* Checks the first line in the checkpoint list instead of the first item in the BTreeMap

* Checks that there is _some_ genesis block in the checkpoints list in `from_list()`, adds Regtest checkpoints (which only includes the genesis block)

* Adds a doc comment to `ParametersBuilder::default()`

* Adds a `disable_pow` field and skips checking proof of work if it's true

* Makes `equihash::Solution` an enum to support Regtest solutions, adds a test for validating and committing the Regtest genesis block

* use genesis_hash as first checkpoint when checkpoints are missing for configured testnets too

* Applies suggestions from code review.

* Reverts changes to `activation_height()` method

* Avoids panic in test

* Updates test docs

* drop custom panic hooks after expected panics

---------

Co-authored-by: Marek <mail@marek.onl>
2024-04-26 05:30:36 +00:00
Arya c28e37bf23
disables `rejection_restores_internal_state_genesis` test on Windows (#8468) 2024-04-26 05:30:31 +00:00
Arya e5d4d739b7
add(consensus/network): Adds `new_regtest()` constructors to `testnet::Parameters` and `Network` (#8413)
* minor cleanup and rename

* Adds an empty NetworkParameters struct to Network::Testnet variant, updates production code.

* Updates tests

* Adds `NetworkKind` and uses it instead of `Network` in `HistoryTreeParts` and `transparent::Address`

* Adds a [network.testnet_parameters] section to the config, uses `NetworkKind` as zebra_network::Config::network field type, and converts 'Network' to `NetworkKind` before serializing

* Applies some suggestions from code review

* Applies suggestions from code review

* returns b58 prefix constants directly to remove From<NetworkKind> impl for zcash_primitives::consensus::Network

* Applies more suggestions from code review.

* moves conversions to zcash_primitives::consensus::Network to where they're used.

* Apply suggestions from code review

Co-authored-by: Marek <mail@marek.onl>

* rename `network` variables and method names typed as NetworkKind to `network_kind`

* use only test block heights for the network associated with them

* Applies more suggestions from code review.

* Rename `NetworkParameters` to `Parameters` and move it a new `testnet` module

* adds activation heights field

* updates stored test config, adds a quicker test for checking that stored configs can be parsed, adds an intermediate representation of activation heights

* implement Parameters for Network

* Passes &Network directly instead of converting to zp_consensus::Network where there were conversions

* fixes a bad merge (removes a network conversion in zcash_note_encryption)

* Adds a test for the Parameters impl for zebra_chain::Network

* fixes doc links

* - Makes the `activation_heights` config field optional by adding a #[serde(default)]
- Panics if a non-zero activation height is provided for the `Genesis` network upgrade
- Always sets the `Genesis` and `BeforeOverwinter` network upgrade activation heights to 0 and 1, `BeforeOverwinter` could be overwritten by a later network upgrade
- Makes the `activation_heights` field on `Parameters` private, adds/uses an accessor method instead, and adds a builder struct and `build()` method

* small refactor of activation_heights() method

* check that activation heights are in the right order

* Updates `NetworkUpgrade::activation_height()` to return the height of the next NetworkUpgrade if it doesn't find the activation height of `&self`

* checks that the miner address is of TestnetKind on Regtest and update assertion message

* Adds a DNetworkUpgradeActivationHeights struct for better control over how activation heights can be configured

* moves all ordered network upgrades to a constant, adds a no_duplicates test, moves struct with activation heights outside deserialization impl and accepts it in `ParametersBuilder::activation_heights()` instead of a Vec

* panics if any network upgrades are configured to activate at Height(0) because it's reserved for Genesis

* Simplifies the `ParametersBuilder::activation_heights()` method and removes an unnecessary test.

* Adds Sapling HRPs as fields on testnet params. (#8398)

* Applies suggestions from code review.

* Update zebra-chain/src/parameters/network_upgrade.rs

Co-authored-by: Marek <mail@marek.onl>

* Adds `network_name` field and accessor method on `Parameters`, uses it in the `Display` impl for `Network`

* Removes unnecessary `.filter()`

* adds constraints on valid network names and a test

* adds config field for setting network name, adds "with_" prefix to ParameterBuilder setter methods

* Adds `MainnetKind`, `TestnetKind`, and `RegtestKind` to reserved network names

* updates stored test configs and fixes `network_name()` docs

* Adds a `new_regtest()` method on `Network` and `testnet::Parameters`, updates config deserialization to return an error if the initial_testnet_peers include any default initial peers AND contain configured activation heights

* Updates `activates_network_upgrades_correctly` test to check Regtest activation heights (and default Mainnet/Testnet)

* Refactors if-let & match statement into general match statement, removes constraint against including `testnet_parameters` field/section in the config when using `Mainnet` or `Regtest`

* Removes outdated TODO

* Restores `testnet_parameters` section of the latest stored config.

* Adds `with_sapling_hrps()` method and uses it to set the Regtest HRPs in `new_regtest()`.

Adds a test for Sapling HRP validation

* Checks that default Mainnet/Testnet/Regtest Sapling HRPs pass validation in `with_sapling_hrps()`

* Uses the correct constant in test

* Adds `is_regtest()` methods

* Updates test docs

* drop custom panic hooks after expected panics

---------

Co-authored-by: Marek <mail@marek.onl>
2024-04-25 04:04:05 +00:00
Arya e95a70de7a
increases timeout duration waiting on done notification in non-blocking logger test (#8462) 2024-04-24 20:28:17 +00:00
Arya ee9ab3162a
fixes concurrency bug in z_get_treestate RPC method (#8460) 2024-04-24 20:27:56 +00:00
Alfredo Garcia d869ec6fe4
change(release): Adjust estimated release interval and end of support (#8429)
* change estimated release interval and end of support

* update readme
2024-04-24 19:22:07 +00:00
Alfredo Garcia 5f69870235
bump(deps): Update what we can from the prod group of deps (#8423)
* update partially the prod group of deps

* update prod deps
2024-04-24 13:54:00 +00:00
Arya 275e99ec72
add(chain): Adds a `network_name` field to `testnet::Parameters` (#8411)
* minor cleanup and rename

* Adds an empty NetworkParameters struct to Network::Testnet variant, updates production code.

* Updates tests

* Adds `NetworkKind` and uses it instead of `Network` in `HistoryTreeParts` and `transparent::Address`

* Adds a [network.testnet_parameters] section to the config, uses `NetworkKind` as zebra_network::Config::network field type, and converts 'Network' to `NetworkKind` before serializing

* Applies some suggestions from code review

* Applies suggestions from code review

* returns b58 prefix constants directly to remove From<NetworkKind> impl for zcash_primitives::consensus::Network

* Applies more suggestions from code review.

* moves conversions to zcash_primitives::consensus::Network to where they're used.

* Apply suggestions from code review

Co-authored-by: Marek <mail@marek.onl>

* rename `network` variables and method names typed as NetworkKind to `network_kind`

* use only test block heights for the network associated with them

* Applies more suggestions from code review.

* Rename `NetworkParameters` to `Parameters` and move it a new `testnet` module

* adds activation heights field

* updates stored test config, adds a quicker test for checking that stored configs can be parsed, adds an intermediate representation of activation heights

* implement Parameters for Network

* Passes &Network directly instead of converting to zp_consensus::Network where there were conversions

* fixes a bad merge (removes a network conversion in zcash_note_encryption)

* Adds a test for the Parameters impl for zebra_chain::Network

* fixes doc links

* - Makes the `activation_heights` config field optional by adding a #[serde(default)]
- Panics if a non-zero activation height is provided for the `Genesis` network upgrade
- Always sets the `Genesis` and `BeforeOverwinter` network upgrade activation heights to 0 and 1, `BeforeOverwinter` could be overwritten by a later network upgrade
- Makes the `activation_heights` field on `Parameters` private, adds/uses an accessor method instead, and adds a builder struct and `build()` method

* small refactor of activation_heights() method

* check that activation heights are in the right order

* Updates `NetworkUpgrade::activation_height()` to return the height of the next NetworkUpgrade if it doesn't find the activation height of `&self`

* checks that the miner address is of TestnetKind on Regtest and update assertion message

* Adds a DNetworkUpgradeActivationHeights struct for better control over how activation heights can be configured

* moves all ordered network upgrades to a constant, adds a no_duplicates test, moves struct with activation heights outside deserialization impl and accepts it in `ParametersBuilder::activation_heights()` instead of a Vec

* panics if any network upgrades are configured to activate at Height(0) because it's reserved for Genesis

* Simplifies the `ParametersBuilder::activation_heights()` method and removes an unnecessary test.

* Adds Sapling HRPs as fields on testnet params. (#8398)

* Applies suggestions from code review.

* Update zebra-chain/src/parameters/network_upgrade.rs

Co-authored-by: Marek <mail@marek.onl>

* Adds `network_name` field and accessor method on `Parameters`, uses it in the `Display` impl for `Network`

* Removes unnecessary `.filter()`

* adds constraints on valid network names and a test

* adds config field for setting network name, adds "with_" prefix to ParameterBuilder setter methods

* Adds `MainnetKind`, `TestnetKind`, and `RegtestKind` to reserved network names

* updates stored test configs and fixes `network_name()` docs

---------

Co-authored-by: Marek <mail@marek.onl>
2024-04-24 11:03:37 +00:00
Alfredo Garcia 8cf0b7a36a
bump(zcash_script): Bump zcash script v0.1.15 and restore Windows support (#8393)
* update zcash_script and zcash_primitives

* restore windows support

* add a windows config file

* try exact output from CI

* ignore config test in windows

* disable test for windows

* remove test for windows

* change zcash_script branch to release

* bump top the last zcash_script release version

* restore `rejection_restores_internal_state_genesis` test

* fix typo in test name and enable single thread on windows

* disable single thread
2024-04-22 22:07:04 +00:00
dependabot[bot] 74319ec477
build(deps): bump rustls from 0.21.10 to 0.21.11 in the cargo group (#8418)
Bumps the cargo group with 1 update: [rustls](https://github.com/rustls/rustls).


Updates `rustls` from 0.21.10 to 0.21.11
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.21.10...v/0.21.11)

---
updated-dependencies:
- dependency-name: rustls
  dependency-type: indirect
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-22 19:32:06 +00:00
Gustavo Valverde 5f835a19e0 fix(build): `buildx` setup must be after registry login 2024-03-22 11:33:32 +01:00
Gustavo Valverde 5aa1a8091c ref(build): avoid using an external cache with Docker Build Cloud 2024-03-22 11:30:37 +01:00
Gustavo Valverde 773b0b531f fix(build): secrets, runner and conditional login 2024-03-22 11:13:37 +01:00
Gustavo Valverde 9dbdfe28c5 feat(build): use Docker Build Cloud for image build 2024-03-22 09:26:26 +01:00
40 changed files with 816 additions and 259 deletions

View File

@ -136,6 +136,8 @@ jobs:
image_name: zebrad
no_cache: ${{ inputs.no_cache || false }}
rust_log: info
# This step needs access to Docker Hub secrets to run successfully
secrets: inherit
# Test that Zebra works using the default config with the latest Zebra version.
test-configuration-file:

View File

@ -149,6 +149,9 @@ jobs:
rust_backtrace: full
rust_lib_backtrace: full
rust_log: info
# This step needs access to Docker Hub secrets to run successfully
secrets: inherit
# zebrad cached checkpoint state tests

View File

@ -111,6 +111,8 @@ jobs:
rust_backtrace: full
rust_lib_backtrace: full
rust_log: info
# This step needs access to Docker Hub secrets to run successfully
secrets: inherit
# Run all the zebra tests, including tests that are ignored by default.
#

View File

@ -78,8 +78,7 @@ jobs:
strategy:
fail-fast: false
matrix:
# TODO: Windows was removed for now, see https://github.com/ZcashFoundation/zebra/issues/3801
os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, beta]
# TODO: When vars.EXPERIMENTAL_FEATURES has features in it, add it here.
# Or work out a way to trim the space from the variable: GitHub doesn't allow empty variables.

View File

@ -68,7 +68,7 @@ jobs:
build:
name: Build images
timeout-minutes: 210
runs-on: ubuntu-latest-xl
runs-on: ubuntu-latest
outputs:
image_digest: ${{ steps.docker_build.outputs.digest }}
image_name: ${{ fromJSON(steps.docker_build.outputs.metadata)['image.name'] }}
@ -92,6 +92,8 @@ jobs:
uses: docker/metadata-action@v5.5.1
with:
# list of Docker images to use as base name for tags
# We only publish images to DockerHub if a release is not a pre-release
# Ref: https://github.com/orgs/community/discussions/26281#discussioncomment-3251177
images: |
us-docker.pkg.dev/${{ vars.GCP_PROJECT }}/zebra/${{ inputs.image_name }}
zfnd/${{ inputs.image_name }},enable=${{ github.event_name == 'release' && !github.event.release.prerelease }}
@ -118,11 +120,6 @@ jobs:
type=edge,enable={{is_default_branch}}
type=schedule
# Setup Docker Buildx to allow use of docker cache layers from GH
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v2.1.2
@ -144,14 +141,20 @@ jobs:
password: ${{ steps.auth.outputs.access_token }}
- name: Login to DockerHub
# We only publish images to DockerHub if a release is not a pre-release
# Ref: https://github.com/orgs/community/discussions/26281#discussioncomment-3251177
if: ${{ github.event_name == 'release' && !github.event.release.prerelease }}
uses: docker/login-action@v3.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Setup Docker Buildx to use Docker Build Cloud
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
with:
version: "lab:latest"
driver: cloud
endpoint: "zfnd/zebra"
# Build and push image to Google Artifact Registry, and possibly DockerHub
- name: Build & push
id: docker_build
@ -171,17 +174,3 @@ jobs:
# Don't read from the cache if the caller disabled it.
# https://docs.docker.com/engine/reference/commandline/buildx_build/#options
no-cache: ${{ inputs.no_cache }}
# To improve build speeds, for each branch we push an additional image to the registry,
# to be used as the caching layer, using the `max` caching mode.
#
# We use multiple cache sources to confirm a cache hit, starting from a per-branch cache.
# If there's no hit, we continue with a `main` branch cache, which helps us avoid
# rebuilding cargo-chef, most dependencies, and possibly some Zebra crates.
#
# The caches are tried in top-down order, the first available cache is used:
# https://github.com/moby/moby/pull/26839#issuecomment-277383550
cache-from: |
type=registry,ref=us-docker.pkg.dev/${{ vars.GCP_PROJECT }}/zebra-caching/${{ inputs.image_name }}${{ inputs.tag_suffix }}:${{ env.GITHUB_REF_SLUG_URL }}-cache
type=registry,ref=us-docker.pkg.dev/${{ vars.GCP_PROJECT }}/zebra-caching/${{ inputs.image_name }}${{ inputs.tag_suffix }}:main-cache
cache-to: |
type=registry,ref=us-docker.pkg.dev/${{ vars.GCP_PROJECT }}/zebra-caching/${{ inputs.image_name }}${{ inputs.tag_suffix }}:${{ env.GITHUB_REF_SLUG_URL }}-cache,mode=max

View File

@ -239,7 +239,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -250,7 +250,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -415,7 +415,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.59",
"syn 2.0.60",
"which",
]
@ -811,7 +811,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -1072,14 +1072,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
name = "cxx"
version = "1.0.107"
version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe98ba1789d56fb3db3bee5e032774d4f421b685de7ba703643584ba24effbe"
checksum = "048948e14bc2c2652ec606c8e3bb913407f0187288fb351a0b2d972beaf12070"
dependencies = [
"cc",
"cxxbridge-flags",
@ -1089,31 +1089,31 @@ dependencies = [
[[package]]
name = "cxx-gen"
version = "0.7.117"
version = "0.7.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b629c0d006c7e44c1444dd17d18a458c9390d32276b758ac7abd21a75c99b0"
checksum = "383ecb9f96a536a1c7a2a61c5786f583da84f9240da149d78d005a4413c9a71e"
dependencies = [
"codespan-reporting",
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.107"
version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20888d9e1d2298e2ff473cee30efe7d5036e437857ab68bbfea84c74dba91da2"
checksum = "af40b0467c68d3d9fb7550ef984edc8ad47252f703ef0f1f2d1052e0e4af8793"
[[package]]
name = "cxxbridge-macro"
version = "1.0.107"
version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fa16a70dd58129e4dfffdff535fb1bce66673f7bbeec4a5a1765a504e1ccd84"
checksum = "7743446286141c9f6d4497c493c01234eb848e14d2e20866ae9811eae0630cb9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -1161,7 +1161,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim 0.10.0",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -1183,7 +1183,7 @@ checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be"
dependencies = [
"darling_core 0.20.6",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -1256,7 +1256,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -1561,7 +1561,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -2629,7 +2629,7 @@ checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -3064,7 +3064,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -3105,7 +3105,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -3206,7 +3206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
dependencies = [
"proc-macro2",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -3329,7 +3329,7 @@ dependencies = [
"prost",
"prost-types",
"regex",
"syn 2.0.59",
"syn 2.0.60",
"tempfile",
"which",
]
@ -3344,7 +3344,7 @@ dependencies = [
"itertools 0.12.1",
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -3809,9 +3809,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.21.10"
version = "0.21.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4"
dependencies = [
"log",
"ring 0.17.8",
@ -4028,9 +4028,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.197"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
dependencies = [
"serde_derive",
]
@ -4046,20 +4046,20 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.197"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
name = "serde_json"
version = "1.0.115"
version = "1.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
dependencies = [
"indexmap 2.2.6",
"itoa",
@ -4137,7 +4137,7 @@ dependencies = [
"darling 0.20.6",
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -4366,9 +4366,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.59"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
@ -4452,29 +4452,29 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
name = "thread-priority"
version = "0.16.0"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a617e9eeeb20448b01a8e2427fb80dfbc9c49d79a1de3b11f25731edbf547e3c"
checksum = "599e8e829c2314b750ecade9309ecc6cf9a48c2e62fe25680b6c1d2172463ca3"
dependencies = [
"bitflags 2.5.0",
"cfg-if 1.0.0",
@ -4590,7 +4590,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -4774,7 +4774,7 @@ dependencies = [
"proc-macro2",
"prost-build",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -4787,7 +4787,7 @@ dependencies = [
"proc-macro2",
"prost-build",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -4917,7 +4917,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -5355,7 +5355,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
"wasm-bindgen-shared",
]
@ -5389,7 +5389,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -5670,9 +5670,9 @@ dependencies = [
[[package]]
name = "zcash_client_backend"
version = "0.10.0-rc.4"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc33f71747a93d509f7e1c047961e359a271bdf4869cc07f7f65ee1ba7df8c2"
checksum = "d6a382af39be9ee5a3788157145c404b7cd19acc440903f6c34b09fb44f0e991"
dependencies = [
"base64 0.21.7",
"bech32",
@ -5737,9 +5737,9 @@ dependencies = [
[[package]]
name = "zcash_primitives"
version = "0.13.0-rc.1"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc4391d9325e0a51a7cbff02b5c4b5472d66087bd9c903ddb12dea7ec22f3e0"
checksum = "d17e4c94ca8d69d2fcf2be97522da5732a580eb2125cda3b150761952f8df8e6"
dependencies = [
"aes",
"bip0039",
@ -5773,9 +5773,9 @@ dependencies = [
[[package]]
name = "zcash_proofs"
version = "0.13.0-rc.1"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48f22eff3bdc382327ef28f809024ddc89ec6d903ba71be629b2cbea34afdda2"
checksum = "df0c99f65a840ff256c106b28d67d702d9759d206112473d4982c92003262406"
dependencies = [
"bellman",
"blake2b_simd",
@ -5804,9 +5804,9 @@ dependencies = [
[[package]]
name = "zcash_script"
version = "0.1.14"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8deff8ea47cbe2a008abefedc1a2d9c0e48a87844379759ace270a0b53353c71"
checksum = "9e3de6aece21108f502f724183955d244e02338613eaa4f9010386c63618a3a8"
dependencies = [
"bellman",
"bindgen",
@ -6187,7 +6187,7 @@ dependencies = [
"serde_json",
"serde_yaml",
"structopt",
"syn 2.0.59",
"syn 2.0.60",
"thiserror",
"tinyvec",
"tokio",
@ -6288,7 +6288,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]
[[package]]
@ -6308,5 +6308,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
"syn 2.0.60",
]

View File

@ -68,7 +68,7 @@ Zebra is tested with the latest `stable` Rust version. Earlier versions are not
supported or tested. Any Zebra release can start depending on new features in the
latest stable Rust.
Every few weeks, we release a [new Zebra version](https://github.com/ZcashFoundation/zebra/releases).
Around every 4 weeks, we release a [new Zebra version](https://github.com/ZcashFoundation/zebra/releases).
Below are quick summaries for installing the dependencies on your machine.

View File

@ -33,7 +33,7 @@ The pre-release version is denoted by appending a hyphen and a series of dot sep
### Supported Releases
Every Zebra version released by the Zcash Foundation is supported up to a specific height. Currently we support each version for about **16 weeks** but this can change from release to release.
Every Zebra version released by the Zcash Foundation is supported up to a specific height. Currently we support each version for about **20 weeks** but this can change from release to release.
When the Zcash chain reaches this end of support height, `zebrad` will shut down and the binary will refuse to start.
@ -95,7 +95,7 @@ In general, expect the following release cycle:
* A major release for each network upgrade, whenever there are breaking changes to Zebra (by API, severe bugs or other kind of upgrades)
* Minor releases for significant new Zebra features or severe bug fixes
* A patch release every few weeks
* A patch release around every 4 weeks
This cadence of releases gives eager developers access to new features as soon as they are fully developed and pass through our code review and integration testing processes, while maintaining the stability and reliability of the platform for production users that prefer to receive features after they have been validated by Zcash and other developers that use the pre-release builds.

View File

@ -97,7 +97,7 @@ orchard = "0.6.0"
zcash_encoding = "0.2.0"
zcash_history = "0.4.0"
zcash_note_encryption = "0.4.0"
zcash_primitives = { version = "0.13.0-rc.1", features = ["transparent-inputs"] }
zcash_primitives = { version = "0.13.0", features = ["transparent-inputs"] }
# Time
chrono = { version = "0.4.38", default-features = false, features = ["clock", "std", "serde"] }
@ -106,12 +106,12 @@ humantime = "2.1.0"
# Error Handling & Formatting
displaydoc = "0.2.4"
static_assertions = "1.1.0"
thiserror = "1.0.58"
thiserror = "1.0.59"
tracing = "0.1.39"
# Serialization
hex = { version = "0.4.3", features = ["serde"] }
serde = { version = "1.0.196", features = ["serde_derive", "rc"] }
serde = { version = "1.0.198", features = ["serde_derive", "rc"] }
serde_with = "3.7.0"
serde-big-array = "0.5.1"
@ -126,7 +126,7 @@ redjubjub = "0.7.0"
reddsa = "0.5.1"
# Production feature json-conversion
serde_json = { version = "1.0.115", optional = true }
serde_json = { version = "1.0.116", optional = true }
# Production feature async-error and testing feature proptest-impl
tokio = { version = "1.37.0", optional = true }

View File

@ -25,6 +25,7 @@ mod header;
mod height;
mod serialize;
pub mod genesis;
pub mod merkle;
#[cfg(any(test, feature = "proptest-impl"))]

View File

@ -0,0 +1,19 @@
//! Regtest genesis block
use std::sync::Arc;
use hex::FromHex;
use crate::{block::Block, serialization::ZcashDeserializeInto};
/// Genesis block for Regtest, copied from zcashd via `getblock 0 0` RPC method
pub fn regtest_genesis_block() -> Arc<Block> {
let regtest_genesis_block_bytes =
<Vec<u8>>::from_hex(include_str!("genesis/block-regtest-0-000-000.txt").trim())
.expect("Block bytes are in valid hex representation");
regtest_genesis_block_bytes
.zcash_deserialize_into()
.map(Arc::new)
.expect("hard-coded Regtest genesis block data must deserialize successfully")
}

View File

@ -0,0 +1 @@
040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac40000000000000000000000000000000000000000000000000000000000000000dae5494d0f0f0f2009000000000000000000000000000000000000000000000000000000000000002401936b7db1eb4ac39f151b8704642d0a8bda13ec547d54cd5e43ba142fc6d8877cab07b30101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000

View File

@ -455,9 +455,15 @@ impl HistoryTree {
sapling_root: &sapling::tree::Root,
orchard_root: &orchard::tree::Root,
) -> Result<(), HistoryTreeError> {
let heartwood_height = NetworkUpgrade::Heartwood
.activation_height(network)
.expect("Heartwood height is known");
let Some(heartwood_height) = NetworkUpgrade::Heartwood.activation_height(network) else {
assert!(
self.0.is_none(),
"history tree must not exist pre-Heartwood"
);
return Ok(());
};
match block
.coinbase_height()
.expect("must have height")

View File

@ -11,6 +11,8 @@ use crate::{
parameters::NetworkUpgrade,
};
use self::testnet::ConfiguredActivationHeights;
pub mod testnet;
#[cfg(test)]
@ -138,15 +140,11 @@ impl fmt::Display for NetworkKind {
}
}
impl From<&Network> for &'static str {
fn from(network: &Network) -> &'static str {
impl<'a> From<&'a Network> for &'a str {
fn from(network: &'a Network) -> &'a str {
match network {
Network::Mainnet => "Mainnet",
// TODO:
// - Add a `name` field to use here instead of checking `is_default_testnet()`
// - zcashd calls the Regtest cache dir 'regtest' (#8327).
Network::Testnet(params) if params.is_default_testnet() => "Testnet",
Network::Testnet(_params) => "UnknownTestnet",
Network::Testnet(params) => params.network_name(),
}
}
}
@ -168,6 +166,11 @@ impl Network {
Self::Testnet(Arc::new(params))
}
/// Creates a new [`Network::Testnet`] with `Regtest` parameters and the provided network upgrade activation heights.
pub fn new_regtest(activation_heights: ConfiguredActivationHeights) -> Self {
Self::new_configured_testnet(testnet::Parameters::new_regtest(activation_heights))
}
/// Returns true if the network is the default Testnet, or false otherwise.
pub fn is_default_testnet(&self) -> bool {
if let Self::Testnet(params) = self {
@ -177,6 +180,23 @@ impl Network {
}
}
/// Returns true if the network is Regtest, or false otherwise.
pub fn is_regtest(&self) -> bool {
if let Self::Testnet(params) = self {
params.is_regtest()
} else {
false
}
}
/// Returns true if proof-of-work validation should be disabled for this network
pub fn disable_pow(&self) -> bool {
if let Self::Testnet(params) = self {
params.disable_pow()
} else {
false
}
}
/// Returns the [`NetworkKind`] for this network.
pub fn kind(&self) -> NetworkKind {
match self {

View File

@ -1,16 +1,40 @@
//! Types and implementation for Testnet consensus parameters
use std::collections::BTreeMap;
use std::{collections::BTreeMap, fmt};
use zcash_primitives::constants as zp_constants;
use crate::{
block::Height,
block::{self, Height},
parameters::{
network_upgrade::TESTNET_ACTIVATION_HEIGHTS, Network, NetworkUpgrade,
NETWORK_UPGRADES_IN_ORDER,
},
};
/// Reserved network names that should not be allowed for configured Testnets.
pub const RESERVED_NETWORK_NAMES: [&str; 6] = [
"Mainnet",
"Testnet",
"Regtest",
"MainnetKind",
"TestnetKind",
"RegtestKind",
];
/// Maximum length for a configured network name.
pub const MAX_NETWORK_NAME_LENGTH: usize = 30;
/// Maximum length for a configured human-readable prefix.
pub const MAX_HRP_LENGTH: usize = 30;
/// The block hash of the Regtest genesis block, `zcash-cli -regtest getblockhash 0`
const REGTEST_GENESIS_HASH: &str =
"029f11d80ef9765602235e1bc9727e3eb6ba20839319f761fee920d63401e327";
/// The block hash of the Testnet genesis block, `zcash-cli -testnet getblockhash 0`
const TESTNET_GENESIS_HASH: &str =
"05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38";
/// Configurable activation heights for Regtest and configured Testnets.
#[derive(Deserialize, Default)]
#[serde(rename_all = "PascalCase")]
@ -35,6 +59,10 @@ pub struct ConfiguredActivationHeights {
/// Builder for the [`Parameters`] struct.
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ParametersBuilder {
/// The name of this network to be used by the `Display` trait impl.
network_name: String,
/// The genesis block hash
genesis_hash: block::Hash,
/// The network upgrade activation heights for this network, see [`Parameters::activation_heights`] for more details.
activation_heights: BTreeMap<Height, NetworkUpgrade>,
/// Sapling extended spending key human-readable prefix for this network
@ -43,35 +71,108 @@ pub struct ParametersBuilder {
hrp_sapling_extended_full_viewing_key: String,
/// Sapling payment address human-readable prefix for this network
hrp_sapling_payment_address: String,
/// A flag for disabling proof-of-work checks when Zebra is validating blocks
disable_pow: bool,
}
impl Default for ParametersBuilder {
/// Creates a [`ParametersBuilder`] with all of the default Testnet parameters except `network_name`.
fn default() -> Self {
Self {
network_name: "UnknownTestnet".to_string(),
// # Correctness
//
// `Genesis` network upgrade activation height must always be 0
activation_heights: [
(Height(0), NetworkUpgrade::Genesis),
// TODO: Find out if `BeforeOverwinter` must always be active at Height(1), remove it here if it's not required.
(Height(1), NetworkUpgrade::BeforeOverwinter),
]
.into_iter()
.collect(),
activation_heights: TESTNET_ACTIVATION_HEIGHTS.iter().cloned().collect(),
hrp_sapling_extended_spending_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY.to_string(),
hrp_sapling_extended_full_viewing_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY.to_string(),
hrp_sapling_payment_address: zp_constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS
.to_string(),
genesis_hash: TESTNET_GENESIS_HASH
.parse()
.expect("hard-coded hash parses"),
disable_pow: false,
}
}
}
impl ParametersBuilder {
/// Sets the network name to be used in the [`Parameters`] being built.
pub fn with_network_name(mut self, network_name: impl fmt::Display) -> Self {
self.network_name = network_name.to_string();
assert!(
!RESERVED_NETWORK_NAMES.contains(&self.network_name.as_str()),
"cannot use reserved network name '{network_name}' as configured Testnet name, reserved names: {RESERVED_NETWORK_NAMES:?}"
);
assert!(
self.network_name.len() <= MAX_NETWORK_NAME_LENGTH,
"network name {network_name} is too long, must be {MAX_NETWORK_NAME_LENGTH} characters or less"
);
assert!(
self.network_name
.chars()
.all(|x| x.is_alphanumeric() || x == '_'),
"network name must include only alphanumeric characters or '_'"
);
self
}
/// Checks that the provided Sapling human-readable prefixes (HRPs) are valid and unique, then
/// sets the Sapling HRPs to be used in the [`Parameters`] being built.
pub fn with_sapling_hrps(
mut self,
hrp_sapling_extended_spending_key: impl fmt::Display,
hrp_sapling_extended_full_viewing_key: impl fmt::Display,
hrp_sapling_payment_address: impl fmt::Display,
) -> Self {
self.hrp_sapling_extended_spending_key = hrp_sapling_extended_spending_key.to_string();
self.hrp_sapling_extended_full_viewing_key =
hrp_sapling_extended_full_viewing_key.to_string();
self.hrp_sapling_payment_address = hrp_sapling_payment_address.to_string();
let sapling_hrps = [
&self.hrp_sapling_extended_spending_key,
&self.hrp_sapling_extended_full_viewing_key,
&self.hrp_sapling_payment_address,
];
for sapling_hrp in sapling_hrps {
assert!(sapling_hrp.len() <= MAX_HRP_LENGTH, "Sapling human-readable prefix {sapling_hrp} is too long, must be {MAX_HRP_LENGTH} characters or less");
assert!(
sapling_hrp.chars().all(|c| c.is_ascii_lowercase() || c == '-'),
"human-readable prefixes should contain only lowercase ASCII characters and dashes, hrp: {sapling_hrp}"
);
assert_eq!(
sapling_hrps
.iter()
.filter(|&&hrp| hrp == sapling_hrp)
.count(),
1,
"Sapling human-readable prefixes must be unique, repeated Sapling HRP: {sapling_hrp}"
);
}
self
}
/// Parses the hex-encoded block hash and sets it as the genesis hash in the [`Parameters`] being built.
pub fn with_genesis_hash(mut self, genesis_hash: impl fmt::Display) -> Self {
self.genesis_hash = genesis_hash
.to_string()
.parse()
.expect("configured genesis hash must parse");
self
}
/// Checks that the provided network upgrade activation heights are in the correct order, then
/// sets them as the new network upgrade activation heights.
pub fn activation_heights(
pub fn with_activation_heights(
mut self,
ConfiguredActivationHeights {
// TODO: Find out if `BeforeOverwinter` is required at Height(1), allow for
@ -99,7 +200,6 @@ impl ParametersBuilder {
.chain(heartwood.into_iter().map(|h| (h, Heartwood)))
.chain(canopy.into_iter().map(|h| (h, Canopy)))
.chain(nu5.into_iter().map(|h| (h, Nu5)))
.filter(|&(_, nu)| nu != NetworkUpgrade::BeforeOverwinter)
.map(|(h, nu)| (h.try_into().expect("activation height must be valid"), nu))
.collect();
@ -127,25 +227,38 @@ impl ParametersBuilder {
// # Correctness
//
// Height(0) must be reserved for the `NetworkUpgrade::Genesis`.
// TODO: Find out if `BeforeOverwinter` must always be active at Height(1), remove it here if it's not required.
self.activation_heights.split_off(&Height(2));
self.activation_heights.extend(activation_heights);
self
}
/// Sets the `disable_pow` flag to be used in the [`Parameters`] being built.
pub fn with_disable_pow(mut self, disable_pow: bool) -> Self {
self.disable_pow = disable_pow;
self
}
/// Converts the builder to a [`Parameters`] struct
pub fn finish(self) -> Parameters {
let Self {
network_name,
genesis_hash,
activation_heights,
hrp_sapling_extended_spending_key,
hrp_sapling_extended_full_viewing_key,
hrp_sapling_payment_address,
disable_pow,
} = self;
Parameters {
network_name,
genesis_hash,
activation_heights,
hrp_sapling_extended_spending_key,
hrp_sapling_extended_full_viewing_key,
hrp_sapling_payment_address,
disable_pow,
}
}
@ -158,6 +271,10 @@ impl ParametersBuilder {
/// Network consensus parameters for test networks such as Regtest and the default Testnet.
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Parameters {
/// The name of this network to be used by the `Display` trait impl.
network_name: String,
/// The genesis block hash
genesis_hash: block::Hash,
/// The network upgrade activation heights for this network.
///
/// Note: This value is ignored by `Network::activation_list()` when `zebra-chain` is
@ -170,19 +287,16 @@ pub struct Parameters {
hrp_sapling_extended_full_viewing_key: String,
/// Sapling payment address human-readable prefix for this network
hrp_sapling_payment_address: String,
/// A flag for disabling proof-of-work checks when Zebra is validating blocks
disable_pow: bool,
}
impl Default for Parameters {
/// Returns an instance of the default public testnet [`Parameters`].
fn default() -> Self {
Self {
activation_heights: TESTNET_ACTIVATION_HEIGHTS.iter().cloned().collect(),
hrp_sapling_extended_spending_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY.to_string(),
hrp_sapling_extended_full_viewing_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY.to_string(),
hrp_sapling_payment_address: zp_constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS
.to_string(),
network_name: "Testnet".to_string(),
..Self::build().finish()
}
}
}
@ -193,11 +307,63 @@ impl Parameters {
ParametersBuilder::default()
}
/// Accepts a [`ConfiguredActivationHeights`].
///
/// Creates an instance of [`Parameters`] with `Regtest` values.
pub fn new_regtest(activation_heights: ConfiguredActivationHeights) -> Self {
Self {
network_name: "Regtest".to_string(),
..Self::build()
.with_genesis_hash(REGTEST_GENESIS_HASH)
.with_disable_pow(true)
.with_sapling_hrps(
zp_constants::regtest::HRP_SAPLING_EXTENDED_SPENDING_KEY,
zp_constants::regtest::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
zp_constants::regtest::HRP_SAPLING_PAYMENT_ADDRESS,
)
// Removes default Testnet activation heights if not configured,
// most network upgrades are disabled by default for Regtest in zcashd
.with_activation_heights(activation_heights)
.finish()
}
}
/// Returns true if the instance of [`Parameters`] represents the default public Testnet.
pub fn is_default_testnet(&self) -> bool {
self == &Self::default()
}
/// Returns true if the instance of [`Parameters`] represents Regtest.
pub fn is_regtest(&self) -> bool {
let Self {
network_name,
genesis_hash,
// Activation heights are configurable on Regtest
activation_heights: _,
hrp_sapling_extended_spending_key,
hrp_sapling_extended_full_viewing_key,
hrp_sapling_payment_address,
disable_pow,
} = Self::new_regtest(ConfiguredActivationHeights::default());
self.network_name == network_name
&& self.genesis_hash == genesis_hash
&& self.hrp_sapling_extended_spending_key == hrp_sapling_extended_spending_key
&& self.hrp_sapling_extended_full_viewing_key == hrp_sapling_extended_full_viewing_key
&& self.hrp_sapling_payment_address == hrp_sapling_payment_address
&& self.disable_pow == disable_pow
}
/// Returns the network name
pub fn network_name(&self) -> &str {
&self.network_name
}
/// Returns the genesis hash
pub fn genesis_hash(&self) -> block::Hash {
self.genesis_hash
}
/// Returns the network upgrade activation heights
pub fn activation_heights(&self) -> &BTreeMap<Height, NetworkUpgrade> {
&self.activation_heights
@ -217,4 +383,9 @@ impl Parameters {
pub fn hrp_sapling_payment_address(&self) -> &str {
&self.hrp_sapling_payment_address
}
/// Returns true if proof-of-work validation should be disabled for this network
pub fn disable_pow(&self) -> bool {
self.disable_pow
}
}

View File

@ -1,12 +1,19 @@
//! Fixed test vectors for the network consensus parameters.
use zcash_primitives::consensus::{self as zp_consensus, Parameters};
use zcash_primitives::{
consensus::{self as zp_consensus, Parameters},
constants as zp_constants,
};
use crate::{
block::Height,
parameters::{
testnet::{self, ConfiguredActivationHeights},
Network, NetworkUpgrade, NETWORK_UPGRADES_IN_ORDER,
testnet::{
self, ConfiguredActivationHeights, MAX_HRP_LENGTH, MAX_NETWORK_NAME_LENGTH,
RESERVED_NETWORK_NAMES,
},
Network, NetworkUpgrade, MAINNET_ACTIVATION_HEIGHTS, NETWORK_UPGRADES_IN_ORDER,
TESTNET_ACTIVATION_HEIGHTS,
},
};
@ -91,13 +98,14 @@ fn check_parameters_impl() {
}
/// Checks that `NetworkUpgrade::activation_height()` returns the activation height of the next
/// network upgrade if it doesn't find an activation height for a prior network upgrade, and that the
/// `Genesis` upgrade is always at `Height(0)`.
/// network upgrade if it doesn't find an activation height for a prior network upgrade, that the
/// `Genesis` upgrade is always at `Height(0)`, and that the default Mainnet/Testnet/Regtest activation
/// heights are what's expected.
#[test]
fn activates_network_upgrades_correctly() {
let expected_activation_height = 1;
let network = testnet::Parameters::build()
.activation_heights(ConfiguredActivationHeights {
.with_activation_heights(ConfiguredActivationHeights {
nu5: Some(expected_activation_height),
..Default::default()
})
@ -124,4 +132,219 @@ fn activates_network_upgrades_correctly() {
should match NU5 activation height, network_upgrade: {nu}, activation_height: {activation_height:?}"
);
}
let expected_default_regtest_activation_heights = &[
(Height(0), NetworkUpgrade::Genesis),
(Height(1), NetworkUpgrade::BeforeOverwinter),
];
for (network, expected_activation_heights) in [
(Network::Mainnet, MAINNET_ACTIVATION_HEIGHTS),
(Network::new_default_testnet(), TESTNET_ACTIVATION_HEIGHTS),
(
Network::new_regtest(Default::default()),
expected_default_regtest_activation_heights,
),
] {
assert_eq!(
network.activation_list(),
expected_activation_heights.iter().cloned().collect(),
"network activation list should match expected activation heights"
);
}
}
/// Checks that configured testnet names are validated and used correctly.
#[test]
fn check_configured_network_name() {
// Sets a no-op panic hook to avoid long output.
std::panic::set_hook(Box::new(|_| {}));
// Checks that reserved network names cannot be used for configured testnets.
for reserved_network_name in RESERVED_NETWORK_NAMES {
std::panic::catch_unwind(|| {
testnet::Parameters::build().with_network_name(reserved_network_name)
})
.expect_err("should panic when attempting to set network name as a reserved name");
}
// Check that max length is enforced, and that network names may only contain alphanumeric characters and '_'.
for invalid_network_name in [
"a".repeat(MAX_NETWORK_NAME_LENGTH + 1),
"!!!!non-alphanumeric-name".to_string(),
] {
std::panic::catch_unwind(|| {
testnet::Parameters::build().with_network_name(invalid_network_name)
})
.expect_err("should panic when setting network name that's too long or contains non-alphanumeric characters (except '_')");
}
drop(std::panic::take_hook());
// Checks that network names are displayed correctly
assert_eq!(
Network::new_default_testnet().to_string(),
"Testnet",
"default testnet should be displayed as 'Testnet'"
);
assert_eq!(
Network::Mainnet.to_string(),
"Mainnet",
"Mainnet should be displayed as 'Mainnet'"
);
assert_eq!(
Network::new_regtest(Default::default()).to_string(),
"Regtest",
"Regtest should be displayed as 'Regtest'"
);
// Check that network name can contain alphanumeric characters and '_'.
let expected_name = "ConfiguredTestnet_1";
let network = testnet::Parameters::build()
// Check that network name can contain `MAX_NETWORK_NAME_LENGTH` characters
.with_network_name("a".repeat(MAX_NETWORK_NAME_LENGTH))
.with_network_name(expected_name)
.to_network();
// Check that configured network name is displayed
assert_eq!(
network.to_string(),
expected_name,
"network must be displayed as configured network name"
);
}
/// Checks that configured Sapling human-readable prefixes (HRPs) are validated and used correctly.
#[test]
fn check_configured_sapling_hrps() {
// Sets a no-op panic hook to avoid long output.
std::panic::set_hook(Box::new(|_| {}));
// Check that configured Sapling HRPs must be unique.
std::panic::catch_unwind(|| {
testnet::Parameters::build().with_sapling_hrps("", "", "");
})
.expect_err("should panic when setting non-unique Sapling HRPs");
// Check that max length is enforced, and that network names may only contain lowecase ASCII characters and dashes.
for invalid_hrp in [
"a".repeat(MAX_NETWORK_NAME_LENGTH + 1),
"!!!!non-alphabetical-name".to_string(),
"A".to_string(),
] {
std::panic::catch_unwind(|| {
testnet::Parameters::build().with_sapling_hrps(invalid_hrp, "dummy-hrp-a", "dummy-hrp-b");
})
.expect_err("should panic when setting Sapling HRPs that are too long or contain non-alphanumeric characters (except '-')");
}
drop(std::panic::take_hook());
// Check that Sapling HRPs can contain lowercase ascii characters and dashes.
let expected_hrp_sapling_extended_spending_key = "sapling-hrp-a";
let expected_hrp_sapling_extended_full_viewing_key = "sapling-hrp-b";
let expected_hrp_sapling_payment_address = "sapling-hrp-c";
let network = testnet::Parameters::build()
// Check that Sapling HRPs can contain `MAX_HRP_LENGTH` characters
.with_sapling_hrps("a".repeat(MAX_HRP_LENGTH), "dummy-hrp-a", "dummy-hrp-b")
.with_sapling_hrps(
expected_hrp_sapling_extended_spending_key,
expected_hrp_sapling_extended_full_viewing_key,
expected_hrp_sapling_payment_address,
)
.to_network();
// Check that configured Sapling HRPs are returned by `Parameters` trait methods
assert_eq!(
network.hrp_sapling_extended_spending_key(),
expected_hrp_sapling_extended_spending_key,
"should return expected Sapling extended spending key HRP"
);
assert_eq!(
network.hrp_sapling_extended_full_viewing_key(),
expected_hrp_sapling_extended_full_viewing_key,
"should return expected Sapling EFVK HRP"
);
assert_eq!(
network.hrp_sapling_payment_address(),
expected_hrp_sapling_payment_address,
"should return expected Sapling payment address HRP"
);
// Check that default Mainnet, Testnet, and Regtest HRPs are valid, these calls will panic
// if any of the values fail validation.
testnet::Parameters::build()
.with_sapling_hrps(
zp_constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY,
zp_constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
zp_constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS,
)
.with_sapling_hrps(
zp_constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY,
zp_constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
zp_constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS,
)
.with_sapling_hrps(
zp_constants::regtest::HRP_SAPLING_EXTENDED_SPENDING_KEY,
zp_constants::regtest::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
zp_constants::regtest::HRP_SAPLING_PAYMENT_ADDRESS,
);
}
/// Checks that configured testnet names are validated and used correctly.
#[test]
fn check_network_name() {
// Sets a no-op panic hook to avoid long output.
std::panic::set_hook(Box::new(|_| {}));
// Checks that reserved network names cannot be used for configured testnets.
for reserved_network_name in RESERVED_NETWORK_NAMES {
std::panic::catch_unwind(|| {
testnet::Parameters::build().with_network_name(reserved_network_name)
})
.expect_err("should panic when attempting to set network name as a reserved name");
}
// Check that max length is enforced, and that network names may only contain alphanumeric characters and '_'.
for invalid_network_name in [
"a".repeat(MAX_NETWORK_NAME_LENGTH + 1),
"!!!!non-alphanumeric-name".to_string(),
] {
std::panic::catch_unwind(|| {
testnet::Parameters::build().with_network_name(invalid_network_name)
})
.expect_err("should panic when setting network name that's too long or contains non-alphanumeric characters (except '_')");
}
drop(std::panic::take_hook());
// Checks that network names are displayed correctly
assert_eq!(
Network::new_default_testnet().to_string(),
"Testnet",
"default testnet should be displayed as 'Testnet'"
);
assert_eq!(
Network::Mainnet.to_string(),
"Mainnet",
"Mainnet should be displayed as 'Mainnet'"
);
// TODO: Check Regtest
// Check that network name can contain alphanumeric characters and '_'.
let expected_name = "ConfiguredTestnet_1";
let network = testnet::Parameters::build()
// Check that network name can contain `MAX_NETWORK_NAME_LENGTH` characters
.with_network_name("a".repeat(MAX_NETWORK_NAME_LENGTH))
.with_network_name(expected_name)
.to_network();
// Check that configured network name is displayed
assert_eq!(
network.to_string(),
expected_name,
"network must be displayed as configured network name"
);
}

View File

@ -10,7 +10,7 @@ impl Arbitrary for equihash::Solution {
.prop_map(|v| {
let mut bytes = [0; equihash::SOLUTION_SIZE];
bytes.copy_from_slice(v.as_slice());
Self(bytes)
Self::Common(bytes)
})
.boxed()
}

View File

@ -29,16 +29,26 @@ pub struct SolverCancelled;
/// The size of an Equihash solution in bytes (always 1344).
pub(crate) const SOLUTION_SIZE: usize = 1344;
/// The size of an Equihash solution in bytes on Regtest (always 36).
pub(crate) const REGTEST_SOLUTION_SIZE: usize = 36;
/// Equihash Solution in compressed format.
///
/// A wrapper around [u8; 1344] because Rust doesn't implement common
/// traits like `Debug`, `Clone`, etc for collections like array
/// beyond lengths 0 to 32.
/// A wrapper around `[u8; n]` where `n` is the solution size because
/// Rust doesn't implement common traits like `Debug`, `Clone`, etc.
/// for collections like arrays beyond lengths 0 to 32.
///
/// The size of an Equihash solution in bytes is always 1344 so the
/// length of this type is fixed.
/// The size of an Equihash solution in bytes is always 1344 on Mainnet and Testnet, and
/// is always 36 on Regtest so the length of this type is fixed.
#[derive(Deserialize, Serialize)]
pub struct Solution(#[serde(with = "BigArray")] pub [u8; SOLUTION_SIZE]);
// It's okay to use the extra space on Regtest
#[allow(clippy::large_enum_variant)]
pub enum Solution {
/// Equihash solution on Mainnet or Testnet
Common(#[serde(with = "BigArray")] [u8; SOLUTION_SIZE]),
/// Equihash solution on Regtest
Regtest(#[serde(with = "BigArray")] [u8; REGTEST_SOLUTION_SIZE]),
}
impl Solution {
/// The length of the portion of the header used as input when verifying
@ -48,15 +58,24 @@ impl Solution {
/// to the verification function.
pub const INPUT_LENGTH: usize = 4 + 32 * 3 + 4 * 2;
/// Returns the inner value of the [`Solution`] as a byte slice.
fn value(&self) -> &[u8] {
match self {
Solution::Common(solution) => solution.as_slice(),
Solution::Regtest(solution) => solution.as_slice(),
}
}
/// Returns `Ok(())` if `EquihashSolution` is valid for `header`
#[allow(clippy::unwrap_in_result)]
pub fn check(&self, header: &Header) -> Result<(), Error> {
let n = 200;
let k = 9;
let nonce = &header.nonce;
let solution = &self.0;
let mut input = Vec::new();
let (solution, n, k) = match self {
Solution::Common(solution) => (solution.as_slice(), 200, 9),
Solution::Regtest(solution) => (solution.as_slice(), 48, 5),
};
let mut input = Vec::new();
header
.zcash_serialize(&mut input)
.expect("serialization into a vec can't fail");
@ -73,23 +92,29 @@ impl Solution {
/// Returns a [`Solution`] containing the bytes from `solution`.
/// Returns an error if `solution` is the wrong length.
pub fn from_bytes(solution: &[u8]) -> Result<Self, SerializationError> {
if solution.len() != SOLUTION_SIZE {
return Err(SerializationError::Parse(
match solution.len() {
// Won't panic, because we just checked the length.
SOLUTION_SIZE => {
let mut bytes = [0; SOLUTION_SIZE];
bytes.copy_from_slice(solution);
Ok(Self::Common(bytes))
}
REGTEST_SOLUTION_SIZE => {
let mut bytes = [0; REGTEST_SOLUTION_SIZE];
bytes.copy_from_slice(solution);
Ok(Self::Regtest(bytes))
}
_unexpected_len => Err(SerializationError::Parse(
"incorrect equihash solution size",
));
)),
}
let mut bytes = [0; SOLUTION_SIZE];
// Won't panic, because we just checked the length.
bytes.copy_from_slice(solution);
Ok(Self(bytes))
}
/// Returns a [`Solution`] of `[0; SOLUTION_SIZE]` to be used in block proposals.
#[cfg(feature = "getblocktemplate-rpcs")]
pub fn for_proposal() -> Self {
Self([0; SOLUTION_SIZE])
// TODO: Accept network as an argument, and if it's Regtest, return the shorter null solution.
Self::Common([0; SOLUTION_SIZE])
}
/// Mines and returns one or more [`Solution`]s based on a template `header`.
@ -126,14 +151,14 @@ impl Solution {
impl PartialEq<Solution> for Solution {
fn eq(&self, other: &Solution) -> bool {
self.0.as_ref() == other.0.as_ref()
self.value() == other.value()
}
}
impl fmt::Debug for Solution {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("EquihashSolution")
.field(&hex::encode(&self.0[..]))
.field(&hex::encode(self.value()))
.finish()
}
}
@ -153,13 +178,13 @@ impl Eq for Solution {}
#[cfg(any(test, feature = "proptest-impl"))]
impl Default for Solution {
fn default() -> Self {
Self([0; SOLUTION_SIZE])
Self::Common([0; SOLUTION_SIZE])
}
}
impl ZcashSerialize for Solution {
fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error> {
zcash_serialize_bytes(&self.0.to_vec(), writer)
zcash_serialize_bytes(&self.value().to_vec(), writer)
}
}

View File

@ -47,12 +47,12 @@ chrono = { version = "0.4.38", default-features = false, features = ["clock", "s
displaydoc = "0.2.4"
lazy_static = "1.4.0"
once_cell = "1.18.0"
serde = { version = "1.0.196", features = ["serde_derive"] }
serde = { version = "1.0.198", features = ["serde_derive"] }
futures = "0.3.30"
futures-util = "0.3.28"
metrics = "0.22.3"
thiserror = "1.0.58"
thiserror = "1.0.59"
tokio = { version = "1.37.0", features = ["time", "sync", "tracing", "rt-multi-thread"] }
tower = { version = "0.4.13", features = ["timeout", "util", "buffer"] }
tracing = "0.1.39"

View File

@ -176,16 +176,18 @@ where
Err(BlockError::MaxHeight(height, hash, block::Height::MAX))?;
}
// > The block data MUST be validated and checked against the server's usual
// > acceptance rules (excluding the check for a valid proof-of-work).
// <https://en.bitcoin.it/wiki/BIP_0023#Block_Proposal>
if request.is_proposal() {
check::difficulty_threshold_is_valid(&block.header, &network, &height, &hash)?;
} else {
// Do the difficulty checks first, to raise the threshold for
// attacks that use any other fields.
check::difficulty_is_valid(&block.header, &network, &height, &hash)?;
check::equihash_solution_is_valid(&block.header)?;
if !network.disable_pow() {
// > The block data MUST be validated and checked against the server's usual
// > acceptance rules (excluding the check for a valid proof-of-work).
// <https://en.bitcoin.it/wiki/BIP_0023#Block_Proposal>
if request.is_proposal() {
check::difficulty_threshold_is_valid(&block.header, &network, &height, &hash)?;
} else {
// Do the difficulty checks first, to raise the threshold for
// attacks that use any other fields.
check::difficulty_is_valid(&block.header, &network, &height, &hash)?;
check::equihash_solution_is_valid(&block.header)?;
}
}
// Next, check the Merkle root validity, to ensure that

View File

@ -595,8 +595,10 @@ where
.ok_or(VerifyCheckpointError::CoinbaseHeight { hash })?;
self.check_height(height)?;
crate::block::check::difficulty_is_valid(&block.header, &self.network, &height, &hash)?;
crate::block::check::equihash_solution_is_valid(&block.header)?;
if !self.network.disable_pow() {
crate::block::check::difficulty_is_valid(&block.header, &self.network, &height, &hash)?;
crate::block::check::equihash_solution_is_valid(&block.header)?;
}
// don't do precalculation until the block passes basic difficulty checks
let block = CheckpointVerifiedBlock::with_hash(block, hash);

View File

@ -55,41 +55,60 @@ impl ParameterCheckpoint for Network {
fn genesis_hash(&self) -> zebra_chain::block::Hash {
match self {
// zcash-cli getblockhash 0
Network::Mainnet => "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08",
// zcash-cli -testnet getblockhash 0
// TODO: Add a `genesis_hash` field to `testnet::Parameters` and return it here (#8366)
Network::Testnet(_params) => {
"05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38"
}
Network::Mainnet => "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08"
.parse()
.expect("hard-coded hash parses"),
// See `zebra_chain::parameters::network::testnet` for more details.
Network::Testnet(params) => params.genesis_hash(),
}
.parse()
.expect("hard-coded hash parses")
}
fn checkpoint_list(&self) -> CheckpointList {
// parse calls CheckpointList::from_list
// TODO:
// - Add a `genesis_hash` field to `testnet::Parameters` and return it here (#8366)
// - Try to disable checkpoints entirely for regtest and custom testnets
let checkpoint_list: CheckpointList = match self {
Network::Mainnet => MAINNET_CHECKPOINTS
.parse()
.expect("Hard-coded Mainnet checkpoint list parses and validates"),
Network::Testnet(_params) => TESTNET_CHECKPOINTS
.parse()
.expect("Hard-coded Testnet checkpoint list parses and validates"),
let (checkpoints_for_network, should_fallback_to_genesis_hash_as_checkpoint) = match self {
Network::Mainnet => (MAINNET_CHECKPOINTS, false),
Network::Testnet(params) if params.is_default_testnet() => (TESTNET_CHECKPOINTS, false),
Network::Testnet(_params) => (TESTNET_CHECKPOINTS, true),
};
match checkpoint_list.hash(block::Height(0)) {
Some(hash) if hash == self.genesis_hash() => checkpoint_list,
Some(_) => {
panic!("The hard-coded genesis checkpoint does not match the network genesis hash")
// Check that the list starts with the correct genesis block and parses checkpoint list.
let first_checkpoint_height = checkpoints_for_network
.lines()
.next()
.map(checkpoint_height_and_hash);
match first_checkpoint_height {
// parse calls CheckpointList::from_list
Some(Ok((block::Height(0), hash))) if hash == self.genesis_hash() => {
checkpoints_for_network
.parse()
.expect("hard-coded checkpoint list parses and validates")
}
None => unreachable!("Parser should have checked for a missing genesis checkpoint"),
_ if should_fallback_to_genesis_hash_as_checkpoint => {
CheckpointList::from_list([(block::Height(0), self.genesis_hash())])
.expect("hard-coded checkpoint list parses and validates")
}
Some(Ok((block::Height(0), _))) => {
panic!("the genesis checkpoint does not match the {self} genesis hash")
}
Some(Ok(_)) => panic!("checkpoints must start at the genesis block height 0"),
Some(Err(err)) => panic!("{err}"),
None => panic!(
"there must be at least one checkpoint on default networks, for the genesis block"
),
}
}
}
/// Parses a checkpoint to a [`block::Height`] and [`block::Hash`].
fn checkpoint_height_and_hash(checkpoint: &str) -> Result<(block::Height, block::Hash), BoxError> {
let fields = checkpoint.split(' ').collect::<Vec<_>>();
if let [height, hash] = fields[..] {
Ok((height.parse()?, hash.parse()?))
} else {
Err(format!("Invalid checkpoint format: expected 2 space-separated fields but found {}: '{checkpoint}'", fields.len()).into())
}
}
/// A list of block height and hash checkpoints.
///
/// Checkpoints should be chosen to avoid forks or chain reorganizations,
@ -115,12 +134,7 @@ impl FromStr for CheckpointList {
let mut checkpoint_list: Vec<(block::Height, block::Hash)> = Vec::new();
for checkpoint in s.lines() {
let fields = checkpoint.split(' ').collect::<Vec<_>>();
if let [height, hash] = fields[..] {
checkpoint_list.push((height.parse()?, hash.parse()?));
} else {
Err(format!("Invalid checkpoint format: expected 2 space-separated fields but found {}: '{checkpoint}'", fields.len()))?;
};
checkpoint_list.push(checkpoint_height_and_hash(checkpoint)?);
}
CheckpointList::from_list(checkpoint_list)
@ -146,17 +160,9 @@ impl CheckpointList {
let checkpoints: BTreeMap<block::Height, block::Hash> =
original_checkpoints.into_iter().collect();
// Check that the list starts with the correct genesis block
// Check that the list starts with _some_ genesis block
match checkpoints.iter().next() {
// TODO: If required (we may not need checkpoints at all in Regtest or custom testnets):
// move this check to `<Network as ParameterCheckpoint>::checkpoint_list(&network)` method above (#8366),
// See <https://github.com/ZcashFoundation/zebra/pull/7924#discussion_r1385865347>
Some((block::Height(0), hash))
if (hash == &Network::Mainnet.genesis_hash()
|| hash == &Network::new_default_testnet().genesis_hash()) => {}
Some((block::Height(0), _)) => {
Err("the genesis checkpoint does not match the Mainnet or Testnet genesis hash")?
}
Some((block::Height(0), _hash)) => {}
Some(_) => Err("checkpoints must start at the genesis block height 0")?,
None => Err("there must be at least one checkpoint, for the genesis block")?,
};

View File

@ -237,6 +237,7 @@ fn checkpoint_list_load_hard_coded() -> Result<(), BoxError> {
let _ = Mainnet.checkpoint_list();
let _ = Network::new_default_testnet().checkpoint_list();
let _ = Network::new_regtest(Default::default()).checkpoint_list();
Ok(())
}

View File

@ -20,13 +20,13 @@ futures-util = "0.3.28"
tonic = "0.11.0"
tonic-reflection = "0.11.0"
prost = "0.12.4"
serde = { version = "1.0.196", features = ["serde_derive"] }
serde = { version = "1.0.198", features = ["serde_derive"] }
tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread"] }
tokio-stream = "0.1.15"
tower = { version = "0.4.13", features = ["util", "buffer"] }
color-eyre = "0.6.3"
zcash_primitives = { version = "0.13.0-rc.1" }
zcash_primitives = { version = "0.13.0" }
zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36", features = ["shielded-scan"] }
zebra-chain = { path = "../zebra-chain" , version = "1.0.0-beta.36" }

View File

@ -56,9 +56,9 @@ pin-project = "1.1.5"
rand = "0.8.5"
rayon = "1.10.0"
regex = "1.10.4"
serde = { version = "1.0.196", features = ["serde_derive"] }
serde = { version = "1.0.198", features = ["serde_derive"] }
tempfile = "3.10.1"
thiserror = "1.0.58"
thiserror = "1.0.59"
futures = "0.3.30"
tokio = { version = "1.37.0", features = ["fs", "io-util", "net", "time", "tracing", "macros", "rt-multi-thread"] }

View File

@ -629,8 +629,8 @@ impl<'de> Deserialize<'de> for Config {
{
#[derive(Deserialize)]
struct DTestnetParameters {
#[serde(default)]
pub(super) activation_heights: ConfiguredActivationHeights,
network_name: Option<String>,
activation_heights: Option<ConfiguredActivationHeights>,
}
#[derive(Deserialize)]
@ -639,6 +639,7 @@ impl<'de> Deserialize<'de> for Config {
listen_addr: String,
network: NetworkKind,
testnet_parameters: Option<DTestnetParameters>,
regtest_activation_heights: ConfiguredActivationHeights,
initial_mainnet_peers: IndexSet<String>,
initial_testnet_peers: IndexSet<String>,
cache_dir: CacheDir,
@ -655,6 +656,7 @@ impl<'de> Deserialize<'de> for Config {
listen_addr: "0.0.0.0".to_string(),
network: Default::default(),
testnet_parameters: None,
regtest_activation_heights: ConfiguredActivationHeights::default(),
initial_mainnet_peers: config.initial_mainnet_peers,
initial_testnet_peers: config.initial_testnet_peers,
cache_dir: config.cache_dir,
@ -669,6 +671,7 @@ impl<'de> Deserialize<'de> for Config {
listen_addr,
network: network_kind,
testnet_parameters,
regtest_activation_heights,
initial_mainnet_peers,
initial_testnet_peers,
cache_dir,
@ -677,23 +680,55 @@ impl<'de> Deserialize<'de> for Config {
max_connections_per_ip,
} = DConfig::deserialize(deserializer)?;
// TODO: Panic here if the initial testnet peers are the default initial testnet peers.
let network = if let Some(DTestnetParameters { activation_heights }) = testnet_parameters {
assert_eq!(
network_kind,
NetworkKind::Testnet,
"set network to 'Testnet' to use configured testnet parameters"
);
/// Accepts an [`IndexSet`] of initial peers,
///
/// Returns true if any of them are the default Testnet or Mainnet initial peers.
fn contains_default_initial_peers(initial_peers: &IndexSet<String>) -> bool {
let Config {
initial_mainnet_peers: mut default_initial_peers,
initial_testnet_peers: default_initial_testnet_peers,
..
} = Config::default();
default_initial_peers.extend(default_initial_testnet_peers);
testnet::Parameters::build()
.activation_heights(activation_heights)
.to_network()
} else {
// Convert to default `Network` for a `NetworkKind` if there are no testnet parameters.
match network_kind {
NetworkKind::Mainnet => Network::Mainnet,
NetworkKind::Testnet => Network::new_default_testnet(),
NetworkKind::Regtest => unimplemented!("Regtest is not yet implemented in Zebra"),
initial_peers
.intersection(&default_initial_peers)
.next()
.is_some()
}
let network = match (network_kind, testnet_parameters) {
(NetworkKind::Mainnet, _) => Network::Mainnet,
(NetworkKind::Testnet, None) => Network::new_default_testnet(),
(NetworkKind::Regtest, _) => Network::new_regtest(regtest_activation_heights),
(
NetworkKind::Testnet,
Some(DTestnetParameters {
network_name,
activation_heights,
}),
) => {
let mut params_builder = testnet::Parameters::build();
if let Some(network_name) = network_name {
params_builder = params_builder.with_network_name(network_name)
}
// Retain default Testnet activation heights unless there's an empty [testnet_parameters.activation_heights] section.
if let Some(activation_heights) = activation_heights {
// Return an error if the initial testnet peers includes any of the default initial Mainnet or Testnet
// peers while activation heights are configured.
// TODO: Check that the network magic is different from the default Mainnet/Testnet network magic too?
if contains_default_initial_peers(&initial_testnet_peers) {
return Err(de::Error::custom(
"cannot use default initial testnet peers with configured activation heights",
));
}
params_builder = params_builder.with_activation_heights(activation_heights)
}
params_builder.to_network()
}
};

View File

@ -46,8 +46,8 @@ color-eyre = { version = "0.6.3", optional = true }
jsonrpc-core = { version = "18.0.0", optional = true }
# Security: avoid default dependency on openssl
reqwest = { version = "0.11.26", default-features = false, features = ["rustls-tls"], optional = true }
serde = { version = "1.0.196", optional = true }
serde_json = { version = "1.0.115", optional = true }
serde = { version = "1.0.198", optional = true }
serde_json = { version = "1.0.116", optional = true }
tokio = { version = "1.37.0", features = ["time"], optional = true }
[dev-dependencies]
@ -55,5 +55,5 @@ tokio = { version = "1.37.0", features = ["time"], optional = true }
color-eyre = "0.6.3"
jsonrpc-core = "18.0.0"
reqwest = { version = "0.11.26", default-features = false, features = ["rustls-tls"] }
serde = "1.0.196"
serde_json = "1.0.115"
serde = "1.0.198"
serde_json = "1.0.116"

View File

@ -53,7 +53,7 @@ jsonrpc-derive = "18.0.0"
jsonrpc-http-server = "18.0.0"
# zebra-rpc needs the preserve_order feature in serde_json, which is a dependency of jsonrpc-core
serde_json = { version = "1.0.115", features = ["preserve_order"] }
serde_json = { version = "1.0.116", features = ["preserve_order"] }
indexmap = { version = "2.2.6", features = ["serde"] }
tokio = { version = "1.37.0", features = ["time", "rt-multi-thread", "macros", "tracing"] }
@ -62,7 +62,7 @@ tower = "0.4.13"
tracing = "0.1.39"
hex = { version = "0.4.3", features = ["serde"] }
serde = { version = "1.0.196", features = ["serde_derive"] }
serde = { version = "1.0.198", features = ["serde_derive"] }
# Experimental feature getblocktemplate-rpcs
rand = { version = "0.8.5", optional = true }
@ -84,7 +84,7 @@ insta = { version = "1.38.0", features = ["redactions", "json", "ron"] }
proptest = "1.4.0"
thiserror = "1.0.58"
thiserror = "1.0.59"
tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] }
zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["proptest-impl"] }

View File

@ -1098,6 +1098,11 @@ where
data: None,
})?;
// # Concurrency
//
// For consistency, this lookup must be performed first, then all the other
// lookups must be based on the hash.
// Fetch the block referenced by [`hash_or_height`] from the state.
// TODO: If this RPC is called a lot, just get the block header,
// rather than the whole block.
@ -1128,6 +1133,9 @@ where
_ => unreachable!("unmatched response to a block request"),
};
let hash = hash_or_height.hash().unwrap_or_else(|| block.hash());
let hash_or_height = hash.into();
// Fetch the Sapling & Orchard treestates referenced by
// [`hash_or_height`] from the state.
@ -1156,8 +1164,6 @@ where
// We've got all the data we need for the RPC response, so we
// assemble the response.
let hash = block.hash();
let height = block
.coinbase_height()
.expect("verified blocks have a valid height");

View File

@ -23,13 +23,14 @@ use super::super::*;
/// Test that the JSON-RPC server spawns when configured with a single thread.
#[test]
#[cfg(not(target_os = "windows"))]
fn rpc_server_spawn_single_thread() {
rpc_server_spawn(false)
}
/// Test that the JSON-RPC server spawns when configured with multiple threads.
#[test]
fn rpc_sever_spawn_parallel_threads() {
fn rpc_server_spawn_parallel_threads() {
rpc_server_spawn(true)
}

View File

@ -45,14 +45,14 @@ color-eyre = "0.6.3"
indexmap = { version = "2.2.6", features = ["serde"] }
itertools = "0.12.1"
semver = "1.0.22"
serde = { version = "1.0.196", features = ["serde_derive"] }
serde = { version = "1.0.198", features = ["serde_derive"] }
tokio = { version = "1.37.0", features = ["time"] }
tower = "0.4.13"
tracing = "0.1.39"
futures = "0.3.30"
zcash_client_backend = "0.10.0-rc.1"
zcash_primitives = "0.13.0-rc.1"
zcash_primitives = "0.13.0"
zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["shielded-scan"] }
zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36", features = ["shielded-scan"] }

View File

@ -15,11 +15,11 @@ keywords = ["zebra", "zcash"]
categories = ["api-bindings", "cryptography::cryptocurrencies"]
[dependencies]
zcash_script = "0.1.14"
zcash_script = "0.1.15"
zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36" }
thiserror = "1.0.58"
thiserror = "1.0.59"
displaydoc = "0.2.4"
[dev-dependencies]

View File

@ -63,9 +63,9 @@ regex = "1.10.4"
rlimit = "0.10.1"
rocksdb = { version = "0.22.0", default-features = false, features = ["lz4"] }
semver = "1.0.22"
serde = { version = "1.0.196", features = ["serde_derive"] }
serde = { version = "1.0.198", features = ["serde_derive"] }
tempfile = "3.10.1"
thiserror = "1.0.58"
thiserror = "1.0.59"
rayon = "1.10.0"
tokio = { version = "1.37.0", features = ["rt-multi-thread", "sync", "tracing"] }
@ -75,7 +75,7 @@ tracing = "0.1.39"
# elasticsearch specific dependencies.
# Security: avoid default dependency on openssl
elasticsearch = { version = "8.5.0-alpha.1", default-features = false, features = ["rustls-tls"], optional = true }
serde_json = { version = "1.0.115", package = "serde_json", optional = true }
serde_json = { version = "1.0.116", package = "serde_json", optional = true }
zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["async-error"] }

View File

@ -451,6 +451,7 @@ fn finalized_equals_pushed_history_tree() -> Result<()> {
/// Check that rejected blocks do not change the internal state of a genesis chain
/// in a non-finalized state.
#[test]
#[cfg(not(target_os = "windows"))]
fn rejection_restores_internal_state_genesis() -> Result<()> {
let _init_guard = zebra_test::init();

View File

@ -37,7 +37,7 @@ tinyvec = { version = "1.6.0", features = ["rustc_1_55"] }
humantime = "2.1.0"
owo-colors = "4.0.0"
spandoc = "0.2.2"
thiserror = "1.0.58"
thiserror = "1.0.59"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-error = "0.2.0"

View File

@ -95,10 +95,10 @@ tinyvec = { version = "1.6.0", features = ["rustc_1_55"] }
structopt = "0.3.26"
hex = "0.4.3"
serde_json = "1.0.115"
serde_json = "1.0.116"
tracing-error = "0.2.0"
tracing-subscriber = "0.3.18"
thiserror = "1.0.58"
thiserror = "1.0.59"
zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36" }
zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36" }
@ -120,11 +120,11 @@ tokio = { version = "1.37.0", features = ["full"], optional = true }
jsonrpc = { version = "0.18.0", optional = true }
zcash_primitives = { version = "0.13.0-rc.1", optional = true }
zcash_primitives = { version = "0.13.0", optional = true }
zcash_client_backend = {version = "0.10.0-rc.1", optional = true}
# For the openapi generator
syn = { version = "2.0.58", features = ["full"], optional = true }
syn = { version = "2.0.60", features = ["full"], optional = true }
quote = { version = "1.0.36", optional = true }
serde_yaml = { version = "0.9.34+deprecated", optional = true }
serde = { version = "1.0.196", features = ["serde_derive"], optional = true }
serde = { version = "1.0.198", features = ["serde_derive"], optional = true }

View File

@ -178,7 +178,7 @@ humantime-serde = "1.1.1"
indexmap = "2.2.6"
lazy_static = "1.4.0"
semver = "1.0.22"
serde = { version = "1.0.196", features = ["serde_derive"] }
serde = { version = "1.0.198", features = ["serde_derive"] }
toml = "0.8.11"
futures = "0.3.30"
@ -193,7 +193,7 @@ color-eyre = { version = "0.6.3", default-features = false, features = ["issue-u
# Enable a feature that makes tinyvec compile much faster.
tinyvec = { version = "1.6.0", features = ["rustc_1_55"] }
thiserror = "1.0.58"
thiserror = "1.0.59"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-appender = "0.2.3"
@ -210,7 +210,7 @@ num-integer = "0.1.46"
rand = "0.8.5"
# prod feature internal-miner
thread-priority = { version = "0.16.0", optional = true }
thread-priority = { version = "1.0.0", optional = true }
# prod feature sentry
sentry = { version = "0.32.2", default-features = false, features = ["backtrace", "contexts", "reqwest", "rustls", "tracing"], optional = true }
@ -261,7 +261,7 @@ regex = "1.10.4"
insta = { version = "1.38.0", features = ["json"] }
# zebra-rpc needs the preserve_order feature, it also makes test results more stable
serde_json = { version = "1.0.115", features = ["preserve_order"] }
serde_json = { version = "1.0.116", features = ["preserve_order"] }
tempfile = "3.10.1"
hyper = { version = "0.14.28", features = ["http1", "http2", "server"]}

View File

@ -22,7 +22,8 @@ pub const ESTIMATED_RELEASE_HEIGHT: u32 = 2_471_000;
///
/// - Zebra will exit with a panic if the current tip height is bigger than the `ESTIMATED_RELEASE_HEIGHT`
/// plus this number of days.
pub const EOS_PANIC_AFTER: u32 = 112;
/// - Currently set to 20 weeks.
pub const EOS_PANIC_AFTER: u32 = 140;
/// The number of days before the end of support where Zebra will display warnings.
pub const EOS_WARN_AFTER: u32 = EOS_PANIC_AFTER - 14;

View File

@ -161,10 +161,12 @@ use color_eyre::{
use semver::Version;
use serde_json::Value;
use tower::ServiceExt;
use zebra_chain::{
block::{self, Height},
block::{self, genesis::regtest_genesis_block, Height},
parameters::Network::{self, *},
};
use zebra_consensus::ParameterCheckpoint;
use zebra_network::constants::PORT_IN_USE_ERROR;
use zebra_node_services::rpc_client::RpcRequestClient;
use zebra_state::{constants::LOCK_FILE_ERROR, state_database_format_version_in_code};
@ -622,6 +624,7 @@ fn config_tests() -> Result<()> {
invalid_generated_config()?;
// Check that we have a current version of the config stored
#[cfg(not(target_os = "windows"))]
last_config_is_stored()?;
// Check that Zebra's previous configurations still work
@ -1756,7 +1759,7 @@ fn non_blocking_logger() -> Result<()> {
});
// Wait until the spawned task finishes up to 45 seconds before shutting down tokio runtime
if done_rx.recv_timeout(Duration::from_secs(45)).is_ok() {
if done_rx.recv_timeout(Duration::from_secs(90)).is_ok() {
rt.shutdown_timeout(Duration::from_secs(3));
}
@ -3098,3 +3101,29 @@ fn scan_start_where_left() -> Result<()> {
async fn scan_task_commands() -> Result<()> {
common::shielded_scan::scan_task_commands::run().await
}
/// Checks that the Regtest genesis block can be validated.
#[tokio::test]
async fn validate_regtest_genesis_block() {
let _init_guard = zebra_test::init();
let network = Network::new_regtest(Default::default());
let state = zebra_state::init_test(&network);
let (
block_verifier_router,
_transaction_verifier,
_parameter_download_task_handle,
_max_checkpoint_height,
) = zebra_consensus::router::init(zebra_consensus::Config::default(), &network, state).await;
let genesis_hash = block_verifier_router
.oneshot(zebra_consensus::Request::Commit(regtest_genesis_block()))
.await
.expect("should validate Regtest genesis block");
assert_eq!(
genesis_hash,
network.genesis_hash(),
"validated block hash should match network genesis hash"
)
}

View File

@ -57,9 +57,12 @@ initial_testnet_peers = [
]
listen_addr = "0.0.0.0:8233"
max_connections_per_ip = 1
network = "Testnet"
network = "Regtest"
peerset_initial_target_size = 25
[network.testnet_parameters]
network_name = "ConfiguredTestnet_1"
[network.testnet_parameters.activation_heights]
BeforeOverwinter = 1
Overwinter = 207_500
@ -69,6 +72,15 @@ Heartwood = 903_800
Canopy = 1_028_500
NU5 = 1_842_420
[network.regtest_activation_heights]
BeforeOverwinter = 1
Overwinter = 207_500
Sapling = 280_000
Blossom = 584_000
Heartwood = 903_800
Canopy = 1_028_500
NU5 = 1_842_420
[rpc]
debug_force_finished_sync = false
parallel_cpu_threads = 0