diff --git a/.github/workflows/ci-coverage.yml b/.github/workflows/ci-coverage.yml index 09077bbcb..f30bf1b56 100644 --- a/.github/workflows/ci-coverage.yml +++ b/.github/workflows/ci-coverage.yml @@ -103,4 +103,4 @@ jobs: run: cargo llvm-cov --lcov --no-run --output-path lcov.info - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v4.1.1 + uses: codecov/codecov-action@v4.3.0 diff --git a/.github/workflows/ci-lint.yml b/.github/workflows/ci-lint.yml index 59f113c87..b787f4bc8 100644 --- a/.github/workflows/ci-lint.yml +++ b/.github/workflows/ci-lint.yml @@ -44,7 +44,7 @@ jobs: - name: Rust files id: changed-files-rust - uses: tj-actions/changed-files@v44.0.0 + uses: tj-actions/changed-files@v44.0.1 with: files: | **/*.rs @@ -56,7 +56,7 @@ jobs: - name: Workflow files id: changed-files-workflows - uses: tj-actions/changed-files@v44.0.0 + uses: tj-actions/changed-files@v44.0.1 with: files: | .github/workflows/*.yml @@ -151,7 +151,7 @@ jobs: steps: - uses: actions/checkout@v4.1.2 - name: actionlint - uses: reviewdog/action-actionlint@v1.43.0 + uses: reviewdog/action-actionlint@v1.44.0 with: level: warning fail_on_error: false diff --git a/.github/workflows/ci-unit-tests-os.yml b/.github/workflows/ci-unit-tests-os.yml index 4a7bd5777..1d332e4d1 100644 --- a/.github/workflows/ci-unit-tests-os.yml +++ b/.github/workflows/ci-unit-tests-os.yml @@ -280,7 +280,7 @@ jobs: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=stable --profile=minimal - name: Install cargo-machete - uses: baptiste0928/cargo-install@v3.0.1 + uses: baptiste0928/cargo-install@v3.1.0 with: crate: cargo-machete diff --git a/.github/workflows/release-crates-io.yml b/.github/workflows/release-crates-io.yml index e1ea8e84a..d99869647 100644 --- a/.github/workflows/release-crates-io.yml +++ b/.github/workflows/release-crates-io.yml @@ -85,7 +85,7 @@ jobs: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=stable --profile=minimal - name: Install cargo-release - uses: baptiste0928/cargo-install@v3.0.1 + uses: baptiste0928/cargo-install@v3.1.0 with: crate: cargo-release diff --git a/.github/workflows/scripts/release-crates-dry-run.sh b/.github/workflows/scripts/release-crates-dry-run.sh index cbae0ca35..df18df580 100755 --- a/.github/workflows/scripts/release-crates-dry-run.sh +++ b/.github/workflows/scripts/release-crates-dry-run.sh @@ -23,8 +23,8 @@ fi cargo release version --verbose --execute --no-confirm --allow-branch '*' --workspace --exclude zebrad --exclude zebra-scan --exclude zebra-grpc beta # Due to a bug in cargo-release, we need to pass exact versions for alpha crates: -cargo release version --verbose --execute --no-confirm --allow-branch '*' --package zebra-scan 0.1.0-alpha.5 -cargo release version --verbose --execute --no-confirm --allow-branch '*' --package zebra-grpc 0.1.0-alpha.3 +cargo release version --verbose --execute --no-confirm --allow-branch '*' --package zebra-scan 0.1.0-alpha.6 +cargo release version --verbose --execute --no-confirm --allow-branch '*' --package zebra-grpc 0.1.0-alpha.4 # Update zebrad: cargo release version --verbose --execute --no-confirm --allow-branch '*' --package zebrad patch diff --git a/CHANGELOG.md b/CHANGELOG.md index bddc43ed7..c7be5e942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,19 +5,34 @@ All notable changes to Zebra are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org). -## Unreleased +## [Zebra 1.6.1](https://github.com/ZcashFoundation/zebra/releases/tag/v1.6.1) - 2024-04-15 -### Added -- `zebra_chain::Network` methods: - - `b58_pubkey_address_prefix`, `b58_script_address_prefix`, `num_funding_streams` +This release adds an OpenAPI specification for Zebra's RPC methods and startup logs about Zebra's storage usage and other database information. + +It also includes: +- Bug fixes and improved error messages for some zebra-scan gRPC methods +- A performance improvement in Zebra's `getblock` RPC method + +### Added + +- Log database information such as storage usage on startup and shutdown ([#8336](https://github.com/ZcashFoundation/zebra/pull/8336), [#8389](https://github.com/ZcashFoundation/zebra/pull/8389)) +- OpenAPI specification for Zebra's RPC methods ([#8342](https://github.com/ZcashFoundation/zebra/pull/8342)) +- Add block times to output of getblock RPC method when called with `verbosity = 2` ([#8384](https://github.com/ZcashFoundation/zebra/pull/8384)) ### Changed -- Functions that take a `zebra_chain::Network` as an argument have been moved to be methods of `Network`, including - - `zebra_chain::parameters`: - - `genesis::genesis_hash`, `NetworkUpgrade::activation_list`, `NetworkUpgrade::is_max_block_time_enforced`, - - `zebra_chain::work::difficulty::ExpandedDifficulty::target_difficutly_limit` - - `zebra_consensus::height_for_first_halving` - - `zebra_consensus::checkpoint::CheckpointList::new` (now `Network::checkpoint_list`) + +- Removed `Copy` trait impl for `Network` ([#8354](https://github.com/ZcashFoundation/zebra/pull/8354)) +- Refactored code for network consensus parameters to `Network` methods ([#8340](https://github.com/ZcashFoundation/zebra/pull/8340)) + +### Fixed + +- Improve zebra-scan gRPC method errors and add timeout to scan service to avoid hanging ([#8318](https://github.com/ZcashFoundation/zebra/pull/8318)) +- Await state service requests in `getblock` method in parallel ([#8376](https://github.com/ZcashFoundation/zebra/pull/8376)) + +### Contributors + +Thank you to everyone who contributed to this release, we couldn't make Zebra without you: +@arya2, @elijahhampton, @gustavovalverde, @idky137, @mpguerra, @oxarbitrage, @upbqdn and @zancas ## [Zebra 1.6.0](https://github.com/ZcashFoundation/zebra/releases/tag/v1.6.0) - 2024-02-23 diff --git a/Cargo.lock b/Cargo.lock index b7996d5f7..67eeac30a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,7 @@ dependencies = [ "arc-swap", "backtrace", "canonical-path", - "clap 4.5.3", + "clap 4.5.4", "color-eyre", "fs-err", "once_cell", @@ -239,7 +239,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -250,7 +250,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -402,7 +402,7 @@ version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cexpr", "clang-sys", "itertools 0.12.1", @@ -415,7 +415,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.53", + "syn 2.0.59", "which", ] @@ -456,9 +456,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitflags-serde-legacy" @@ -466,7 +466,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b64e60c28b6d25ad92e8b367801ff9aa12b41d05fc8798055d296bace4a60cc" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "serde", ] @@ -537,9 +537,9 @@ dependencies = [ [[package]] name = "bs58" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "sha2", "tinyvec", @@ -581,9 +581,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bzip2-sys" @@ -782,9 +782,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -804,14 +804,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -969,7 +969,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.3", + "clap 4.5.4", "criterion-plot", "is-terminal", "itertools 0.10.5", @@ -1072,7 +1072,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -1096,7 +1096,7 @@ dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -1113,7 +1113,7 @@ checksum = "7743446286141c9f6d4497c493c01234eb848e14d2e20866ae9811eae0630cb9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -1161,7 +1161,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -1183,7 +1183,7 @@ checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" dependencies = [ "darling_core 0.20.6", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -1256,7 +1256,16 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", +] + +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", ] [[package]] @@ -1413,9 +1422,9 @@ checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" [[package]] name = "fixed-hash" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", "rand 0.8.5", @@ -1552,7 +1561,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -1631,7 +1640,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "libgit2-sys", "log", @@ -1671,9 +1680,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1681,7 +1690,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.2.5", + "indexmap 2.2.6", "slab", "tokio", "tokio-util 0.7.10", @@ -1700,7 +1709,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.1.0", - "indexmap 2.2.5", + "indexmap 2.2.6", "slab", "tokio", "tokio-util 0.7.10", @@ -1990,7 +1999,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.24", + "h2 0.3.26", "http 0.2.11", "http-body 0.4.6", "httparse", @@ -2132,9 +2141,9 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361c467824d4d9d4f284be4b2608800839419dccc4d4608f28345237fe354623" +checksum = "eb1872810fb725b06b8c153dde9e86f3ec26747b9b60096da7a869883b549cbe" dependencies = [ "either", ] @@ -2158,9 +2167,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -2208,9 +2217,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.36.1" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7c22c4d34ef4788c351e971c52bfdfe7ea2766f8c5466bc175dd46e52ac22e" +checksum = "3eab73f58e59ca6526037208f0e98851159ec1633cf17b6cd2e1f2c3fd5d53cc" dependencies = [ "console", "lazy_static", @@ -2220,7 +2229,6 @@ dependencies = [ "ron", "serde", "similar", - "yaml-rust", ] [[package]] @@ -2293,9 +2301,9 @@ dependencies = [ [[package]] name = "jsonrpc" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26d9104d516092f092d97448787505881fdb6518293b2d6500bf9c180c839dd" +checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf" dependencies = [ "base64 0.13.1", "serde", @@ -2441,7 +2449,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall 0.4.1", ] @@ -2494,6 +2502,12 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.11" @@ -2597,7 +2611,7 @@ dependencies = [ "http-body-util", "hyper 1.2.0", "hyper-util", - "indexmap 2.2.5", + "indexmap 2.2.6", "ipnet", "metrics 0.22.3", "metrics-util", @@ -2615,7 +2629,7 @@ checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -3050,7 +3064,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -3071,7 +3085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.5", + "indexmap 2.2.6", ] [[package]] @@ -3091,7 +3105,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -3192,14 +3206,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] name = "primitive-types" -version = "0.11.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", @@ -3250,9 +3264,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e" dependencies = [ "unicode-ident", ] @@ -3265,7 +3279,7 @@ checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.2", + "bitflags 2.5.0", "lazy_static", "num-traits", "rand 0.8.5", @@ -3290,9 +3304,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", "prost-derive", @@ -3315,22 +3329,22 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.53", + "syn 2.0.59", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -3397,9 +3411,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -3496,14 +3510,14 @@ version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", ] [[package]] name = "rayon" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -3581,9 +3595,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -3635,7 +3649,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.3.24", + "h2 0.3.26", "http 0.2.11", "http-body 0.4.6", "hyper 0.14.28", @@ -3786,7 +3800,7 @@ version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -4038,16 +4052,16 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -4094,7 +4108,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.5", + "indexmap 2.2.6", "serde", "serde_derive", "serde_json", @@ -4123,16 +4137,16 @@ dependencies = [ "darling 0.20.6", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] name = "serde_yaml" -version = "0.9.33" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -4165,7 +4179,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19f96dde3a8693874f7e7c53d95616569b4009379a903789efbd448f4ea9cc7" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "either", "incrementalmerkletree", "tracing", @@ -4352,9 +4366,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" dependencies = [ "proc-macro2", "quote", @@ -4453,7 +4467,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -4462,7 +4476,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a617e9eeeb20448b01a8e2427fb80dfbc9c49d79a1de3b11f25731edbf547e3c" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if 1.0.0", "libc", "log", @@ -4540,9 +4554,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -4576,7 +4590,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -4591,9 +4605,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -4678,7 +4692,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "toml_datetime", "winnow 0.5.40", ] @@ -4689,7 +4703,7 @@ version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -4707,7 +4721,7 @@ dependencies = [ "axum", "base64 0.21.7", "bytes", - "h2 0.3.24", + "h2 0.3.26", "http 0.2.11", "http-body 0.4.6", "hyper 0.14.28", @@ -4734,7 +4748,7 @@ dependencies = [ "axum", "base64 0.21.7", "bytes", - "h2 0.3.24", + "h2 0.3.26", "http 0.2.11", "http-body 0.4.6", "hyper 0.14.28", @@ -4760,7 +4774,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -4773,7 +4787,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -4812,7 +4826,7 @@ dependencies = [ [[package]] name = "tower-batch-control" -version = "0.2.41-beta.11" +version = "0.2.41-beta.12" dependencies = [ "color-eyre", "ed25519-zebra", @@ -4835,7 +4849,7 @@ dependencies = [ [[package]] name = "tower-fallback" -version = "0.2.41-beta.11" +version = "0.2.41-beta.12" dependencies = [ "futures-core", "pin-project", @@ -4903,7 +4917,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -5341,7 +5355,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", "wasm-bindgen-shared", ] @@ -5375,7 +5389,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5641,25 +5655,17 @@ version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "zcash_address" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bce173f1d9ed4f806e310bc3a873301531e7a6dc209928584d6404e3f8228ef4" +checksum = "827c17a1f7e3a69f0d44e991ff610c7a842228afdc9dc2325ffdd1a67fee01e9" dependencies = [ "bech32", "bs58", "f4jumble", "zcash_encoding", + "zcash_protocol", ] [[package]] @@ -5707,9 +5713,9 @@ dependencies = [ [[package]] name = "zcash_history" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb611a28a4e13ac715ee712f4344d6b279b767daf6345dafefb2c4bf582b6679" +checksum = "2fde17bf53792f9c756b313730da14880257d7661b5bfc69d0571c3a7c11a76d" dependencies = [ "blake2b_simd", "byteorder", @@ -5786,6 +5792,16 @@ dependencies = [ "zcash_primitives", ] +[[package]] +name = "zcash_protocol" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f8189d4a304e8aa3aef3b75e89f3874bb0dc84b1cd623316a84e79e06cddabc" +dependencies = [ + "document-features", + "memuse", +] + [[package]] name = "zcash_script" version = "0.1.15" @@ -5824,9 +5840,9 @@ dependencies = [ [[package]] name = "zebra-chain" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bitflags-serde-legacy", "bitvec", "blake2b_simd", @@ -5886,7 +5902,7 @@ dependencies = [ [[package]] name = "zebra-consensus" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ "bellman", "blake2b_simd", @@ -5932,7 +5948,7 @@ dependencies = [ [[package]] name = "zebra-grpc" -version = "0.1.0-alpha.2" +version = "0.1.0-alpha.3" dependencies = [ "color-eyre", "futures-util", @@ -5954,9 +5970,9 @@ dependencies = [ [[package]] name = "zebra-network" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "bytes", "chrono", @@ -5965,7 +5981,7 @@ dependencies = [ "hex", "howudoin", "humantime-serde", - "indexmap 2.2.5", + "indexmap 2.2.6", "itertools 0.12.1", "lazy_static", "metrics 0.22.3", @@ -5995,7 +6011,7 @@ dependencies = [ [[package]] name = "zebra-node-services" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ "color-eyre", "jsonrpc-core", @@ -6008,13 +6024,13 @@ dependencies = [ [[package]] name = "zebra-rpc" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ "chrono", "futures", "hex", "hyper 0.14.28", - "indexmap 2.2.5", + "indexmap 2.2.6", "insta", "jsonrpc-core", "jsonrpc-derive", @@ -6039,7 +6055,7 @@ dependencies = [ [[package]] name = "zebra-scan" -version = "0.1.0-alpha.4" +version = "0.1.0-alpha.5" dependencies = [ "bls12_381", "chrono", @@ -6047,7 +6063,7 @@ dependencies = [ "ff", "futures", "group", - "indexmap 2.2.5", + "indexmap 2.2.6", "insta", "itertools 0.12.1", "jubjub", @@ -6071,7 +6087,7 @@ dependencies = [ [[package]] name = "zebra-script" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ "displaydoc", "hex", @@ -6084,7 +6100,7 @@ dependencies = [ [[package]] name = "zebra-state" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ "bincode", "chrono", @@ -6098,7 +6114,7 @@ dependencies = [ "howudoin", "human_bytes", "humantime-serde", - "indexmap 2.2.5", + "indexmap 2.2.6", "insta", "itertools 0.12.1", "jubjub", @@ -6129,13 +6145,13 @@ dependencies = [ [[package]] name = "zebra-test" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ "color-eyre", "futures", "hex", "humantime", - "indexmap 2.2.5", + "indexmap 2.2.6", "insta", "itertools 0.12.1", "lazy_static", @@ -6157,7 +6173,7 @@ dependencies = [ [[package]] name = "zebra-utils" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" dependencies = [ "color-eyre", "hex", @@ -6170,7 +6186,7 @@ dependencies = [ "serde_json", "serde_yaml", "structopt", - "syn 2.0.53", + "syn 2.0.59", "thiserror", "tinyvec", "tokio", @@ -6186,12 +6202,12 @@ dependencies = [ [[package]] name = "zebrad" -version = "1.6.0" +version = "1.6.1" dependencies = [ "abscissa_core", "atty", "chrono", - "clap 4.5.3", + "clap 4.5.4", "color-eyre", "console-subscriber", "dirs", @@ -6201,7 +6217,7 @@ dependencies = [ "howudoin", "humantime-serde", "hyper 0.14.28", - "indexmap 2.2.5", + "indexmap 2.2.6", "indicatif", "inferno", "insta", @@ -6271,7 +6287,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] [[package]] @@ -6291,5 +6307,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.59", ] diff --git a/README.md b/README.md index a07298a05..f2c3f0597 100644 --- a/README.md +++ b/README.md @@ -185,9 +185,9 @@ There are a few bugs in Zebra that we're still working on fixing: - Block download and verification sometimes times out during Zebra's initial sync [#5709](https://github.com/ZcashFoundation/zebra/issues/5709). The full sync still finishes reasonably quickly. -- No Windows support [#3801](https://github.com/ZcashFoundation/zebra/issues/3801). We used to test with Windows Server 2019, but not any more; see the issue for details. +- No Windows support [#3801](https://github.com/ZcashFoundation/zebra/issues/3801). We used to test with Windows Server 2019, but not any more; `zcash_script` has recently been updated to compile with MSVC, we're now waiting on a `zcash_script` release and dependency update, see the issue for details. -- Experimental Tor support is disabled until [Zebra upgrades to the latest `arti-client`](https://github.com/ZcashFoundation/zebra/issues/5492). This happened due to a Rust dependency conflict, which could only be resolved by `arti` upgrading to a version of `x25519-dalek` with the dependency fix. +- Experimental Tor support is disabled until Zebra upgrades to the latest `arti-client`. This happened due to a Rust dependency conflict ([#5492](https://github.com/ZcashFoundation/zebra/issues/5492)) and is still an issue due to [another dependency conflict](https://github.com/ZcashFoundation/zebra/issues/8328#issuecomment-1969989648). ## Documentation diff --git a/book/src/user/docker.md b/book/src/user/docker.md index 4dc7a60d7..02065d782 100644 --- a/book/src/user/docker.md +++ b/book/src/user/docker.md @@ -37,7 +37,7 @@ docker run -d --platform linux/amd64 \ ### Build it locally ```shell -git clone --depth 1 --branch v1.6.0 https://github.com/ZcashFoundation/zebra.git +git clone --depth 1 --branch v1.6.1 https://github.com/ZcashFoundation/zebra.git docker build --file docker/Dockerfile --target runtime --tag zebra:local . docker run --detach zebra:local ``` diff --git a/book/src/user/install.md b/book/src/user/install.md index a3d223628..038984cb1 100644 --- a/book/src/user/install.md +++ b/book/src/user/install.md @@ -19,7 +19,7 @@ To compile Zebra directly from GitHub, or from a GitHub release source archive: ```sh git clone https://github.com/ZcashFoundation/zebra.git cd zebra -git checkout v1.6.0 +git checkout v1.6.1 ``` 3. Build and Run `zebrad` @@ -32,7 +32,7 @@ target/release/zebrad start ### Compiling from git using cargo install ```sh -cargo install --git https://github.com/ZcashFoundation/zebra --tag v1.6.0 zebrad +cargo install --git https://github.com/ZcashFoundation/zebra --tag v1.6.1 zebrad ``` ### Compiling on ARM diff --git a/tower-batch-control/Cargo.toml b/tower-batch-control/Cargo.toml index c21fc13a8..fb72cbc56 100644 --- a/tower-batch-control/Cargo.toml +++ b/tower-batch-control/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tower-batch-control" -version = "0.2.41-beta.11" +version = "0.2.41-beta.12" authors = ["Zcash Foundation ", "Tower Maintainers "] description = "Tower middleware for batch request processing" # # Legal @@ -25,8 +25,8 @@ categories = ["algorithms", "asynchronous"] futures = "0.3.30" futures-core = "0.3.28" pin-project = "1.1.5" -rayon = "1.9.0" -tokio = { version = "1.36.0", features = ["time", "sync", "tracing", "macros"] } +rayon = "1.10.0" +tokio = { version = "1.37.0", features = ["time", "sync", "tracing", "macros"] } tokio-util = "0.7.10" tower = { version = "0.4.13", features = ["util", "buffer"] } tracing = "0.1.39" @@ -41,9 +41,9 @@ tinyvec = { version = "1.6.0", features = ["rustc_1_55"] } ed25519-zebra = "4.0.3" rand = "0.8.5" -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } tokio-test = "0.4.4" -tower-fallback = { path = "../tower-fallback/", version = "0.2.41-beta.11" } +tower-fallback = { path = "../tower-fallback/", version = "0.2.41-beta.12" } tower-test = "0.4.0" -zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.35" } +zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.36" } diff --git a/tower-fallback/Cargo.toml b/tower-fallback/Cargo.toml index c26c9c3d4..633ccbe62 100644 --- a/tower-fallback/Cargo.toml +++ b/tower-fallback/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tower-fallback" -version = "0.2.41-beta.11" +version = "0.2.41-beta.12" authors = ["Zcash Foundation "] description = "A Tower service combinator that sends requests to a first service, then retries processing on a second fallback service if the first service errors." license = "MIT OR Apache-2.0" @@ -22,6 +22,6 @@ futures-core = "0.3.28" tracing = "0.1.39" [dev-dependencies] -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } -zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.35" } +zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.36" } diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index 7b4d41524..654c83c5b 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-chain" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "Core Zcash data structures" license = "MIT OR Apache-2.0" @@ -64,12 +64,12 @@ bench = ["zebra-test"] # Cryptography bitvec = "1.0.1" -bitflags = "2.4.2" +bitflags = "2.5.0" bitflags-serde-legacy = "0.1.1" blake2b_simd = "1.0.2" blake2s_simd = "1.0.2" bridgetree = "0.4.0" -bs58 = { version = "0.5.0", features = ["check"] } +bs58 = { version = "0.5.1", features = ["check"] } byteorder = "1.5.0" # TODO: Internal miner feature functionality was removed at https://github.com/ZcashFoundation/zebra/issues/8180 @@ -78,11 +78,11 @@ byteorder = "1.5.0" equihash = "0.2.0" group = "0.13.0" -incrementalmerkletree = "0.5.0" +incrementalmerkletree = "0.5.1" jubjub = "0.10.0" lazy_static = "1.4.0" num-integer = "0.1.46" -primitive-types = "0.11.1" +primitive-types = "0.12.2" rand_core = "0.6.4" ripemd = "0.1.3" # Matches version used by hdwallet @@ -95,7 +95,7 @@ x25519-dalek = { version = "2.0.1", features = ["serde"] } halo2 = { package = "halo2_proofs", version = "0.3.0" } orchard = "0.6.0" zcash_encoding = "0.2.0" -zcash_history = "0.3.0" +zcash_history = "0.4.0" zcash_note_encryption = "0.4.0" zcash_primitives = { version = "0.13.0", features = ["transparent-inputs"] } @@ -118,7 +118,7 @@ serde-big-array = "0.5.1" # Processing futures = "0.3.30" itertools = "0.12.1" -rayon = "1.9.0" +rayon = "1.10.0" # ZF deps ed25519-zebra = "4.0.3" @@ -126,12 +126,12 @@ redjubjub = "0.7.0" reddsa = "0.5.1" # Production feature json-conversion -serde_json = { version = "1.0.113", optional = true } +serde_json = { version = "1.0.115", optional = true } # Production feature async-error and testing feature proptest-impl -tokio = { version = "1.36.0", optional = true } +tokio = { version = "1.37.0", optional = true } -zcash_address = { version = "0.3.1" } +zcash_address = { version = "0.3.2" } # Experimental feature shielded-scan zcash_client_backend = { version = "0.10.0-rc.1", optional = true } @@ -143,7 +143,7 @@ proptest-derive = { version = "0.4.0", optional = true } rand = { version = "0.8.5", optional = true } rand_chacha = { version = "0.3.1", optional = true } -zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.35", optional = true } +zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.36", optional = true } [dev-dependencies] # Benchmarks @@ -164,9 +164,9 @@ proptest-derive = "0.4.0" rand = "0.8.5" rand_chacha = "0.3.1" -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } -zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.35" } +zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.36" } [[bench]] name = "block" diff --git a/zebra-chain/src/block/arbitrary.rs b/zebra-chain/src/block/arbitrary.rs index 973ad110f..5a39afa2e 100644 --- a/zebra-chain/src/block/arbitrary.rs +++ b/zebra-chain/src/block/arbitrary.rs @@ -1,22 +1,13 @@ //! Randomised property testing for [`Block`]s. -use std::{collections::HashMap, sync::Arc}; - -use proptest::{ - arbitrary::{any, Arbitrary}, - prelude::*, -}; +use proptest::prelude::*; use crate::{ amount::NonNegative, block, fmt::{HexDebug, SummaryDebug}, history_tree::HistoryTree, - parameters::{ - Network, - NetworkUpgrade::{self, *}, - GENESIS_PREVIOUS_BLOCK_HASH, - }, + parameters::{NetworkUpgrade::*, GENESIS_PREVIOUS_BLOCK_HASH}, serialization, transaction::arbitrary::MAX_ARBITRARY_ITEMS, transparent::{ diff --git a/zebra-chain/src/block/tests/prop.rs b/zebra-chain/src/block/tests/prop.rs index 5f642e63d..beeecb782 100644 --- a/zebra-chain/src/block/tests/prop.rs +++ b/zebra-chain/src/block/tests/prop.rs @@ -2,21 +2,19 @@ use std::{env, io::ErrorKind}; -use proptest::{arbitrary::any, prelude::*, test_runner::Config}; +use proptest::{prelude::*, test_runner::Config}; use hex::{FromHex, ToHex}; use zebra_test::prelude::*; use crate::{ - parameters::{Network, GENESIS_PREVIOUS_BLOCK_HASH}, + parameters::GENESIS_PREVIOUS_BLOCK_HASH, serialization::{SerializationError, ZcashDeserializeInto, ZcashSerialize}, - LedgerState, }; use super::super::{ arbitrary::{allow_all_transparent_coinbase_spends, PREVOUTS_CHAIN_HEIGHT}, - serialize::MAX_BLOCK_BYTES, *, }; diff --git a/zebra-chain/src/block/tests/vectors.rs b/zebra-chain/src/block/tests/vectors.rs index 8aa81dbd3..5ff19ca10 100644 --- a/zebra-chain/src/block/tests/vectors.rs +++ b/zebra-chain/src/block/tests/vectors.rs @@ -202,7 +202,7 @@ fn block_test_vectors_height_mainnet() { fn block_test_vectors_height_testnet() { let _init_guard = zebra_test::init(); - block_test_vectors_height(Testnet); + block_test_vectors_height(Network::new_default_testnet()); } /// Test that the block test vector indexes match the heights in the block data, @@ -245,7 +245,7 @@ fn block_commitment_mainnet() { fn block_commitment_testnet() { let _init_guard = zebra_test::init(); - block_commitment(Testnet); + block_commitment(Network::new_default_testnet()); } /// Check that the block commitment field parses without errors. diff --git a/zebra-chain/src/history_tree.rs b/zebra-chain/src/history_tree.rs index 8666ba49e..ca19c5892 100644 --- a/zebra-chain/src/history_tree.rs +++ b/zebra-chain/src/history_tree.rs @@ -372,8 +372,8 @@ impl NonEmptyHistoryTree { } /// Return the network where this tree is used. - pub fn network(&self) -> Network { - self.network.clone() + pub fn network(&self) -> &Network { + &self.network } } diff --git a/zebra-chain/src/history_tree/tests/vectors.rs b/zebra-chain/src/history_tree/tests/vectors.rs index 9ddb32bd0..e65da99b6 100644 --- a/zebra-chain/src/history_tree/tests/vectors.rs +++ b/zebra-chain/src/history_tree/tests/vectors.rs @@ -22,10 +22,10 @@ use eyre::Result; /// higher level API. #[test] fn push_and_prune() -> Result<()> { - push_and_prune_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Heartwood)?; - push_and_prune_for_network_upgrade(Network::Testnet, NetworkUpgrade::Heartwood)?; - push_and_prune_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Canopy)?; - push_and_prune_for_network_upgrade(Network::Testnet, NetworkUpgrade::Canopy)?; + for network in Network::iter() { + push_and_prune_for_network_upgrade(network.clone(), NetworkUpgrade::Heartwood)?; + push_and_prune_for_network_upgrade(network, NetworkUpgrade::Canopy)?; + } Ok(()) } @@ -109,8 +109,9 @@ fn push_and_prune_for_network_upgrade( fn upgrade() -> Result<()> { // The history tree only exists Hearwood-onward, and the only upgrade for which // we have vectors since then is Canopy. Therefore, only test the Heartwood->Canopy upgrade. - upgrade_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Canopy)?; - upgrade_for_network_upgrade(Network::Testnet, NetworkUpgrade::Canopy)?; + for network in Network::iter() { + upgrade_for_network_upgrade(network, NetworkUpgrade::Canopy)?; + } Ok(()) } diff --git a/zebra-chain/src/orchard/action.rs b/zebra-chain/src/orchard/action.rs index f08b0464c..ae7690def 100644 --- a/zebra-chain/src/orchard/action.rs +++ b/zebra-chain/src/orchard/action.rs @@ -1,4 +1,4 @@ -use std::{convert::TryFrom, io}; +use std::io; use halo2::pasta::pallas; use reddsa::orchard::SpendAuth; diff --git a/zebra-chain/src/orchard/arbitrary.rs b/zebra-chain/src/orchard/arbitrary.rs index c0f9615c2..7a6544606 100644 --- a/zebra-chain/src/orchard/arbitrary.rs +++ b/zebra-chain/src/orchard/arbitrary.rs @@ -7,7 +7,7 @@ use group::{ use halo2::pasta::pallas; use reddsa::{orchard::SpendAuth, Signature, SigningKey, VerificationKey, VerificationKeyBytes}; -use proptest::{arbitrary::any, array, collection::vec, prelude::*}; +use proptest::{array, collection::vec, prelude::*}; use super::{ keys::*, note, tree, Action, AuthorizedAction, Flags, NoteCommitment, ValueCommitment, diff --git a/zebra-chain/src/orchard/note/arbitrary.rs b/zebra-chain/src/orchard/note/arbitrary.rs index e6b38f124..e9365de80 100644 --- a/zebra-chain/src/orchard/note/arbitrary.rs +++ b/zebra-chain/src/orchard/note/arbitrary.rs @@ -1,4 +1,4 @@ -use proptest::{arbitrary::any, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; use super::*; diff --git a/zebra-chain/src/orchard/shielded_data.rs b/zebra-chain/src/orchard/shielded_data.rs index 3a034c05f..5347919cd 100644 --- a/zebra-chain/src/orchard/shielded_data.rs +++ b/zebra-chain/src/orchard/shielded_data.rs @@ -8,7 +8,7 @@ use std::{ use byteorder::{ReadBytesExt, WriteBytesExt}; use halo2::pasta::pallas; -use reddsa::{self, orchard::Binding, orchard::SpendAuth, Signature}; +use reddsa::{orchard::Binding, orchard::SpendAuth, Signature}; use crate::{ amount::{Amount, NegativeAllowed}, diff --git a/zebra-chain/src/orchard/tree.rs b/zebra-chain/src/orchard/tree.rs index 1447b03a5..25cde25d9 100644 --- a/zebra-chain/src/orchard/tree.rs +++ b/zebra-chain/src/orchard/tree.rs @@ -19,7 +19,7 @@ use std::{ }; use bitvec::prelude::*; -use bridgetree::{self, NonEmptyFrontier}; +use bridgetree::NonEmptyFrontier; use halo2::pasta::{group::ff::PrimeField, pallas}; use hex::ToHex; use incrementalmerkletree::Hashable; diff --git a/zebra-chain/src/parameters.rs b/zebra-chain/src/parameters.rs index fe62f7b60..2974bd78c 100644 --- a/zebra-chain/src/parameters.rs +++ b/zebra-chain/src/parameters.rs @@ -21,7 +21,7 @@ mod transaction; pub mod arbitrary; pub use genesis::*; -pub use network::Network; +pub use network::{testnet, Network, NetworkKind}; pub use network_upgrade::*; pub use transaction::*; diff --git a/zebra-chain/src/parameters/arbitrary.rs b/zebra-chain/src/parameters/arbitrary.rs index 12440946d..63e678b3d 100644 --- a/zebra-chain/src/parameters/arbitrary.rs +++ b/zebra-chain/src/parameters/arbitrary.rs @@ -2,7 +2,7 @@ use proptest::prelude::*; -use super::NetworkUpgrade; +use super::{Network, NetworkUpgrade}; impl NetworkUpgrade { /// Generates network upgrades. @@ -32,3 +32,13 @@ impl NetworkUpgrade { .boxed() } } + +impl Arbitrary for Network { + type Parameters = (); + + fn arbitrary_with(_args: ()) -> Self::Strategy { + prop_oneof![Just(Self::Mainnet), Just(Self::new_default_testnet())].boxed() + } + + type Strategy = BoxedStrategy; +} diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 3ba5a0902..47bcf68e8 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -1,16 +1,17 @@ //! Consensus parameters for each Zcash network. -use std::{fmt, str::FromStr}; +use std::{fmt, str::FromStr, sync::Arc}; use thiserror::Error; +use zcash_primitives::{consensus as zp_consensus, constants as zp_constants}; + use crate::{ block::{self, Height, HeightDiff}, - parameters::NetworkUpgrade::Canopy, + parameters::NetworkUpgrade, }; -#[cfg(any(test, feature = "proptest-impl"))] -use proptest_derive::Arbitrary; +pub mod testnet; #[cfg(test)] mod tests; @@ -51,52 +52,101 @@ mod tests; /// after the grace period. const ZIP_212_GRACE_PERIOD_DURATION: HeightDiff = 32_256; +/// An enum describing the kind of network, whether it's the production mainnet or a testnet. +// Note: The order of these variants is important for correct bincode (de)serialization +// of history trees in the db format. +// TODO: Replace bincode (de)serialization of `HistoryTreeParts` in a db format upgrade? +#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub enum NetworkKind { + /// The production mainnet. + #[default] + Mainnet, + + /// A test network. + Testnet, + + /// Regtest mode, not yet implemented + // TODO: Add `new_regtest()` and `is_regtest` methods on `Network`. + Regtest, +} + +impl From for NetworkKind { + fn from(network: Network) -> Self { + network.kind() + } +} + /// An enum describing the possible network choices. -#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)] -#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize)] +#[serde(into = "NetworkKind")] pub enum Network { /// The production mainnet. #[default] Mainnet, - /// The oldest public test network. - Testnet, + /// A test network such as the default public testnet, + /// a configured testnet, or Regtest. + Testnet(Arc), } -use zcash_primitives::consensus::{Network as ZcashPrimitivesNetwork, Parameters as _}; -impl Network { +impl NetworkKind { /// Returns the human-readable prefix for Base58Check-encoded transparent /// pay-to-public-key-hash payment addresses for the network. - pub fn b58_pubkey_address_prefix(&self) -> [u8; 2] { - ::from(self).b58_pubkey_address_prefix() + pub fn b58_pubkey_address_prefix(self) -> [u8; 2] { + match self { + Self::Mainnet => zp_constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX, + Self::Testnet | Self::Regtest => zp_constants::testnet::B58_PUBKEY_ADDRESS_PREFIX, + } } /// Returns the human-readable prefix for Base58Check-encoded transparent pay-to-script-hash /// payment addresses for the network. - pub fn b58_script_address_prefix(&self) -> [u8; 2] { - ::from(self).b58_script_address_prefix() - } - /// Returns true if the maximum block time rule is active for `network` and `height`. - /// - /// Always returns true if `network` is the Mainnet. - /// If `network` is the Testnet, the `height` should be at least - /// TESTNET_MAX_TIME_START_HEIGHT to return true. - /// Returns false otherwise. - /// - /// Part of the consensus rules at - pub fn is_max_block_time_enforced(&self, height: block::Height) -> bool { + pub fn b58_script_address_prefix(self) -> [u8; 2] { match self { - Network::Mainnet => true, - Network::Testnet => height >= super::TESTNET_MAX_TIME_START_HEIGHT, + Self::Mainnet => zp_constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX, + Self::Testnet | Self::Regtest => zp_constants::testnet::B58_SCRIPT_ADDRESS_PREFIX, } } + + /// Return the network name as defined in + /// [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest) + pub fn bip70_network_name(&self) -> String { + if *self == Self::Mainnet { + "main".to_string() + } else { + "test".to_string() + } + } +} + +impl From for &'static str { + fn from(network: NetworkKind) -> &'static str { + // These should be different from the `Display` impl for `Network` so that its lowercase form + // can't be parsed as the default Testnet in the `Network` `FromStr` impl, it's easy to + // distinguish them in logs, and so it's generally harder to confuse the two. + match network { + NetworkKind::Mainnet => "MainnetKind", + NetworkKind::Testnet => "TestnetKind", + NetworkKind::Regtest => "RegtestKind", + } + } +} + +impl fmt::Display for NetworkKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str((*self).into()) + } } impl From<&Network> for &'static str { fn from(network: &Network) -> &'static str { match network { Network::Mainnet => "Mainnet", - Network::Testnet => "Testnet", + // 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", } } } @@ -108,17 +158,62 @@ impl fmt::Display for Network { } impl Network { + /// Creates a new [`Network::Testnet`] with the default Testnet [`testnet::Parameters`]. + pub fn new_default_testnet() -> Self { + Self::Testnet(Arc::new(testnet::Parameters::default())) + } + + /// Creates a new configured [`Network::Testnet`] with the provided Testnet [`testnet::Parameters`]. + pub fn new_configured_testnet(params: testnet::Parameters) -> Self { + Self::Testnet(Arc::new(params)) + } + + /// 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 { + params.is_default_testnet() + } else { + false + } + } + + /// Returns the [`NetworkKind`] for this network. + pub fn kind(&self) -> NetworkKind { + match self { + Network::Mainnet => NetworkKind::Mainnet, + // TODO: Return `NetworkKind::Regtest` if the parameters match the default Regtest params + Network::Testnet(_) => NetworkKind::Testnet, + } + } + /// Returns an iterator over [`Network`] variants. pub fn iter() -> impl Iterator { // TODO: Use default values of `Testnet` variant when adding fields for #7845. - [Self::Mainnet, Self::Testnet].into_iter() + [Self::Mainnet, Self::new_default_testnet()].into_iter() + } + + /// Returns true if the maximum block time rule is active for `network` and `height`. + /// + /// Always returns true if `network` is the Mainnet. + /// If `network` is the Testnet, the `height` should be at least + /// TESTNET_MAX_TIME_START_HEIGHT to return true. + /// Returns false otherwise. + /// + /// Part of the consensus rules at + pub fn is_max_block_time_enforced(&self, height: block::Height) -> bool { + match self { + Network::Mainnet => true, + // TODO: Move `TESTNET_MAX_TIME_START_HEIGHT` to a field on testnet::Parameters (#8364) + Network::Testnet(_params) => height >= super::TESTNET_MAX_TIME_START_HEIGHT, + } } /// Get the default port associated to this network. pub fn default_port(&self) -> u16 { match self { Network::Mainnet => 8233, - Network::Testnet => 18233, + // TODO: Add a `default_port` field to `testnet::Parameters` to return here. (zcashd uses 18344 for Regtest) + Network::Testnet(_params) => 18233, } } @@ -132,7 +227,7 @@ impl Network { // // See the `ZIP_212_GRACE_PERIOD_DURATION` documentation for more information. - let canopy_activation = Canopy + let canopy_activation = NetworkUpgrade::Canopy .activation_height(self) .expect("Canopy activation height must be present for both networks"); @@ -143,10 +238,7 @@ impl Network { /// Return the network name as defined in /// [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest) pub fn bip70_network_name(&self) -> String { - match self { - Network::Mainnet => "main".to_string(), - Network::Testnet => "test".to_string(), - } + self.kind().bip70_network_name() } /// Return the lowercase network name. @@ -167,13 +259,14 @@ impl Network { } } +// This is used for parsing a command-line argument for the `TipHeight` command in zebrad. impl FromStr for Network { type Err = InvalidNetworkError; fn from_str(string: &str) -> Result { match string.to_lowercase().as_str() { "mainnet" => Ok(Network::Mainnet), - "testnet" => Ok(Network::Testnet), + "testnet" => Ok(Network::new_default_testnet()), _ => Err(InvalidNetworkError(string.to_owned())), } } @@ -182,3 +275,70 @@ impl FromStr for Network { #[derive(Clone, Debug, Error)] #[error("Invalid network: {0}")] pub struct InvalidNetworkError(String); + +impl zp_consensus::Parameters for Network { + fn activation_height( + &self, + nu: zcash_primitives::consensus::NetworkUpgrade, + ) -> Option { + let target_nu = match nu { + zp_consensus::NetworkUpgrade::Overwinter => NetworkUpgrade::Overwinter, + zp_consensus::NetworkUpgrade::Sapling => NetworkUpgrade::Sapling, + zp_consensus::NetworkUpgrade::Blossom => NetworkUpgrade::Blossom, + zp_consensus::NetworkUpgrade::Heartwood => NetworkUpgrade::Heartwood, + zp_consensus::NetworkUpgrade::Canopy => NetworkUpgrade::Canopy, + zp_consensus::NetworkUpgrade::Nu5 => NetworkUpgrade::Nu5, + }; + + // Heights are hard-coded below Height::MAX or checked when the config is parsed. + target_nu + .activation_height(self) + .map(|Height(h)| zp_consensus::BlockHeight::from_u32(h)) + } + + fn coin_type(&self) -> u32 { + match self { + Network::Mainnet => zp_constants::mainnet::COIN_TYPE, + // The regtest cointype reuses the testnet cointype, + // See + Network::Testnet(_) => zp_constants::testnet::COIN_TYPE, + } + } + + fn address_network(&self) -> Option { + match self { + Network::Mainnet => Some(zcash_address::Network::Main), + // TODO: Check if network is `Regtest` first, and if it is, return `zcash_address::Network::Regtest` + Network::Testnet(_params) => Some(zcash_address::Network::Test), + } + } + + fn hrp_sapling_extended_spending_key(&self) -> &str { + match self { + Network::Mainnet => zp_constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY, + Network::Testnet(params) => params.hrp_sapling_extended_spending_key(), + } + } + + fn hrp_sapling_extended_full_viewing_key(&self) -> &str { + match self { + Network::Mainnet => zp_constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, + Network::Testnet(params) => params.hrp_sapling_extended_full_viewing_key(), + } + } + + fn hrp_sapling_payment_address(&self) -> &str { + match self { + Network::Mainnet => zp_constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, + Network::Testnet(params) => params.hrp_sapling_payment_address(), + } + } + + fn b58_pubkey_address_prefix(&self) -> [u8; 2] { + self.kind().b58_pubkey_address_prefix() + } + + fn b58_script_address_prefix(&self) -> [u8; 2] { + self.kind().b58_script_address_prefix() + } +} diff --git a/zebra-chain/src/parameters/network/testnet.rs b/zebra-chain/src/parameters/network/testnet.rs new file mode 100644 index 000000000..1a1b47001 --- /dev/null +++ b/zebra-chain/src/parameters/network/testnet.rs @@ -0,0 +1,220 @@ +//! Types and implementation for Testnet consensus parameters +use std::collections::BTreeMap; + +use zcash_primitives::constants as zp_constants; + +use crate::{ + block::Height, + parameters::{ + network_upgrade::TESTNET_ACTIVATION_HEIGHTS, Network, NetworkUpgrade, + NETWORK_UPGRADES_IN_ORDER, + }, +}; + +/// Configurable activation heights for Regtest and configured Testnets. +#[derive(Deserialize, Default)] +#[serde(rename_all = "PascalCase")] +pub struct ConfiguredActivationHeights { + /// Activation height for `BeforeOverwinter` network upgrade. + pub before_overwinter: Option, + /// Activation height for `Overwinter` network upgrade. + pub overwinter: Option, + /// Activation height for `Sapling` network upgrade. + pub sapling: Option, + /// Activation height for `Blossom` network upgrade. + pub blossom: Option, + /// Activation height for `Heartwood` network upgrade. + pub heartwood: Option, + /// Activation height for `Canopy` network upgrade. + pub canopy: Option, + /// Activation height for `NU5` network upgrade. + #[serde(rename = "NU5")] + pub nu5: Option, +} + +/// Builder for the [`Parameters`] struct. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct ParametersBuilder { + /// The network upgrade activation heights for this network, see [`Parameters::activation_heights`] for more details. + activation_heights: BTreeMap, + /// Sapling extended spending key human-readable prefix for this network + hrp_sapling_extended_spending_key: String, + /// Sapling extended full viewing key human-readable prefix for this network + hrp_sapling_extended_full_viewing_key: String, + /// Sapling payment address human-readable prefix for this network + hrp_sapling_payment_address: String, +} + +impl Default for ParametersBuilder { + fn default() -> Self { + Self { + // # 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(), + 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(), + } + } +} + +impl ParametersBuilder { + /// 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( + mut self, + ConfiguredActivationHeights { + // TODO: Find out if `BeforeOverwinter` is required at Height(1), allow for + // configuring its activation height if it's not required to be at Height(1) + before_overwinter: _, + overwinter, + sapling, + blossom, + heartwood, + canopy, + nu5, + }: ConfiguredActivationHeights, + ) -> Self { + use NetworkUpgrade::*; + + // # Correctness + // + // These must be in order so that later network upgrades overwrite prior ones + // if multiple network upgrades are configured with the same activation height. + let activation_heights: BTreeMap<_, _> = overwinter + .into_iter() + .map(|h| (h, Overwinter)) + .chain(sapling.into_iter().map(|h| (h, Sapling))) + .chain(blossom.into_iter().map(|h| (h, Blossom))) + .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(); + + let network_upgrades: Vec<_> = activation_heights.iter().map(|(_h, &nu)| nu).collect(); + + // Check that the provided network upgrade activation heights are in the same order by height as the default testnet activation heights + let mut activation_heights_iter = activation_heights.iter(); + for expected_network_upgrade in NETWORK_UPGRADES_IN_ORDER { + if !network_upgrades.contains(&expected_network_upgrade) { + continue; + } else if let Some((&height, &network_upgrade)) = activation_heights_iter.next() { + assert_ne!( + height, + Height(0), + "Height(0) is reserved for the `Genesis` upgrade" + ); + + assert!( + network_upgrade == expected_network_upgrade, + "network upgrades must be activated in order, the correct order is {NETWORK_UPGRADES_IN_ORDER:?}" + ); + } + } + + // # Correctness + // + // Height(0) must be reserved for the `NetworkUpgrade::Genesis`. + self.activation_heights.split_off(&Height(2)); + self.activation_heights.extend(activation_heights); + + self + } + + /// Converts the builder to a [`Parameters`] struct + pub fn finish(self) -> Parameters { + let Self { + activation_heights, + hrp_sapling_extended_spending_key, + hrp_sapling_extended_full_viewing_key, + hrp_sapling_payment_address, + } = self; + Parameters { + activation_heights, + hrp_sapling_extended_spending_key, + hrp_sapling_extended_full_viewing_key, + hrp_sapling_payment_address, + } + } + + /// Converts the builder to a configured [`Network::Testnet`] + pub fn to_network(self) -> Network { + Network::new_configured_testnet(self.finish()) + } +} + +/// 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 network upgrade activation heights for this network. + /// + /// Note: This value is ignored by `Network::activation_list()` when `zebra-chain` is + /// compiled with the `zebra-test` feature flag AND the `TEST_FAKE_ACTIVATION_HEIGHTS` + /// environment variable is set. + activation_heights: BTreeMap, + /// Sapling extended spending key human-readable prefix for this network + hrp_sapling_extended_spending_key: String, + /// Sapling extended full viewing key human-readable prefix for this network + hrp_sapling_extended_full_viewing_key: String, + /// Sapling payment address human-readable prefix for this network + hrp_sapling_payment_address: String, +} + +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(), + } + } +} + +impl Parameters { + /// Creates a new [`ParametersBuilder`]. + pub fn build() -> ParametersBuilder { + ParametersBuilder::default() + } + + /// Returns true if the instance of [`Parameters`] represents the default public Testnet. + pub fn is_default_testnet(&self) -> bool { + self == &Self::default() + } + + /// Returns the network upgrade activation heights + pub fn activation_heights(&self) -> &BTreeMap { + &self.activation_heights + } + + /// Returns the `hrp_sapling_extended_spending_key` field + pub fn hrp_sapling_extended_spending_key(&self) -> &str { + &self.hrp_sapling_extended_spending_key + } + + /// Returns the `hrp_sapling_extended_full_viewing_key` field + pub fn hrp_sapling_extended_full_viewing_key(&self) -> &str { + &self.hrp_sapling_extended_full_viewing_key + } + + /// Returns the `hrp_sapling_payment_address` field + pub fn hrp_sapling_payment_address(&self) -> &str { + &self.hrp_sapling_payment_address + } +} diff --git a/zebra-chain/src/parameters/network/tests.rs b/zebra-chain/src/parameters/network/tests.rs index 2bf82ef4e..cc95d9d45 100644 --- a/zebra-chain/src/parameters/network/tests.rs +++ b/zebra-chain/src/parameters/network/tests.rs @@ -1 +1,2 @@ mod prop; +mod vectors; diff --git a/zebra-chain/src/parameters/network/tests/prop.rs b/zebra-chain/src/parameters/network/tests/prop.rs index cab04496d..c2b1e31e0 100644 --- a/zebra-chain/src/parameters/network/tests/prop.rs +++ b/zebra-chain/src/parameters/network/tests/prop.rs @@ -34,6 +34,6 @@ proptest! { let _init_guard = zebra_test::init(); assert!(Network::Mainnet.is_max_block_time_enforced(height)); - assert_eq!(Network::Testnet.is_max_block_time_enforced(height), TESTNET_MAX_TIME_START_HEIGHT <= height); + assert_eq!(Network::new_default_testnet().is_max_block_time_enforced(height), TESTNET_MAX_TIME_START_HEIGHT <= height); } } diff --git a/zebra-chain/src/parameters/network/tests/vectors.rs b/zebra-chain/src/parameters/network/tests/vectors.rs new file mode 100644 index 000000000..b6fca27c2 --- /dev/null +++ b/zebra-chain/src/parameters/network/tests/vectors.rs @@ -0,0 +1,127 @@ +//! Fixed test vectors for the network consensus parameters. + +use zcash_primitives::consensus::{self as zp_consensus, Parameters}; + +use crate::{ + block::Height, + parameters::{ + testnet::{self, ConfiguredActivationHeights}, + Network, NetworkUpgrade, NETWORK_UPGRADES_IN_ORDER, + }, +}; + +/// Checks that every method in the `Parameters` impl for `zebra_chain::Network` has the same output +/// as the Parameters impl for `zcash_primitives::consensus::Network` on Mainnet and the default Testnet. +#[test] +fn check_parameters_impl() { + let zp_network_upgrades = [ + zp_consensus::NetworkUpgrade::Overwinter, + zp_consensus::NetworkUpgrade::Sapling, + zp_consensus::NetworkUpgrade::Blossom, + zp_consensus::NetworkUpgrade::Heartwood, + zp_consensus::NetworkUpgrade::Canopy, + zp_consensus::NetworkUpgrade::Nu5, + ]; + + for (network, zp_network) in [ + (Network::Mainnet, zp_consensus::Network::MainNetwork), + ( + Network::new_default_testnet(), + zp_consensus::Network::TestNetwork, + ), + ] { + for nu in zp_network_upgrades { + let activation_height = network + .activation_height(nu) + .expect("must have activation height for past network upgrades"); + + assert_eq!( + activation_height, + zp_network + .activation_height(nu) + .expect("must have activation height for past network upgrades"), + "Parameters::activation_heights() outputs must match" + ); + + let activation_height: u32 = activation_height.into(); + + for height in (activation_height - 1)..=(activation_height + 1) { + for nu in zp_network_upgrades { + let height = zp_consensus::BlockHeight::from_u32(height); + assert_eq!( + network.is_nu_active(nu, height), + zp_network.is_nu_active(nu, height), + "Parameters::is_nu_active() outputs must match", + ); + } + } + } + + assert_eq!( + network.coin_type(), + zp_network.coin_type(), + "Parameters::coin_type() outputs must match" + ); + assert_eq!( + network.hrp_sapling_extended_spending_key(), + zp_network.hrp_sapling_extended_spending_key(), + "Parameters::hrp_sapling_extended_spending_key() outputs must match" + ); + assert_eq!( + network.hrp_sapling_extended_full_viewing_key(), + zp_network.hrp_sapling_extended_full_viewing_key(), + "Parameters::hrp_sapling_extended_full_viewing_key() outputs must match" + ); + assert_eq!( + network.hrp_sapling_payment_address(), + zp_network.hrp_sapling_payment_address(), + "Parameters::hrp_sapling_payment_address() outputs must match" + ); + assert_eq!( + network.b58_pubkey_address_prefix(), + zp_network.b58_pubkey_address_prefix(), + "Parameters::b58_pubkey_address_prefix() outputs must match" + ); + assert_eq!( + network.b58_script_address_prefix(), + zp_network.b58_script_address_prefix(), + "Parameters::b58_script_address_prefix() outputs must match" + ); + } +} + +/// 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)`. +#[test] +fn activates_network_upgrades_correctly() { + let expected_activation_height = 1; + let network = testnet::Parameters::build() + .activation_heights(ConfiguredActivationHeights { + nu5: Some(expected_activation_height), + ..Default::default() + }) + .to_network(); + + let genesis_activation_height = NetworkUpgrade::Genesis + .activation_height(&network) + .expect("must return an activation height"); + + assert_eq!( + genesis_activation_height, + Height(0), + "activation height for all networks after Genesis and BeforeOverwinter should match NU5 activation height" + ); + + for nu in NETWORK_UPGRADES_IN_ORDER.into_iter().skip(1) { + let activation_height = nu + .activation_height(&network) + .expect("must return an activation height"); + + assert_eq!( + activation_height, Height(expected_activation_height), + "activation height for all networks after Genesis and BeforeOverwinter \ + should match NU5 activation height, network_upgrade: {nu}, activation_height: {activation_height:?}" + ); + } +} diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index 4d88e96bd..de546e3b4 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -7,7 +7,6 @@ use crate::parameters::{Network, Network::*}; use std::collections::{BTreeMap, HashMap}; use std::fmt; -use std::ops::Bound::*; use chrono::{DateTime, Duration, Utc}; use hex::{FromHex, ToHex}; @@ -15,6 +14,18 @@ use hex::{FromHex, ToHex}; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; +/// A list of network upgrades in the order that they must be activated. +pub const NETWORK_UPGRADES_IN_ORDER: [NetworkUpgrade; 8] = [ + Genesis, + BeforeOverwinter, + Overwinter, + Sapling, + Blossom, + Heartwood, + Canopy, + Nu5, +]; + /// A Zcash network upgrade. /// /// Network upgrades can change the Zcash network protocol or consensus rules in @@ -242,12 +253,7 @@ impl Network { /// and it's a test build, this returns a list of fake activation heights /// used by some tests. pub fn activation_list(&self) -> BTreeMap { - let (mainnet_heights, testnet_heights) = { - #[cfg(not(feature = "zebra-test"))] - { - (MAINNET_ACTIVATION_HEIGHTS, TESTNET_ACTIVATION_HEIGHTS) - } - + match self { // To prevent accidentally setting this somehow, only check the env var // when being compiled for tests. We can't use cfg(test) since the // test that uses this is in zebra-state, and cfg(test) is not @@ -260,24 +266,19 @@ impl Network { // feature should only be enabled for tests: // https://doc.rust-lang.org/cargo/reference/features.html#resolver-version-2-command-line-flags #[cfg(feature = "zebra-test")] - if std::env::var_os("TEST_FAKE_ACTIVATION_HEIGHTS").is_some() { - ( - FAKE_MAINNET_ACTIVATION_HEIGHTS, - FAKE_TESTNET_ACTIVATION_HEIGHTS, - ) - } else { - (MAINNET_ACTIVATION_HEIGHTS, TESTNET_ACTIVATION_HEIGHTS) + Mainnet if std::env::var_os("TEST_FAKE_ACTIVATION_HEIGHTS").is_some() => { + FAKE_MAINNET_ACTIVATION_HEIGHTS.iter().cloned().collect() } - }; - match self { - Mainnet => mainnet_heights, - Testnet => testnet_heights, + #[cfg(feature = "zebra-test")] + Testnet(_) if std::env::var_os("TEST_FAKE_ACTIVATION_HEIGHTS").is_some() => { + FAKE_TESTNET_ACTIVATION_HEIGHTS.iter().cloned().collect() + } + Mainnet => MAINNET_ACTIVATION_HEIGHTS.iter().cloned().collect(), + Testnet(params) => params.activation_heights().clone(), } - .iter() - .cloned() - .collect() } } + impl NetworkUpgrade { /// Returns the current network upgrade for `network` and `height`. pub fn current(network: &Network, height: block::Height) -> NetworkUpgrade { @@ -289,11 +290,28 @@ impl NetworkUpgrade { .expect("every height has a current network upgrade") } + /// Returns the next expected network upgrade after this network upgrade + pub fn next_upgrade(self) -> Option { + match self { + Genesis => Some(BeforeOverwinter), + BeforeOverwinter => Some(Overwinter), + Overwinter => Some(Sapling), + Sapling => Some(Blossom), + Blossom => Some(Heartwood), + Heartwood => Some(Canopy), + Canopy => Some(Nu5), + Nu5 => None, + } + } + /// Returns the next network upgrade for `network` and `height`. /// /// Returns None if the next upgrade has not been implemented in Zebra /// yet. + #[cfg(test)] pub fn next(network: &Network, height: block::Height) -> Option { + use std::ops::Bound::*; + network .activation_list() .range((Excluded(height), Unbounded)) @@ -301,17 +319,27 @@ impl NetworkUpgrade { .next() } - /// Returns the activation height for this network upgrade on `network`. + /// Returns the activation height for this network upgrade on `network`, or + /// + /// Returns the activation height of the first network upgrade that follows + /// this network upgrade if there is no activation height for this network upgrade + /// such as on Regtest or a configured Testnet where multiple network upgrades have the + /// same activation height, or if one is omitted when others that follow it are included. /// /// Returns None if this network upgrade is a future upgrade, and its /// activation height has not been set yet. + /// + /// Returns None if this network upgrade has not been configured on a Testnet or Regtest. pub fn activation_height(&self, network: &Network) -> Option { network .activation_list() .iter() - .filter(|(_, nu)| nu == &self) + .find(|(_, nu)| nu == &self) .map(|(height, _)| *height) - .next() + .or_else(|| { + self.next_upgrade() + .and_then(|next_nu| next_nu.activation_height(network)) + }) } /// Returns `true` if `height` is the activation height of any network upgrade @@ -394,9 +422,14 @@ impl NetworkUpgrade { height: block::Height, ) -> Option { match (network, height) { - (Network::Testnet, height) if height < TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT => None, + // TODO: Move `TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT` to a field on testnet::Parameters (#8364) + (Network::Testnet(_params), height) + if height < TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT => + { + None + } (Network::Mainnet, _) => None, - (Network::Testnet, _) => { + (Network::Testnet(_params), _) => { let network_upgrade = NetworkUpgrade::current(network, height); Some(network_upgrade.target_spacing() * TESTNET_MINIMUM_DIFFICULTY_GAP_MULTIPLIER) } diff --git a/zebra-chain/src/parameters/tests.rs b/zebra-chain/src/parameters/tests.rs index 715ceb682..2b0f8b4a2 100644 --- a/zebra-chain/src/parameters/tests.rs +++ b/zebra-chain/src/parameters/tests.rs @@ -21,7 +21,7 @@ fn activation_bijective() { let mainnet_nus: HashSet<&NetworkUpgrade> = mainnet_activations.values().collect(); assert_eq!(MAINNET_ACTIVATION_HEIGHTS.len(), mainnet_nus.len()); - let testnet_activations = Testnet.activation_list(); + let testnet_activations = Network::new_default_testnet().activation_list(); let testnet_heights: HashSet<&block::Height> = testnet_activations.keys().collect(); assert_eq!(TESTNET_ACTIVATION_HEIGHTS.len(), testnet_heights.len()); @@ -38,7 +38,7 @@ fn activation_extremes_mainnet() { #[test] fn activation_extremes_testnet() { let _init_guard = zebra_test::init(); - activation_extremes(Testnet) + activation_extremes(Network::new_default_testnet()) } /// Test the activation_list, activation_height, current, and next functions @@ -115,7 +115,7 @@ fn activation_consistent_mainnet() { #[test] fn activation_consistent_testnet() { let _init_guard = zebra_test::init(); - activation_consistent(Testnet) + activation_consistent(Network::new_default_testnet()) } /// Check that the `activation_height`, `is_activation_height`, @@ -178,7 +178,7 @@ fn branch_id_extremes_mainnet() { #[test] fn branch_id_extremes_testnet() { let _init_guard = zebra_test::init(); - branch_id_extremes(Testnet) + branch_id_extremes(Network::new_default_testnet()) } /// Test the branch_id_list, branch_id, and current functions for `network` with @@ -217,7 +217,7 @@ fn branch_id_consistent_mainnet() { #[test] fn branch_id_consistent_testnet() { let _init_guard = zebra_test::init(); - branch_id_consistent(Testnet) + branch_id_consistent(Network::new_default_testnet()) } /// Check that the branch_id and current functions are consistent for `network`. diff --git a/zebra-chain/src/primitives/address.rs b/zebra-chain/src/primitives/address.rs index 553e523b7..7e5f76138 100644 --- a/zebra-chain/src/primitives/address.rs +++ b/zebra-chain/src/primitives/address.rs @@ -5,7 +5,7 @@ use zcash_address::unified::{self, Container}; use zcash_primitives::sapling; -use crate::{parameters::Network, transparent, BoxError}; +use crate::{parameters::NetworkKind, transparent, BoxError}; /// Zcash address variants pub enum Address { @@ -14,8 +14,8 @@ pub enum Address { /// Sapling address Sapling { - /// Address' network - network: Network, + /// Address' network kind + network: NetworkKind, /// Sapling address address: sapling::PaymentAddress, @@ -23,8 +23,8 @@ pub enum Address { /// Unified address Unified { - /// Address' network - network: Network, + /// Address' network kind + network: NetworkKind, /// Unified address unified_address: zcash_address::unified::Address, @@ -40,28 +40,6 @@ pub enum Address { }, } -impl TryFrom for Network { - // TODO: better error type - type Error = BoxError; - - fn try_from(network: zcash_address::Network) -> Result { - match network { - zcash_address::Network::Main => Ok(Network::Mainnet), - zcash_address::Network::Test => Ok(Network::Testnet), - zcash_address::Network::Regtest => Err("unsupported Zcash network parameters".into()), - } - } -} - -impl From<&Network> for zcash_address::Network { - fn from(network: &Network) -> Self { - match network { - Network::Mainnet => zcash_address::Network::Main, - Network::Testnet => zcash_address::Network::Test, - } - } -} - impl zcash_address::TryFromAddress for Address { // TODO: crate::serialization::SerializationError type Error = BoxError; @@ -71,7 +49,7 @@ impl zcash_address::TryFromAddress for Address { data: [u8; 20], ) -> Result> { Ok(Self::Transparent(transparent::Address::from_pub_key_hash( - &network.try_into()?, + NetworkKind::from_zcash_address(network), data, ))) } @@ -81,7 +59,7 @@ impl zcash_address::TryFromAddress for Address { data: [u8; 20], ) -> Result> { Ok(Self::Transparent(transparent::Address::from_script_hash( - &network.try_into()?, + NetworkKind::from_zcash_address(network), data, ))) } @@ -90,7 +68,7 @@ impl zcash_address::TryFromAddress for Address { network: zcash_address::Network, data: [u8; 43], ) -> Result> { - let network = network.try_into()?; + let network = NetworkKind::from_zcash_address(network); sapling::PaymentAddress::from_bytes(&data) .map(|address| Self::Sapling { address, network }) .ok_or_else(|| BoxError::from("not a valid sapling address").into()) @@ -100,7 +78,7 @@ impl zcash_address::TryFromAddress for Address { network: zcash_address::Network, unified_address: zcash_address::unified::Address, ) -> Result> { - let network = &network.try_into()?; + let network = NetworkKind::from_zcash_address(network); let mut orchard = None; let mut sapling = None; let mut transparent = None; @@ -144,7 +122,7 @@ impl zcash_address::TryFromAddress for Address { } Ok(Self::Unified { - network: network.clone(), + network, unified_address, orchard, sapling, @@ -155,10 +133,10 @@ impl zcash_address::TryFromAddress for Address { impl Address { /// Returns the network for the address. - pub fn network(&self) -> Network { + pub fn network(&self) -> NetworkKind { match &self { - Self::Transparent(address) => address.network(), - Self::Sapling { network, .. } | Self::Unified { network, .. } => network.clone(), + Self::Transparent(address) => address.network_kind(), + Self::Sapling { network, .. } | Self::Unified { network, .. } => *network, } } @@ -185,10 +163,34 @@ impl Address { Self::Transparent(address) => Some(address.to_string()), Self::Sapling { address, network } => { let data = address.to_bytes(); - let address = ZcashAddress::from_sapling(network.into(), data); + let address = ZcashAddress::from_sapling(network.to_zcash_address(), data); Some(address.encode()) } Self::Unified { .. } => None, } } } + +impl NetworkKind { + /// Converts a [`zcash_address::Network`] to a [`NetworkKind`]. + /// + /// This method is meant to be used for decoding Zcash addresses in zebra-rpc methods. + fn from_zcash_address(network: zcash_address::Network) -> Self { + match network { + zcash_address::Network::Main => NetworkKind::Mainnet, + zcash_address::Network::Test => NetworkKind::Testnet, + zcash_address::Network::Regtest => NetworkKind::Regtest, + } + } + + /// Converts a [`zcash_address::Network`] to a [`NetworkKind`]. + /// + /// This method is meant to be used for encoding Zcash addresses in zebra-rpc methods. + fn to_zcash_address(self) -> zcash_address::Network { + match self { + NetworkKind::Mainnet => zcash_address::Network::Main, + NetworkKind::Testnet => zcash_address::Network::Test, + NetworkKind::Regtest => zcash_address::Network::Regtest, + } + } +} diff --git a/zebra-chain/src/primitives/proofs/bctv14.rs b/zebra-chain/src/primitives/proofs/bctv14.rs index ac1f6d5f0..3e13b763f 100644 --- a/zebra-chain/src/primitives/proofs/bctv14.rs +++ b/zebra-chain/src/primitives/proofs/bctv14.rs @@ -53,7 +53,7 @@ impl ZcashDeserialize for Bctv14Proof { } #[cfg(any(test, feature = "proptest-impl"))] -use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; #[cfg(any(test, feature = "proptest-impl"))] impl Arbitrary for Bctv14Proof { diff --git a/zebra-chain/src/primitives/proofs/groth16.rs b/zebra-chain/src/primitives/proofs/groth16.rs index 43f661a38..13fd04c15 100644 --- a/zebra-chain/src/primitives/proofs/groth16.rs +++ b/zebra-chain/src/primitives/proofs/groth16.rs @@ -65,7 +65,7 @@ impl ZcashDeserialize for Groth16Proof { } #[cfg(any(test, feature = "proptest-impl"))] -use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; #[cfg(any(test, feature = "proptest-impl"))] impl Arbitrary for Groth16Proof { diff --git a/zebra-chain/src/primitives/proofs/halo2.rs b/zebra-chain/src/primitives/proofs/halo2.rs index eb62d1a94..1cccfa2d2 100644 --- a/zebra-chain/src/primitives/proofs/halo2.rs +++ b/zebra-chain/src/primitives/proofs/halo2.rs @@ -36,7 +36,7 @@ impl ZcashDeserialize for Halo2Proof { } } #[cfg(any(test, feature = "proptest-impl"))] -use proptest::{arbitrary::Arbitrary, prelude::*}; +use proptest::prelude::*; #[cfg(any(test, feature = "proptest-impl"))] impl Arbitrary for Halo2Proof { diff --git a/zebra-chain/src/primitives/zcash_history.rs b/zebra-chain/src/primitives/zcash_history.rs index 8642343da..e43b9478f 100644 --- a/zebra-chain/src/primitives/zcash_history.rs +++ b/zebra-chain/src/primitives/zcash_history.rs @@ -6,7 +6,7 @@ mod tests; -use std::{collections::BTreeMap, convert::TryInto, io, sync::Arc}; +use std::{collections::BTreeMap, io, sync::Arc}; use serde_big_array::BigArray; pub use zcash_history::{V1, V2}; diff --git a/zebra-chain/src/primitives/zcash_history/tests/vectors.rs b/zebra-chain/src/primitives/zcash_history/tests/vectors.rs index b5ead1098..d23cb078d 100644 --- a/zebra-chain/src/primitives/zcash_history/tests/vectors.rs +++ b/zebra-chain/src/primitives/zcash_history/tests/vectors.rs @@ -11,10 +11,10 @@ use eyre::Result; /// and its next block. #[test] fn tree() -> Result<()> { - tree_for_network_upgrade(&Network::Mainnet, NetworkUpgrade::Heartwood)?; - tree_for_network_upgrade(&Network::Testnet, NetworkUpgrade::Heartwood)?; - tree_for_network_upgrade(&Network::Mainnet, NetworkUpgrade::Canopy)?; - tree_for_network_upgrade(&Network::Testnet, NetworkUpgrade::Canopy)?; + for network in Network::iter() { + tree_for_network_upgrade(&network, NetworkUpgrade::Heartwood)?; + tree_for_network_upgrade(&network, NetworkUpgrade::Canopy)?; + } Ok(()) } diff --git a/zebra-chain/src/primitives/zcash_note_encryption.rs b/zebra-chain/src/primitives/zcash_note_encryption.rs index 0870dac56..f8e47fbad 100644 --- a/zebra-chain/src/primitives/zcash_note_encryption.rs +++ b/zebra-chain/src/primitives/zcash_note_encryption.rs @@ -26,7 +26,7 @@ pub fn decrypts_successfully(transaction: &Transaction, network: &Network, heigh if let Some(bundle) = alt_tx.sapling_bundle() { for output in bundle.shielded_outputs().iter() { let recovery = zcash_primitives::sapling::note_encryption::try_sapling_output_recovery( - &::from(network), + network, alt_height, &null_sapling_ovk, output, diff --git a/zebra-chain/src/primitives/zcash_primitives.rs b/zebra-chain/src/primitives/zcash_primitives.rs index c4e439184..564afab09 100644 --- a/zebra-chain/src/primitives/zcash_primitives.rs +++ b/zebra-chain/src/primitives/zcash_primitives.rs @@ -328,29 +328,11 @@ pub(crate) fn transparent_output_address( match alt_addr { Some(zcash_primitives::legacy::TransparentAddress::PublicKey(pub_key_hash)) => Some( - transparent::Address::from_pub_key_hash(network, pub_key_hash), + transparent::Address::from_pub_key_hash(network.kind(), pub_key_hash), + ), + Some(zcash_primitives::legacy::TransparentAddress::Script(script_hash)) => Some( + transparent::Address::from_script_hash(network.kind(), script_hash), ), - Some(zcash_primitives::legacy::TransparentAddress::Script(script_hash)) => { - Some(transparent::Address::from_script_hash(network, script_hash)) - } None => None, } } - -impl From<&Network> for zcash_primitives::consensus::Network { - fn from(network: &Network) -> Self { - match network { - Network::Mainnet => zcash_primitives::consensus::Network::MainNetwork, - Network::Testnet => zcash_primitives::consensus::Network::TestNetwork, - } - } -} - -impl From for Network { - fn from(network: zcash_primitives::consensus::Network) -> Self { - match network { - zcash_primitives::consensus::Network::MainNetwork => Network::Mainnet, - zcash_primitives::consensus::Network::TestNetwork => Network::Testnet, - } - } -} diff --git a/zebra-chain/src/sapling/arbitrary.rs b/zebra-chain/src/sapling/arbitrary.rs index 403633a1b..7d1029657 100644 --- a/zebra-chain/src/sapling/arbitrary.rs +++ b/zebra-chain/src/sapling/arbitrary.rs @@ -5,7 +5,7 @@ use jubjub::{AffinePoint, ExtendedPoint}; use rand::SeedableRng; use rand_chacha::ChaChaRng; -use proptest::{arbitrary::any, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; use crate::primitives::Groth16Proof; diff --git a/zebra-chain/src/sapling/commitment.rs b/zebra-chain/src/sapling/commitment.rs index 1ef230815..5256d324b 100644 --- a/zebra-chain/src/sapling/commitment.rs +++ b/zebra-chain/src/sapling/commitment.rs @@ -1,9 +1,6 @@ //! Note and value commitments. -use std::{ - convert::{TryFrom, TryInto}, - fmt, io, -}; +use std::{fmt, io}; use bitvec::prelude::*; use jubjub::ExtendedPoint; diff --git a/zebra-chain/src/sapling/keys.rs b/zebra-chain/src/sapling/keys.rs index 2037e368a..7b6e783b8 100644 --- a/zebra-chain/src/sapling/keys.rs +++ b/zebra-chain/src/sapling/keys.rs @@ -16,7 +16,7 @@ use rand_core::{CryptoRng, RngCore}; use crate::{ error::{AddressError, RandError}, - primitives::redjubjub::{self, SpendAuth}, + primitives::redjubjub::SpendAuth, serialization::{ serde_helpers, ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize, }, diff --git a/zebra-chain/src/sapling/note/arbitrary.rs b/zebra-chain/src/sapling/note/arbitrary.rs index e6b38f124..e9365de80 100644 --- a/zebra-chain/src/sapling/note/arbitrary.rs +++ b/zebra-chain/src/sapling/note/arbitrary.rs @@ -1,4 +1,4 @@ -use proptest::{arbitrary::any, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; use super::*; diff --git a/zebra-chain/src/sapling/spend.rs b/zebra-chain/src/sapling/spend.rs index 5b634e9ae..d7545f70a 100644 --- a/zebra-chain/src/sapling/spend.rs +++ b/zebra-chain/src/sapling/spend.rs @@ -3,14 +3,11 @@ //! Zebra uses a generic spend type for `V4` and `V5` transactions. //! The anchor change is handled using the `AnchorVariant` type trait. -use std::{convert::TryInto, fmt, io}; +use std::{fmt, io}; use crate::{ block::MAX_BLOCK_BYTES, - primitives::{ - redjubjub::{self, SpendAuth}, - Groth16Proof, - }, + primitives::{redjubjub::SpendAuth, Groth16Proof}, serialization::{ ReadZcashExt, SerializationError, TrustedPreallocate, WriteZcashExt, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize, diff --git a/zebra-chain/src/sapling/tests/prop.rs b/zebra-chain/src/sapling/tests/prop.rs index 108de8a70..a65ef7dfd 100644 --- a/zebra-chain/src/sapling/tests/prop.rs +++ b/zebra-chain/src/sapling/tests/prop.rs @@ -8,7 +8,6 @@ use crate::{ serialization::{ZcashDeserializeInto, ZcashSerialize}, transaction::{LockTime, Transaction}, }; -use std::convert::TryInto; proptest! { /// Serialize and deserialize `Spend` diff --git a/zebra-chain/src/sapling/tests/tree.rs b/zebra-chain/src/sapling/tests/tree.rs index 17ee640f0..37773e01e 100644 --- a/zebra-chain/src/sapling/tests/tree.rs +++ b/zebra-chain/src/sapling/tests/tree.rs @@ -51,8 +51,9 @@ fn incremental_roots() { #[test] fn incremental_roots_with_blocks() -> Result<()> { - incremental_roots_with_blocks_for_network(Network::Mainnet)?; - incremental_roots_with_blocks_for_network(Network::Testnet)?; + for network in Network::iter() { + incremental_roots_with_blocks_for_network(network)?; + } Ok(()) } diff --git a/zebra-chain/src/sapling/tree.rs b/zebra-chain/src/sapling/tree.rs index 1d11620ba..7b137422b 100644 --- a/zebra-chain/src/sapling/tree.rs +++ b/zebra-chain/src/sapling/tree.rs @@ -19,7 +19,7 @@ use std::{ }; use bitvec::prelude::*; -use bridgetree::{self, NonEmptyFrontier}; +use bridgetree::NonEmptyFrontier; use hex::ToHex; use incrementalmerkletree::{frontier::Frontier, Hashable}; diff --git a/zebra-chain/src/serialization/arbitrary.rs b/zebra-chain/src/serialization/arbitrary.rs index 15d4fe5a4..ab1b5abfb 100644 --- a/zebra-chain/src/serialization/arbitrary.rs +++ b/zebra-chain/src/serialization/arbitrary.rs @@ -1,9 +1,7 @@ //! Arbitrary data generation for serialization proptests -use std::convert::TryInto; - use chrono::{DateTime, TimeZone, Utc}; -use proptest::{arbitrary::any, prelude::*}; +use proptest::prelude::*; use super::{ CompactSizeMessage, DateTime32, TrustedPreallocate, ZcashSerialize, MAX_PROTOCOL_MESSAGE_LEN, diff --git a/zebra-chain/src/serialization/compact_size.rs b/zebra-chain/src/serialization/compact_size.rs index 0cb073ef8..b62f915ae 100644 --- a/zebra-chain/src/serialization/compact_size.rs +++ b/zebra-chain/src/serialization/compact_size.rs @@ -5,8 +5,6 @@ //! - [`CompactSizeMessage`] for sizes that must be less than the network message limit, and //! - [`CompactSize64`] for flags, arbitrary counts, and sizes that span multiple blocks. -use std::convert::{TryFrom, TryInto}; - use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crate::serialization::{ diff --git a/zebra-chain/src/serialization/constraint.rs b/zebra-chain/src/serialization/constraint.rs index 262d4e37f..a4ffc5659 100644 --- a/zebra-chain/src/serialization/constraint.rs +++ b/zebra-chain/src/serialization/constraint.rs @@ -1,9 +1,6 @@ //! Serialization constraint helpers. -use std::{ - convert::{TryFrom, TryInto}, - ops::Deref, -}; +use std::ops::Deref; use crate::serialization::SerializationError; diff --git a/zebra-chain/src/serialization/tests/preallocate.rs b/zebra-chain/src/serialization/tests/preallocate.rs index 592e4b816..405fd1365 100644 --- a/zebra-chain/src/serialization/tests/preallocate.rs +++ b/zebra-chain/src/serialization/tests/preallocate.rs @@ -2,7 +2,7 @@ use proptest::{collection::size_range, prelude::*}; -use std::{convert::TryInto, matches}; +use std::matches; use crate::serialization::{ arbitrary::max_allocation_is_big_enough, zcash_deserialize::MAX_U8_ALLOCATION, diff --git a/zebra-chain/src/sprout/arbitrary.rs b/zebra-chain/src/sprout/arbitrary.rs index a66a7d192..0cce35078 100644 --- a/zebra-chain/src/sprout/arbitrary.rs +++ b/zebra-chain/src/sprout/arbitrary.rs @@ -1,4 +1,4 @@ -use proptest::{arbitrary::any, array, prelude::*}; +use proptest::{array, prelude::*}; use crate::{ amount::{Amount, NonNegative}, diff --git a/zebra-chain/src/sprout/note/arbitrary.rs b/zebra-chain/src/sprout/note/arbitrary.rs index ae7090f53..7bddb2146 100644 --- a/zebra-chain/src/sprout/note/arbitrary.rs +++ b/zebra-chain/src/sprout/note/arbitrary.rs @@ -1,4 +1,4 @@ -use proptest::{arbitrary::any, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; impl Arbitrary for super::EncryptedNote { type Parameters = (); diff --git a/zebra-chain/src/sprout/tests/tree.rs b/zebra-chain/src/sprout/tests/tree.rs index f71c8c6a3..f04ee9af3 100644 --- a/zebra-chain/src/sprout/tests/tree.rs +++ b/zebra-chain/src/sprout/tests/tree.rs @@ -79,9 +79,9 @@ fn incremental_roots() { #[test] fn incremental_roots_with_blocks() -> Result<()> { - incremental_roots_with_blocks_for_network(Network::Mainnet)?; - incremental_roots_with_blocks_for_network(Network::Testnet)?; - + for network in Network::iter() { + incremental_roots_with_blocks_for_network(network)?; + } Ok(()) } diff --git a/zebra-chain/src/tests/vectors.rs b/zebra-chain/src/tests/vectors.rs index 0e60f6e99..deb2a5077 100644 --- a/zebra-chain/src/tests/vectors.rs +++ b/zebra-chain/src/tests/vectors.rs @@ -30,7 +30,9 @@ impl Network { } } + /// Returns blocks indexed by height in a [`BTreeMap`]. /// + /// Returns Mainnet blocks if `self` is set to Mainnet, and Testnet blocks otherwise. pub fn block_map(&self) -> BTreeMap { if self.is_mainnet() { zebra_test::vectors::MAINNET_BLOCKS.clone() diff --git a/zebra-chain/src/transaction/arbitrary.rs b/zebra-chain/src/transaction/arbitrary.rs index f459af7f4..432b83b2b 100644 --- a/zebra-chain/src/transaction/arbitrary.rs +++ b/zebra-chain/src/transaction/arbitrary.rs @@ -1,17 +1,9 @@ //! Arbitrary data generation for transaction proptests -use std::{ - cmp::max, - collections::HashMap, - convert::{TryFrom, TryInto}, - ops::Neg, - sync::Arc, -}; +use std::{cmp::max, collections::HashMap, ops::Neg, sync::Arc}; use chrono::{TimeZone, Utc}; -use proptest::{ - arbitrary::any, array, collection::vec, option, prelude::*, test_runner::TestRunner, -}; +use proptest::{array, collection::vec, option, prelude::*, test_runner::TestRunner}; use reddsa::{orchard::Binding, Signature}; use crate::{ diff --git a/zebra-chain/src/transaction/hash.rs b/zebra-chain/src/transaction/hash.rs index 5c644d0e7..a7fa60066 100644 --- a/zebra-chain/src/transaction/hash.rs +++ b/zebra-chain/src/transaction/hash.rs @@ -28,11 +28,7 @@ //! //! [1]: crate::transaction::UnminedTx -use std::{ - convert::{TryFrom, TryInto}, - fmt, - sync::Arc, -}; +use std::{fmt, sync::Arc}; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; diff --git a/zebra-chain/src/transaction/memo.rs b/zebra-chain/src/transaction/memo.rs index 15d1c8359..a4d3c07b6 100644 --- a/zebra-chain/src/transaction/memo.rs +++ b/zebra-chain/src/transaction/memo.rs @@ -1,4 +1,4 @@ -use std::{cmp, convert::TryFrom, fmt}; +use std::{cmp, fmt}; /// A 512-byte (plaintext) memo associated with a note, as described in /// [protocol specification §5.5][ps]. diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index dd8a8c2e4..044db7d51 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -1,10 +1,10 @@ //! Contains impls of `ZcashSerialize`, `ZcashDeserialize` for all of the //! transaction types, so that all of the serialization logic is in one place. -use std::{borrow::Borrow, convert::TryInto, io, sync::Arc}; +use std::{borrow::Borrow, io, sync::Arc}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use halo2::pasta::{group::ff::PrimeField, pallas}; +use halo2::pasta::group::ff::PrimeField; use hex::FromHex; use reddsa::{orchard::Binding, orchard::SpendAuth, Signature}; @@ -12,13 +12,12 @@ use crate::{ amount, block::MAX_BLOCK_BYTES, parameters::{OVERWINTER_VERSION_GROUP_ID, SAPLING_VERSION_GROUP_ID, TX_V5_VERSION_GROUP_ID}, - primitives::{Groth16Proof, Halo2Proof, ZkSnarkProof}, + primitives::{Halo2Proof, ZkSnarkProof}, serialization::{ zcash_deserialize_external_count, zcash_serialize_empty_list, zcash_serialize_external_count, AtLeastOne, ReadZcashExt, SerializationError, TrustedPreallocate, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize, }, - sprout, }; use super::*; diff --git a/zebra-chain/src/transaction/tests/vectors.rs b/zebra-chain/src/transaction/tests/vectors.rs index 129565a6c..7115d7f36 100644 --- a/zebra-chain/src/transaction/tests/vectors.rs +++ b/zebra-chain/src/transaction/tests/vectors.rs @@ -5,11 +5,10 @@ use color_eyre::eyre::Result; use lazy_static::lazy_static; use crate::{ - amount::Amount, block::{Block, Height, MAX_BLOCK_BYTES}, - parameters::{Network, NetworkUpgrade}, + parameters::Network, serialization::{SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize}, - transaction::{hash::WtxId, sighash::SigHasher, txid::TxIdBuilder, Transaction}, + transaction::{sighash::SigHasher, txid::TxIdBuilder}, transparent::Script, }; @@ -343,9 +342,9 @@ fn empty_v5_librustzcash_round_trip() { #[test] fn fake_v5_round_trip() { let _init_guard = zebra_test::init(); - - fake_v5_round_trip_for_network(Network::Mainnet); - fake_v5_round_trip_for_network(Network::Testnet); + for network in Network::iter() { + fake_v5_round_trip_for_network(network); + } } fn fake_v5_round_trip_for_network(network: Network) { @@ -491,9 +490,9 @@ fn invalid_orchard_nullifier() { #[test] fn fake_v5_librustzcash_round_trip() { let _init_guard = zebra_test::init(); - - fake_v5_librustzcash_round_trip_for_network(Network::Mainnet); - fake_v5_librustzcash_round_trip_for_network(Network::Testnet); + for network in Network::iter() { + fake_v5_librustzcash_round_trip_for_network(network); + } } fn fake_v5_librustzcash_round_trip_for_network(network: Network) { @@ -931,9 +930,9 @@ fn zip244_sighash() -> Result<()> { #[test] fn binding_signatures() { let _init_guard = zebra_test::init(); - - binding_signatures_for_network(Network::Mainnet); - binding_signatures_for_network(Network::Testnet); + for network in Network::iter() { + binding_signatures_for_network(network); + } } fn binding_signatures_for_network(network: Network) { diff --git a/zebra-chain/src/transaction/txid.rs b/zebra-chain/src/transaction/txid.rs index f8b71aec7..f67f6dee5 100644 --- a/zebra-chain/src/transaction/txid.rs +++ b/zebra-chain/src/transaction/txid.rs @@ -1,6 +1,6 @@ //! Transaction ID computation. Contains code for generating the Transaction ID //! from the transaction. -use std::{convert::TryInto, io}; +use std::io; use super::{Hash, Transaction}; use crate::serialization::{sha256d, ZcashSerialize}; diff --git a/zebra-chain/src/transparent/address.rs b/zebra-chain/src/transparent/address.rs index 0c7ab62de..1b933af2e 100644 --- a/zebra-chain/src/transparent/address.rs +++ b/zebra-chain/src/transparent/address.rs @@ -2,12 +2,8 @@ use std::{fmt, io}; -use ripemd::{Digest, Ripemd160}; -use secp256k1::PublicKey; -use sha2::Sha256; - use crate::{ - parameters::Network, + parameters::NetworkKind, serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, transparent::{opcodes::OpCode, Script}, }; @@ -29,15 +25,11 @@ use proptest::prelude::*; #[derive( Clone, Eq, PartialEq, Hash, serde_with::SerializeDisplay, serde_with::DeserializeFromStr, )] -#[cfg_attr( - any(test, feature = "proptest-impl"), - derive(proptest_derive::Arbitrary) -)] pub enum Address { /// P2SH (Pay to Script Hash) addresses PayToScriptHash { /// Production, test, or other network - network: Network, + network_kind: NetworkKind, /// 20 bytes specifying a script hash. script_hash: [u8; 20], }, @@ -45,7 +37,7 @@ pub enum Address { /// P2PKH (Pay to Public Key Hash) addresses PayToPublicKeyHash { /// Production, test, or other network - network: Network, + network_kind: NetworkKind, /// 20 bytes specifying a public key hash, which is a RIPEMD-160 /// hash of a SHA-256 hash of a compressed ECDSA key encoding. pub_key_hash: [u8; 20], @@ -58,17 +50,17 @@ impl fmt::Debug for Address { match self { Address::PayToScriptHash { - network, + network_kind, script_hash, } => debug_struct - .field("network", network) + .field("network_kind", network_kind) .field("script_hash", &hex::encode(script_hash)) .finish(), Address::PayToPublicKeyHash { - network, + network_kind, pub_key_hash, } => debug_struct - .field("network", network) + .field("network_kind", network_kind) .field("pub_key_hash", &hex::encode(pub_key_hash)) .finish(), } @@ -101,17 +93,17 @@ impl ZcashSerialize for Address { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { match self { Address::PayToScriptHash { - network, + network_kind, script_hash, } => { - writer.write_all(&network.b58_script_address_prefix())?; + writer.write_all(&network_kind.b58_script_address_prefix())?; writer.write_all(script_hash)? } Address::PayToPublicKeyHash { - network, + network_kind, pub_key_hash, } => { - writer.write_all(&network.b58_pubkey_address_prefix())?; + writer.write_all(&network_kind.b58_pubkey_address_prefix())?; writer.write_all(pub_key_hash)? } } @@ -131,25 +123,25 @@ impl ZcashDeserialize for Address { match version_bytes { zcash_primitives::constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX => { Ok(Address::PayToScriptHash { - network: Network::Mainnet, + network_kind: NetworkKind::Mainnet, script_hash: hash_bytes, }) } zcash_primitives::constants::testnet::B58_SCRIPT_ADDRESS_PREFIX => { Ok(Address::PayToScriptHash { - network: Network::Testnet, + network_kind: NetworkKind::Testnet, script_hash: hash_bytes, }) } zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX => { Ok(Address::PayToPublicKeyHash { - network: Network::Mainnet, + network_kind: NetworkKind::Mainnet, pub_key_hash: hash_bytes, }) } zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX => { Ok(Address::PayToPublicKeyHash { - network: Network::Testnet, + network_kind: NetworkKind::Testnet, pub_key_hash: hash_bytes, }) } @@ -158,51 +150,28 @@ impl ZcashDeserialize for Address { } } -trait ToAddressWithNetwork { - /// Convert `self` to an `Address`, given the current `network`. - fn to_address(&self, network: Network) -> Address; -} - -impl ToAddressWithNetwork for Script { - fn to_address(&self, network: Network) -> Address { - Address::PayToScriptHash { - network, - script_hash: Address::hash_payload(self.as_raw_bytes()), - } - } -} - -impl ToAddressWithNetwork for PublicKey { - fn to_address(&self, network: Network) -> Address { - Address::PayToPublicKeyHash { - network, - pub_key_hash: Address::hash_payload(&self.serialize()[..]), - } - } -} - impl Address { /// Create an address for the given public key hash and network. - pub fn from_pub_key_hash(network: &Network, pub_key_hash: [u8; 20]) -> Self { + pub fn from_pub_key_hash(network_kind: NetworkKind, pub_key_hash: [u8; 20]) -> Self { Self::PayToPublicKeyHash { - network: network.clone(), + network_kind, pub_key_hash, } } /// Create an address for the given script hash and network. - pub fn from_script_hash(network: &Network, script_hash: [u8; 20]) -> Self { + pub fn from_script_hash(network_kind: NetworkKind, script_hash: [u8; 20]) -> Self { Self::PayToScriptHash { - network: network.clone(), + network_kind, script_hash, } } - /// Returns the network for this address. - pub fn network(&self) -> Network { + /// Returns the network kind for this address. + pub fn network_kind(&self) -> NetworkKind { match self { - Address::PayToScriptHash { network, .. } => network.clone(), - Address::PayToPublicKeyHash { network, .. } => network.clone(), + Address::PayToScriptHash { network_kind, .. } => *network_kind, + Address::PayToPublicKeyHash { network_kind, .. } => *network_kind, } } @@ -223,21 +192,6 @@ impl Address { } } - /// A hash of a transparent address payload, as used in - /// transparent pay-to-script-hash and pay-to-publickey-hash - /// addresses. - /// - /// The resulting hash in both of these cases is always exactly 20 - /// bytes. - /// - fn hash_payload(bytes: &[u8]) -> [u8; 20] { - let sha_hash = Sha256::digest(bytes); - let ripe_hash = Ripemd160::digest(sha_hash); - let mut payload = [0u8; 20]; - payload[..].copy_from_slice(&ripe_hash[..]); - payload - } - /// Given a transparent address (P2SH or a P2PKH), create a script that can be used in a coinbase /// transaction output. pub fn create_script_from_address(&self) -> Script { @@ -268,11 +222,53 @@ impl Address { #[cfg(test)] mod tests { - + use ripemd::{Digest, Ripemd160}; use secp256k1::PublicKey; + use sha2::Sha256; use super::*; + trait ToAddressWithNetwork { + /// Convert `self` to an `Address`, given the current `network`. + fn to_address(&self, network: NetworkKind) -> Address; + } + + impl ToAddressWithNetwork for Script { + fn to_address(&self, network_kind: NetworkKind) -> Address { + Address::PayToScriptHash { + network_kind, + script_hash: Address::hash_payload(self.as_raw_bytes()), + } + } + } + + impl ToAddressWithNetwork for PublicKey { + fn to_address(&self, network_kind: NetworkKind) -> Address { + Address::PayToPublicKeyHash { + network_kind, + pub_key_hash: Address::hash_payload(&self.serialize()[..]), + } + } + } + + impl Address { + /// A hash of a transparent address payload, as used in + /// transparent pay-to-script-hash and pay-to-publickey-hash + /// addresses. + /// + /// The resulting hash in both of these cases is always exactly 20 + /// bytes. + /// + #[allow(dead_code)] + fn hash_payload(bytes: &[u8]) -> [u8; 20] { + let sha_hash = Sha256::digest(bytes); + let ripe_hash = Ripemd160::digest(sha_hash); + let mut payload = [0u8; 20]; + payload[..].copy_from_slice(&ripe_hash[..]); + payload + } + } + #[test] fn pubkey_mainnet() { let _init_guard = zebra_test::init(); @@ -283,7 +279,7 @@ mod tests { ]) .expect("A PublicKey from slice"); - let t_addr = pub_key.to_address(Network::Mainnet); + let t_addr = pub_key.to_address(NetworkKind::Mainnet); assert_eq!(format!("{t_addr}"), "t1bmMa1wJDFdbc2TiURQP5BbBz6jHjUBuHq"); } @@ -298,7 +294,7 @@ mod tests { ]) .expect("A PublicKey from slice"); - let t_addr = pub_key.to_address(Network::Testnet); + let t_addr = pub_key.to_address(NetworkKind::Testnet); assert_eq!(format!("{t_addr}"), "tmTc6trRhbv96kGfA99i7vrFwb5p7BVFwc3"); } @@ -309,7 +305,7 @@ mod tests { let script = Script::new(&[0u8; 20]); - let t_addr = script.to_address(Network::Mainnet); + let t_addr = script.to_address(NetworkKind::Mainnet); assert_eq!(format!("{t_addr}"), "t3Y5pHwfgHbS6pDjj1HLuMFxhFFip1fcJ6g"); } @@ -320,7 +316,7 @@ mod tests { let script = Script::new(&[0; 20]); - let t_addr = script.to_address(Network::Testnet); + let t_addr = script.to_address(NetworkKind::Testnet); assert_eq!(format!("{t_addr}"), "t2L51LcmpA43UMvKTw2Lwtt9LMjwyqU2V1P"); } @@ -342,7 +338,7 @@ mod tests { assert_eq!( format!("{t_addr:?}"), - "TransparentAddress { network: Mainnet, script_hash: \"7d46a730d31f97b1930d3368a967c309bd4d136a\" }" + "TransparentAddress { network_kind: Mainnet, script_hash: \"7d46a730d31f97b1930d3368a967c309bd4d136a\" }" ); } } diff --git a/zebra-chain/src/transparent/arbitrary.rs b/zebra-chain/src/transparent/arbitrary.rs index f7678bdc8..c9e9bdb1d 100644 --- a/zebra-chain/src/transparent/arbitrary.rs +++ b/zebra-chain/src/transparent/arbitrary.rs @@ -1,8 +1,8 @@ -use proptest::{arbitrary::any, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; -use crate::{block, LedgerState}; +use crate::{block, parameters::NetworkKind, LedgerState}; -use super::{CoinbaseData, Input, OutPoint, Script, GENESIS_COINBASE_DATA}; +use super::{Address, CoinbaseData, Input, OutPoint, Script, GENESIS_COINBASE_DATA}; impl Input { /// Construct a strategy for creating valid-ish vecs of Inputs. @@ -46,3 +46,27 @@ impl Arbitrary for Input { type Strategy = BoxedStrategy; } + +impl Arbitrary for Address { + type Parameters = (); + + fn arbitrary_with(_args: ()) -> Self::Strategy { + any::<(bool, bool, [u8; 20])>() + .prop_map(|(is_mainnet, is_p2pkh, hash_bytes)| { + let network = if is_mainnet { + NetworkKind::Mainnet + } else { + NetworkKind::Testnet + }; + + if is_p2pkh { + Address::from_pub_key_hash(network, hash_bytes) + } else { + Address::from_script_hash(network, hash_bytes) + } + }) + .boxed() + } + + type Strategy = BoxedStrategy; +} diff --git a/zebra-chain/src/transparent/script.rs b/zebra-chain/src/transparent/script.rs index ebc442450..e3c49b9e1 100644 --- a/zebra-chain/src/transparent/script.rs +++ b/zebra-chain/src/transparent/script.rs @@ -95,7 +95,6 @@ mod proptests { use proptest::prelude::*; use super::*; - use crate::serialization::{ZcashDeserialize, ZcashSerialize}; proptest! { #[test] diff --git a/zebra-chain/src/transparent/tests/vectors.rs b/zebra-chain/src/transparent/tests/vectors.rs index d3ceae413..f83dbf1c6 100644 --- a/zebra-chain/src/transparent/tests/vectors.rs +++ b/zebra-chain/src/transparent/tests/vectors.rs @@ -67,15 +67,17 @@ fn get_transparent_output_address() -> Result<()> { let addr = transparent_output_address(&transaction.outputs()[0], &Network::Mainnet) .expect("should return address"); assert_eq!(addr.to_string(), "t3M5FDmPfWNRG3HRLddbicsuSCvKuk9hxzZ"); - let addr = transparent_output_address(&transaction.outputs()[0], &Network::Testnet) - .expect("should return address"); + let addr = + transparent_output_address(&transaction.outputs()[0], &Network::new_default_testnet()) + .expect("should return address"); assert_eq!(addr.to_string(), "t294SGSVoNq2daz15ZNbmAW65KQZ5e3nN5G"); // Public key hash e4ff5512ffafe9287992a1cd177ca6e408e03003 let addr = transparent_output_address(&transaction.outputs()[1], &Network::Mainnet) .expect("should return address"); assert_eq!(addr.to_string(), "t1ekRwsd4LaSsd6NXgsx66q2HxQWTLCF44y"); - let addr = transparent_output_address(&transaction.outputs()[1], &Network::Testnet) - .expect("should return address"); + let addr = + transparent_output_address(&transaction.outputs()[1], &Network::new_default_testnet()) + .expect("should return address"); assert_eq!(addr.to_string(), "tmWbBGi7TjExNmLZyMcFpxVh3ZPbGrpbX3H"); Ok(()) @@ -84,9 +86,9 @@ fn get_transparent_output_address() -> Result<()> { #[test] fn get_transparent_output_address_with_blocks() { let _init_guard = zebra_test::init(); - - get_transparent_output_address_with_blocks_for_network(Network::Mainnet); - get_transparent_output_address_with_blocks_for_network(Network::Testnet); + for network in Network::iter() { + get_transparent_output_address_with_blocks_for_network(network); + } } /// Test that the block test vector indexes match the heights in the block data, diff --git a/zebra-chain/src/transparent/utxo.rs b/zebra-chain/src/transparent/utxo.rs index db626148e..015816519 100644 --- a/zebra-chain/src/transparent/utxo.rs +++ b/zebra-chain/src/transparent/utxo.rs @@ -1,6 +1,6 @@ //! Unspent transparent output data structures and functions. -use std::{collections::HashMap, convert::TryInto}; +use std::collections::HashMap; use crate::{ block::{self, Block, Height}, diff --git a/zebra-chain/src/value_balance.rs b/zebra-chain/src/value_balance.rs index 43f7b11b4..dc56f70b8 100644 --- a/zebra-chain/src/value_balance.rs +++ b/zebra-chain/src/value_balance.rs @@ -6,7 +6,7 @@ use crate::{ transparent, }; -use std::{borrow::Borrow, collections::HashMap, convert::TryInto}; +use std::{borrow::Borrow, collections::HashMap}; #[cfg(any(test, feature = "proptest-impl"))] use crate::{amount::MAX_MONEY, transaction::Transaction}; diff --git a/zebra-chain/src/work/arbitrary.rs b/zebra-chain/src/work/arbitrary.rs index a1a03468d..eac18f63a 100644 --- a/zebra-chain/src/work/arbitrary.rs +++ b/zebra-chain/src/work/arbitrary.rs @@ -1,6 +1,6 @@ use super::*; -use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; impl Arbitrary for equihash::Solution { type Parameters = (); diff --git a/zebra-chain/src/work/difficulty.rs b/zebra-chain/src/work/difficulty.rs index 9c5252c2b..c13210923 100644 --- a/zebra-chain/src/work/difficulty.rs +++ b/zebra-chain/src/work/difficulty.rs @@ -699,7 +699,8 @@ impl ParameterDifficulty for Network { /* 2^243 - 1 */ Network::Mainnet => (U256::one() << 243) - 1, /* 2^251 - 1 */ - Network::Testnet => (U256::one() << 251) - 1, + // TODO: Add a `target_difficulty_limit` field to `testnet::Parameters` to return here. + Network::Testnet(_params) => (U256::one() << 251) - 1, }; // `zcashd` converts the PoWLimit into a compact representation before diff --git a/zebra-chain/src/work/difficulty/arbitrary.rs b/zebra-chain/src/work/difficulty/arbitrary.rs index 1e6c93032..96d1f9053 100644 --- a/zebra-chain/src/work/difficulty/arbitrary.rs +++ b/zebra-chain/src/work/difficulty/arbitrary.rs @@ -1,8 +1,6 @@ use super::*; -use crate::block; - -use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; impl Arbitrary for CompactDifficulty { type Parameters = (); diff --git a/zebra-chain/src/work/difficulty/tests/prop.rs b/zebra-chain/src/work/difficulty/tests/prop.rs index a33fb5940..9be589f7b 100644 --- a/zebra-chain/src/work/difficulty/tests/prop.rs +++ b/zebra-chain/src/work/difficulty/tests/prop.rs @@ -1,8 +1,4 @@ -use proptest::{arbitrary::any, prelude::*}; - -use std::cmp::Ordering; - -use crate::block; +use proptest::prelude::*; use super::super::*; diff --git a/zebra-chain/src/work/difficulty/tests/vectors.rs b/zebra-chain/src/work/difficulty/tests/vectors.rs index 9f9c03544..09250e6b2 100644 --- a/zebra-chain/src/work/difficulty/tests/vectors.rs +++ b/zebra-chain/src/work/difficulty/tests/vectors.rs @@ -263,8 +263,9 @@ fn compact_bitcoin_test_vectors() { /// Test blocks using CompactDifficulty. #[test] fn block_difficulty() -> Result<(), Report> { - block_difficulty_for_network(Network::Mainnet)?; - block_difficulty_for_network(Network::Testnet)?; + for network in Network::iter() { + block_difficulty_for_network(network)?; + } Ok(()) } @@ -349,8 +350,9 @@ fn block_difficulty_for_network(network: Network) -> Result<(), Report> { /// Test that the genesis block threshold is PowLimit #[test] fn genesis_block_difficulty() -> Result<(), Report> { - genesis_block_difficulty_for_network(Network::Mainnet)?; - genesis_block_difficulty_for_network(Network::Testnet)?; + for network in Network::iter() { + genesis_block_difficulty_for_network(network)?; + } Ok(()) } @@ -454,7 +456,10 @@ fn check_testnet_minimum_difficulty_block(height: block::Height) -> Result<(), R // threshold, as documented in ZIP-205 and ZIP-208: // https://zips.z.cash/zip-0205#change-to-difficulty-adjustment-on-testnet // https://zips.z.cash/zip-0208#minimum-difficulty-blocks-on-testnet - match NetworkUpgrade::minimum_difficulty_spacing_for_height(&Network::Testnet, height) { + match NetworkUpgrade::minimum_difficulty_spacing_for_height( + &Network::new_default_testnet(), + height, + ) { None => Err(eyre!("the minimum difficulty rule is not active"))?, Some(spacing) if (time_gap <= spacing) => Err(eyre!( "minimum difficulty block times must be more than 6 target spacing intervals apart" @@ -477,12 +482,12 @@ fn check_testnet_minimum_difficulty_block(height: block::Height) -> Result<(), R /// SPANDOC: Check that the testnet minimum difficulty is the PoWLimit {?height, ?threshold, ?hash} { - assert_eq!(threshold, Network::Testnet.target_difficulty_limit(), + assert_eq!(threshold, Network::new_default_testnet().target_difficulty_limit(), "testnet minimum difficulty thresholds should be equal to the PoWLimit. Hint: Blocks with large gaps are allowed to have the minimum difficulty, but it's not required."); // all blocks pass the minimum difficulty threshold, even if they aren't minimum // difficulty blocks, because it's the lowest permitted difficulty assert!( - hash <= Network::Testnet.target_difficulty_limit(), + hash <= Network::new_default_testnet().target_difficulty_limit(), "testnet minimum difficulty hashes must be less than the PoWLimit" ); } diff --git a/zebra-chain/src/work/tests/prop.rs b/zebra-chain/src/work/tests/prop.rs index f5bdf0109..c11f1eb23 100644 --- a/zebra-chain/src/work/tests/prop.rs +++ b/zebra-chain/src/work/tests/prop.rs @@ -2,7 +2,7 @@ use std::{env, sync::Arc}; -use proptest::{arbitrary::any, prelude::*, test_runner::Config}; +use proptest::{prelude::*, test_runner::Config}; use crate::{ block::{self, Block}, diff --git a/zebra-chain/src/work/tests/vectors.rs b/zebra-chain/src/work/tests/vectors.rs index ab1f51955..06a752de0 100644 --- a/zebra-chain/src/work/tests/vectors.rs +++ b/zebra-chain/src/work/tests/vectors.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use crate::{ block::{Block, MAX_BLOCK_BYTES}, serialization::{CompactSizeMessage, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize}, diff --git a/zebra-consensus/Cargo.toml b/zebra-consensus/Cargo.toml index e2a0a645c..165558fc5 100644 --- a/zebra-consensus/Cargo.toml +++ b/zebra-consensus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-consensus" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "Implementation of Zcash consensus checks" license = "MIT OR Apache-2.0" @@ -41,7 +41,7 @@ bls12_381 = "0.8.0" halo2 = { package = "halo2_proofs", version = "0.3.0" } jubjub = "0.10.0" rand = "0.8.5" -rayon = "1.9.0" +rayon = "1.10.0" chrono = { version = "0.4.34", default-features = false, features = ["clock", "std"] } displaydoc = "0.2.4" @@ -53,7 +53,7 @@ futures = "0.3.30" futures-util = "0.3.28" metrics = "0.22.3" thiserror = "1.0.58" -tokio = { version = "1.36.0", features = ["time", "sync", "tracing", "rt-multi-thread"] } +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" tracing-futures = "0.2.5" @@ -63,13 +63,13 @@ orchard = "0.6.0" zcash_proofs = { version = "0.13.0-rc.1", features = ["multicore" ] } wagyu-zcash-parameters = "0.2.0" -tower-fallback = { path = "../tower-fallback/", version = "0.2.41-beta.11" } -tower-batch-control = { path = "../tower-batch-control/", version = "0.2.41-beta.11" } +tower-fallback = { path = "../tower-fallback/", version = "0.2.41-beta.12" } +tower-batch-control = { path = "../tower-batch-control/", version = "0.2.41-beta.12" } -zebra-script = { path = "../zebra-script", version = "1.0.0-beta.35" } -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35" } -zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.35" } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35" } +zebra-script = { path = "../zebra-script", version = "1.0.0-beta.36" } +zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36" } +zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36" } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36" } # prod feature progress-bar howudoin = { version = "0.1.2", optional = true } @@ -90,10 +90,10 @@ proptest = "1.4.0" proptest-derive = "0.4.0" spandoc = "0.2.2" -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } tracing-error = "0.2.0" tracing-subscriber = "0.3.18" -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.35" } +zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.36" } diff --git a/zebra-consensus/src/block/subsidy/funding_streams.rs b/zebra-consensus/src/block/subsidy/funding_streams.rs index 39382e7a2..c3389782b 100644 --- a/zebra-consensus/src/block/subsidy/funding_streams.rs +++ b/zebra-consensus/src/block/subsidy/funding_streams.rs @@ -29,7 +29,7 @@ pub fn funding_stream_values( let mut results = HashMap::new(); if height >= canopy_height { - let range = FUNDING_STREAM_HEIGHT_RANGES.get(network).unwrap(); + let range = FUNDING_STREAM_HEIGHT_RANGES.get(&network.kind()).unwrap(); if range.contains(&height) { let block_subsidy = block_subsidy(height, network)?; for (&receiver, &numerator) in FUNDING_STREAM_RECEIVER_NUMERATORS.iter() { @@ -83,7 +83,10 @@ fn funding_stream_address_index(height: Height, network: &Network) -> usize { .checked_add(funding_stream_address_period(height, network)) .expect("no overflow should happen in this sum") .checked_sub(funding_stream_address_period( - FUNDING_STREAM_HEIGHT_RANGES.get(network).unwrap().start, + FUNDING_STREAM_HEIGHT_RANGES + .get(&network.kind()) + .unwrap() + .start, network, )) .expect("no overflow should happen in this sub") as usize; @@ -105,7 +108,7 @@ pub fn funding_stream_address( ) -> transparent::Address { let index = funding_stream_address_index(height, network); let address = &FUNDING_STREAM_ADDRESSES - .get(network) + .get(&network.kind()) .expect("there is always another hash map as value for a given valid network") .get(&receiver) .expect("in the inner hash map there is always a vector of strings with addresses")[index]; diff --git a/zebra-consensus/src/block/subsidy/funding_streams/tests.rs b/zebra-consensus/src/block/subsidy/funding_streams/tests.rs index 763fa1727..7f6011a42 100644 --- a/zebra-consensus/src/block/subsidy/funding_streams/tests.rs +++ b/zebra-consensus/src/block/subsidy/funding_streams/tests.rs @@ -44,7 +44,7 @@ fn test_funding_stream_values() -> Result<(), Report> { ); // funding stream period is ending - let range = FUNDING_STREAM_HEIGHT_RANGES.get(network).unwrap(); + let range = FUNDING_STREAM_HEIGHT_RANGES.get(&network.kind()).unwrap(); let end = range.end; let last = end - 1; @@ -68,7 +68,7 @@ fn test_funding_stream_addresses() -> Result<(), Report> { let address = transparent::Address::from_str(address).expect("address should deserialize"); assert_eq!( - &address.network(), + &address.network_kind(), network, "incorrect network for {receiver:?} funding stream address constant: {address}", ); diff --git a/zebra-consensus/src/block/subsidy/general.rs b/zebra-consensus/src/block/subsidy/general.rs index 37ba1cfe9..5397a0ec7 100644 --- a/zebra-consensus/src/block/subsidy/general.rs +++ b/zebra-consensus/src/block/subsidy/general.rs @@ -2,7 +2,7 @@ //! //! [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies -use std::{collections::HashSet, convert::TryFrom}; +use std::collections::HashSet; use zebra_chain::{ amount::{Amount, Error, NonNegative}, @@ -122,9 +122,9 @@ mod test { #[test] fn halving_test() -> Result<(), Report> { let _init_guard = zebra_test::init(); - - halving_for_network(&Network::Mainnet)?; - halving_for_network(&Network::Testnet)?; + for network in Network::iter() { + halving_for_network(&network)?; + } Ok(()) } @@ -249,8 +249,9 @@ mod test { fn block_subsidy_test() -> Result<(), Report> { let _init_guard = zebra_test::init(); - block_subsidy_for_network(&Network::Mainnet)?; - block_subsidy_for_network(&Network::Testnet)?; + for network in Network::iter() { + block_subsidy_for_network(&network)?; + } Ok(()) } diff --git a/zebra-consensus/src/block/tests.rs b/zebra-consensus/src/block/tests.rs index 44e577b1c..52c24a1f3 100644 --- a/zebra-consensus/src/block/tests.rs +++ b/zebra-consensus/src/block/tests.rs @@ -1,22 +1,18 @@ //! Tests for block verification -use std::sync::Arc; - -use chrono::Utc; use color_eyre::eyre::{eyre, Report}; use once_cell::sync::Lazy; use tower::{buffer::Buffer, util::BoxService}; use zebra_chain::{ - amount::{Amount, MAX_MONEY}, + amount::MAX_MONEY, block::{ - self, tests::generate::{ large_multi_transaction_block, large_single_transaction_block_many_inputs, }, Block, Height, }, - parameters::{Network, NetworkUpgrade}, + parameters::NetworkUpgrade, serialization::{ZcashDeserialize, ZcashDeserializeInto}, transaction::{arbitrary::transaction_to_fake_v5, LockTime, Transaction}, work::difficulty::{ParameterDifficulty as _, INVALID_COMPACT_DIFFICULTY}, @@ -181,9 +177,9 @@ fn coinbase_is_first_for_historical_blocks() -> Result<(), Report> { #[test] fn difficulty_is_valid_for_historical_blocks() -> Result<(), Report> { let _init_guard = zebra_test::init(); - - difficulty_is_valid_for_network(Network::Mainnet)?; - difficulty_is_valid_for_network(Network::Testnet)?; + for network in Network::iter() { + difficulty_is_valid_for_network(network)?; + } Ok(()) } @@ -285,9 +281,9 @@ fn equihash_is_valid_for_historical_blocks() -> Result<(), Report> { #[test] fn subsidy_is_valid_for_historical_blocks() -> Result<(), Report> { let _init_guard = zebra_test::init(); - - subsidy_is_valid_for_network(Network::Mainnet)?; - subsidy_is_valid_for_network(Network::Testnet)?; + for network in Network::iter() { + subsidy_is_valid_for_network(network)?; + } Ok(()) } @@ -388,9 +384,9 @@ fn coinbase_validation_failure() -> Result<(), Report> { #[test] fn funding_stream_validation() -> Result<(), Report> { let _init_guard = zebra_test::init(); - - funding_stream_validation_for_network(Network::Mainnet)?; - funding_stream_validation_for_network(Network::Testnet)?; + for network in Network::iter() { + funding_stream_validation_for_network(network)?; + } Ok(()) } @@ -463,9 +459,9 @@ fn funding_stream_validation_failure() -> Result<(), Report> { #[test] fn miner_fees_validation_success() -> Result<(), Report> { let _init_guard = zebra_test::init(); - - miner_fees_validation_for_network(Network::Mainnet)?; - miner_fees_validation_for_network(Network::Testnet)?; + for network in Network::iter() { + miner_fees_validation_for_network(network)?; + } Ok(()) } @@ -546,12 +542,14 @@ fn merkle_root_is_valid() -> Result<(), Report> { let _init_guard = zebra_test::init(); // test all original blocks available, all blocks validate - merkle_root_is_valid_for_network(Network::Mainnet)?; - merkle_root_is_valid_for_network(Network::Testnet)?; + for network in Network::iter() { + merkle_root_is_valid_for_network(network)?; + } // create and test fake blocks with v5 transactions, all blocks fail validation - merkle_root_fake_v5_for_network(Network::Mainnet)?; - merkle_root_fake_v5_for_network(Network::Testnet)?; + for network in Network::iter() { + merkle_root_fake_v5_for_network(network)?; + } Ok(()) } @@ -683,8 +681,9 @@ fn legacy_sigops_count_for_historic_blocks() { fn transaction_expiration_height_validation() -> Result<(), Report> { let _init_guard = zebra_test::init(); - transaction_expiration_height_for_network(&Network::Mainnet)?; - transaction_expiration_height_for_network(&Network::Testnet)?; + for network in Network::iter() { + transaction_expiration_height_for_network(&network)?; + } Ok(()) } diff --git a/zebra-consensus/src/checkpoint/list.rs b/zebra-consensus/src/checkpoint/list.rs index 2b45e4365..887998482 100644 --- a/zebra-consensus/src/checkpoint/list.rs +++ b/zebra-consensus/src/checkpoint/list.rs @@ -57,7 +57,10 @@ impl ParameterCheckpoint for Network { // zcash-cli getblockhash 0 Network::Mainnet => "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08", // zcash-cli -testnet getblockhash 0 - Network::Testnet => "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38", + // TODO: Add a `genesis_hash` field to `testnet::Parameters` and return it here (#8366) + Network::Testnet(_params) => { + "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38" + } } .parse() .expect("hard-coded hash parses") @@ -65,11 +68,14 @@ impl ParameterCheckpoint for Network { 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 => TESTNET_CHECKPOINTS + Network::Testnet(_params) => TESTNET_CHECKPOINTS .parse() .expect("Hard-coded Testnet checkpoint list parses and validates"), }; @@ -142,9 +148,12 @@ impl CheckpointList { // Check that the list starts with the correct 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 `::checkpoint_list(&network)` method above (#8366), + // See Some((block::Height(0), hash)) if (hash == &Network::Mainnet.genesis_hash() - || hash == &Network::Testnet.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")? } diff --git a/zebra-consensus/src/checkpoint/list/tests.rs b/zebra-consensus/src/checkpoint/list/tests.rs index 0588a365c..09288dfc0 100644 --- a/zebra-consensus/src/checkpoint/list/tests.rs +++ b/zebra-consensus/src/checkpoint/list/tests.rs @@ -5,8 +5,8 @@ use std::sync::Arc; use num_integer::div_ceil; use zebra_chain::{ - block::{self, Block, HeightDiff, MAX_BLOCK_BYTES}, - parameters::{Network, Network::*}, + block::{Block, HeightDiff, MAX_BLOCK_BYTES}, + parameters::Network::*, serialization::ZcashDeserialize, }; use zebra_node_services::constants::{MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP}; @@ -236,7 +236,7 @@ fn checkpoint_list_load_hard_coded() -> Result<(), BoxError> { .expect("hard-coded Testnet checkpoint list should parse"); let _ = Mainnet.checkpoint_list(); - let _ = Testnet.checkpoint_list(); + let _ = Network::new_default_testnet().checkpoint_list(); Ok(()) } @@ -248,7 +248,7 @@ fn checkpoint_list_hard_coded_mandatory_mainnet() -> Result<(), BoxError> { #[test] fn checkpoint_list_hard_coded_mandatory_testnet() -> Result<(), BoxError> { - checkpoint_list_hard_coded_mandatory(Testnet) + checkpoint_list_hard_coded_mandatory(Network::new_default_testnet()) } /// Check that the hard-coded lists cover the mandatory checkpoint @@ -274,7 +274,7 @@ fn checkpoint_list_hard_coded_max_gap_mainnet() -> Result<(), BoxError> { #[test] fn checkpoint_list_hard_coded_max_gap_testnet() -> Result<(), BoxError> { - checkpoint_list_hard_coded_max_gap(Testnet) + checkpoint_list_hard_coded_max_gap(Network::new_default_testnet()) } /// Check that the hard-coded checkpoints are within [`MAX_CHECKPOINT_HEIGHT_GAP`], diff --git a/zebra-consensus/src/checkpoint/main-checkpoints.txt b/zebra-consensus/src/checkpoint/main-checkpoints.txt index 600b614b1..a7a627bc1 100644 --- a/zebra-consensus/src/checkpoint/main-checkpoints.txt +++ b/zebra-consensus/src/checkpoint/main-checkpoints.txt @@ -11639,3 +11639,146 @@ 2409498 00000000000c2894048e8fbbf1108e6a8f84593bf0335223c3c2128543d479a5 2409898 0000000001c5aff172cf4e599395d534772238835404afa53808643fa61dc2fa 2410298 00000000014bcaf8d811cab113e55e64323a260e44112327f14c316e4af04b55 +2410698 000000000074abbb1a77198784055beec34b53988c07d8eaebb0f2274f47833d +2411098 0000000001877576e911283f14dcde318e4731041623c886e84c930d2dcd962b +2411498 000000000080d1a24a7238e7c6ec746dc01c4786ee5819a65935429c498732a8 +2411898 00000000010450f3a9271cbd2afcd1df0a3812892e87e871616bc054a6f5b01d +2412298 0000000001861c83002d9401eaf4d3da9c400de8740d13a54e288c2a7af4f834 +2412698 00000000011703212bedee58979af16f1856f6d30ea7cb84384a9d5a981f5f16 +2413098 000000000123067b2ed14b6684fb476045eb0c8e690cbc48ca512807723d9f7f +2413498 00000000015ec06faaa816f09db1da794d45b5768cbf613a80a30c55127f4456 +2413898 00000000007a4583ab6052ed9a2c22872eab4d2a106089b22ef257688415564f +2414298 0000000000d7b1d31a6f95fea2563136205aa71703913a5f1ad47353360ce25f +2414698 000000000154e7cf6da622ca7a79107f4c3008c118bafdd3082b63daf93c401d +2415098 0000000000cb6415ba52f692bfdc927f2ce6bde5d036452768cfe255f0ca2060 +2415498 0000000000e0fc7f206650ea32e4f962488ed5cd980088fd055fddec61e5a942 +2415898 0000000001332748030a0132e75280fe60b5c9077fb2e25fdcfbbfc9a6cee6ae +2416298 00000000005729a24befc31831b49ca11e265b9ae6216846db404106454a408e +2416698 000000000159a1d4896850cecade845e646a1d6153e1c10633ccf46c12e4d4fb +2417098 0000000001473bdabd3e72b13ed1d28311717e20f0f2ea7b6e2e326d9bac63eb +2417498 00000000012652a761cb0fc7612297644fe8fc08cc0c493e74e0b53dce486894 +2417898 0000000001accf7b75d9013ba2b876da41206aa76fb9a36557522ddd3e2da8f8 +2418298 0000000000c28729dcdd37d2907e70febfbba7ba444a33745da37964d07f0002 +2418698 00000000008b367bca551f930534b52fd498e52e73f32527306f317d480ed6ef +2419098 0000000001bac9fb3e5fc759107f0a1ce9d3432b32a15d6bd01fef4d5dcf7fc7 +2419498 000000000114edeea337f95f92564a0f55c0bb3b98f5709a85c0da680187bf72 +2419898 00000000001fde65e8d493be57542b84f4ee7e3c06b23349cb79c2277ca1724d +2420298 0000000000b0997e0537bba7f3b3339d93eff8fba95032300207ffa23e18aaca +2420698 00000000007d065f53425cec1d871bad4f968d84caec8e09c3697b4fe3fee2b1 +2421098 00000000004a8f4e3d0dadc25630631d0260c6d6984c57c9cd802be2fd821710 +2421498 0000000000ed5e661810a3037445089a1b5dcb7dcfffb5c646f6cb6120cb8522 +2421898 0000000000d3b343f8031d787e6dd65951fe03c467e7a19293e05583604eb9d3 +2422298 00000000017fca9d2048520f0262197bd10d0843c7ed8de7b0cd23b739c0f742 +2422698 00000000012f634dc58c34994a94d04a2474a5318739751a4f9cc260b425d805 +2423098 0000000000d628ccced35b6da464cc40a0b0cf2d8c89213c2476dba74bf5bc49 +2423498 000000000102da5580e43d276a27fd2c4fe708ae63627764c7c519f97868962a +2423898 00000000008f737ed1b017c6dcdf4334ef9888f30d450b988db0c8ef4ea04ae3 +2424298 0000000001a959e67fbbf8256186f208bd2eb6d61926a3a8640ea582f36f539a +2424698 00000000003313c0a59b72b91a1442af12768d012e6f02905e2145379c3d3a7e +2425098 000000000164379001b5618e2ff078a001d5a6ce9eef596646119faecafd7a51 +2425498 0000000000193b2b8e06072273f9e077ff6229e76e8f4d52d27fc5eedc7a7cc8 +2425898 0000000000e5082819e76fd696530b16fd5d0a958987b21021f986cd83a5936e +2426298 000000000176ce3130087b699ec3d3dcbe58c40c585e7b9393835bc1eb61b271 +2426406 000000000123367bd7b6a399da1f66096902b0b2beafe9d9f43af6c03bd35c8d +2426806 00000000005eace8d5016f89a9ce2b301fa3ab39d126c66cf4d3ee850df558ad +2427206 0000000001844e1f6c64cba1594e4fe2885963a45a0c160f403c06af6bfe9425 +2427606 0000000000eb53fa9f19b10b9026ba88b34eefff3ad65b3ffd505bbff1faaf8c +2428006 0000000000f2ce391c58ab733d7ed207c1fa1ea341e022d7bf48284ecec8836a +2428406 0000000000297d10cbaf490691b12d813e49ac43d263dbd512cc014e68deed15 +2428806 00000000017e35714ff28848ade3bcd8dd3fa51571702792266989aad30a9b1d +2429206 000000000257ba2bf67556982fb05720840931fe03450fb2c8b2bc0ede71a674 +2429606 00000000013ec91145c68ee667c327d0ef7b8ed5dddb05b6ea9a790ebda624bd +2430006 000000000027dfb5cbaad9e9fc32fb3cb2143c6439606d0b0cb7923eddc3e9ab +2430406 00000000010864cee8ae0dc86e9e2acd2c07c0d661bc2f3c103f71ebae19e857 +2430806 0000000000b5357e2fe108f26d435492a8c9cf35dba3031d551e8d2db8782d7f +2431206 000000000075f18cec35d79ea3b127adadb748bff5835634bad37d6795cda70f +2431606 00000000002a76542370efe7418b8b865998620eb4d5ea320eb2927472012971 +2432006 0000000000178a53dc0c7bd3ca917922f1a82fb3da79af37c8d6684f29a9f9bf +2432406 0000000000050708181d568a09a5ca026d168741179e3aef5163c8d79d2b346c +2432806 0000000000cff0c075bab37d65511f9b571d765c66fe3c1d439620dd14a1f4e8 +2433206 0000000000cf934f64006f3da9c6753281f0a5fb8358fa6c7412848bea1a8689 +2433606 0000000000ab87ffb227c383696bf737a9ec555b2b02d2dba4ad0fd66c39b53f +2434006 0000000000dfcb7cddb9ce836c75913fd99ac3abd0255ed547a288302e90e8c9 +2434406 0000000000a4268bc0d7263b55a4c27a926849587f454d53d87cb886f974f400 +2434806 000000000061d0c26358d933d119d30accf989586fb23c266d8bda3384e9412c +2435206 0000000001cd5f28e6a770c3ad763efb6284f24c65f0a71d6d3cf23dd5a6d1e5 +2435606 00000000015240cf91bd4d4debe44a74f5beeccb589e3b14087b8cd49c355558 +2436006 0000000000ec73e74e585a6afc3fb323d5b7858d8bda2372f0265de095f00c57 +2436406 00000000000da656180ba97828f21dd94cbc0fae851f5a711bd9c10dd056accf +2436806 00000000004546b21ba296a0a509ca241a3634bf89112f3a35761e5964171a4a +2437206 0000000000def12da2cba31d09823e428cfe758b483a3bb499fbbd1f5e5b0b18 +2437606 00000000003445d0c3cee942f7cdc83d8bee851443e870110f4a842d39ec267e +2438006 000000000138854bdb230882a1875a6da0e28c2a78fb684b36041fa31672d0eb +2438406 00000000019e5a71a62fd1a7456f828553e0ead8e9da0bf20f0e6dba79096af3 +2438806 000000000058b2c7d0ad9c93d77c66ac2d5158733690f318842abc65e1743955 +2439206 0000000000a3d31c72a300c9f59168af8e5e40bea1d173a5cd932a1e544c25ee +2439606 0000000000f6d464b59a17c16fe882cb875d9c5a9c7f10e1a4a0ccee7b064153 +2440006 000000000090236b76ceefd8230b583f2f7c140d440e155d6cfcb064036a5b92 +2440406 00000000017ac32b6af1dc0308290a8d763631248be6d0aff1d314cba66de4a3 +2440806 00000000002552280add89aab9af8261d8e383f446b2f4574a0fe9b5131d5bb4 +2441206 00000000007958a356127cb7c62683dac0ff778ca6bcfd3525dfc22e61f6b917 +2441606 00000000001814b42124032ed605dd6001aa18e649d2481d4d63bcc1122c8f86 +2442006 00000000012ade1e4f56c0eb9168a9214d363ea4aa1cbca9373b85a07328722a +2442406 0000000001a47c6a5bc1f0860b8d5645360ee660e1b849b41546d39ea38d55e3 +2442806 00000000013083927151a545a05c35b571df2e2bdca84a312ef44f7f28e96451 +2443206 000000000184e98d96c728a14254d3ee29562746ed88c866a723ce4bb28428af +2443606 0000000000a0be875c27da9b28508e12a5c9d2385639098c0c829944d56a7241 +2444006 00000000011745d5cdf9f0cca985323d25d64183f792abb62a0355b8685f5c09 +2444406 000000000081883d2aef16a5ddd2db6fd6b46751820bf7a3a1ef3426827f333b +2444806 0000000001612d85d4b119d47636521669f0b8c9def3789e4182c337290a0958 +2445206 0000000000f050b8df00a4d16e0fd73703cf5efeffa443fbefcc1b3e485949f3 +2445606 0000000001a768955eb857e8122d381014a4f9a9222ef86f40c5454b75aa1ff4 +2446006 0000000000b5cba2a1fffd325be1b08edb2212f24c8a993b30dd5e44c5c5df3d +2446406 0000000000d799591573be6c88b82c2f9d8c01ba302d9491b3c3bc6dadf6b989 +2446806 0000000001b79fe078526ecd68c0b52372624d124eef343b799a5af5bef06ac6 +2447206 0000000001a02215512cb2d4cbb150d26041b0accc968ba97cad2aec978c3dfb +2447606 000000000132ec5e6bcf6a6793f620149f9948490931294bf5df6175571e244a +2448006 00000000003c5362cca582ecd67f9e6846c947dff1bf8a36ccde74dc2597ecf2 +2448406 00000000005cfa25b9ef53533299c13b38e0a401cf93a0892feab6f4ae0f7381 +2448806 0000000000d7315679aa86ab3b95e8ad58c80ad5f4f2c4c964b3c22f2cdec3e8 +2449206 0000000000f604443aab1f1bc930c548036bb7605a34bed17c4ea8586c0c1028 +2449606 0000000000dfb8c5a98b4d7f80448ef73ab00fee9a968f39aabeb21fc4f3c66f +2450006 000000000044d8fbeb946cf56ebde9ee2d6b07d4929c5701d79f9a567cf4ab28 +2450406 0000000000ad71116268e862524a3c487ba7cac5dedcd1a701840b0f37a7b41e +2450806 00000000001af6d8231b95468f98eee59f3f91ca0ca20e58dd924bb6965f7a41 +2451206 00000000014dca515eb569e0bbc5d85f065647eb7bce5d7f21c0aba5eed509fd +2451606 0000000000ec47bea7b114bc980897886580d6f297f6a15b41ade0dea47beb42 +2452006 0000000000ba2a7f1aaced150a9a6839ed251a24db125e1c00d5186ebb7164a1 +2452406 00000000002407086ceef2b2aa39401d56032f66833b68420e108903b8841354 +2452806 0000000001d4dd97eb00b9c9a399fb3ea69b2d86250c5466ebdb798de09c11a8 +2453206 000000000131de02255f51f91063bf6abadc3074194d0ae5a3825cc36d5d8c16 +2453606 00000000009a6fa623b162d69e57c809c1028c91b6d86da97240c53131553252 +2454006 000000000025ad720646d4302540f7789bf51b369fefaa4daff27c7d7477bbb5 +2454406 0000000000424178e973135d439fd626e6ff7e14150419fec83406d15a39bb6e +2454806 0000000000c46c5c9de22e1001e72ab6ff9203adfa9c72c92be9729e30864615 +2455206 000000000028d3c72040bbe6fe02a8cbff6057589a08fc995a1d6c40876027e7 +2455606 00000000014703c61054f834378347032a589f4fc811848b2dd7c94de2c4576c +2456006 000000000020172d8e9a1893953c03fdf298e19e80c33c429870d651a12a9261 +2456406 00000000000c924aae23d79e4403c258e41d34386fcd6a303aa283a271beea76 +2456806 0000000000fb34194f3226bb7ea01f80adf73061be715ca4533c0f40417ae423 +2457206 0000000000eed0793877f53c1e7688df3029e6894957e94fd34a78597ef4ebec +2457606 0000000001626127a1258ab11e06b4880b5dd8d0c6410ab80f656e3152a23620 +2458006 0000000000f7c68f10bebde82d77b86d28db6488524e6388ffda72ce29628b71 +2458406 00000000008804ce8332235bb3055714be66127dce0d1209f232e17ff9d795c4 +2458806 0000000000a50d1c7cfda161b4378303c37bacaa9ad3aa2c1af7e70540ec0d1d +2459206 00000000005d07da5cb672421efd8d5e12ae6dcad86349b6705fce178b33c365 +2459606 000000000181e14ea1fa1b9c9dae09eb32b02697e92dafddf345460266d26a00 +2460006 0000000001119b9c66f8c4572f37ecf63ce75cf7d9dcf2127bf5492d3b62db29 +2460406 00000000001d30b923e80eb9009159da7fec1587fbd5d2327c7a1d28b35d2efb +2460806 0000000000b2b59bb14a8ecfc87bdaf05bfed790f58118dff282971daa0d4d84 +2461206 00000000009168eb8334048bb6ddbe02f78c9cfaebfb3c748d8babccc880aa11 +2461606 0000000000b90fae17740699b3676adc60c80736f5deb44c86ac3d68375440fe +2462006 000000000139632ede19c974b40bf9e8488e296a974d713525f00b530fa60dd1 +2462406 0000000001289e6b24028d4fa7374a354d78025bc9285d728c81f4340c7145b7 +2462806 0000000000743a7070fb47ac66698aa239511c4a6dc6ecb4aef8718e7995a1af +2463206 000000000144d0d6778bf3c753fcce6093a164d9a05a2cfa21e84dc125c5a7ef +2463606 00000000002a9d5bf095e988eaa8ee63790cd488c4a099c7803be776aa209384 +2464006 0000000000e9e640f2e1bd74f4ddfdfd0ff459918e586a5d188700631ea94b9f +2464406 00000000016725a797a746c69cadbab7241837cf011d958154c82b21eed2080c +2464806 00000000001eedd5d41a4a564e97be3439fece3a56a605bed5e0a3b3c7200852 +2465206 0000000001994294fa900d7af1b9522cfe3f2efb98019646f7478e7d5acdd82b +2465606 000000000145875d651a642dce311526bc3ff5930cc7c7855883a62b17583751 +2466006 000000000114929697bf82b46255463975808bff395fbe7f79bc87e489643ee6 +2466406 0000000000429761e2a4026ffe8a5a9384e328354cbcb75fb56831141579bd94 +2466806 00000000006531daea055577a25502c2ba4da2c6fde848c627a60f79541c0ebd +2467206 0000000000cdc0064706cb20cf17d239dd1b6a910c2cdea067d3e67658c3a972 diff --git a/zebra-consensus/src/checkpoint/test-checkpoints.txt b/zebra-consensus/src/checkpoint/test-checkpoints.txt index bfa58c760..8381f76f5 100644 --- a/zebra-consensus/src/checkpoint/test-checkpoints.txt +++ b/zebra-consensus/src/checkpoint/test-checkpoints.txt @@ -6818,3 +6818,166 @@ 2726800 003f3ef8cd3ac611f543a0724ba4c8888e144551dd89e47fa6385873bd49b357 2727200 003ba226a19d5608b2cd726e31d658ffb802de92f1ec1f4117f43899602b5a17 2727600 001ff47bc28b72302f17a3b33caca54528004fabe31cbc94df70e9764a3ad952 +2728000 001b46a80b7ab1f4ac8f87beef6da07b2dfff4500d7153ec900334387e808f4c +2728400 0038bfee25b99725c26c354970831c53adf7ebfb76976b6b5b62a168842b06a9 +2728800 000a8d332aa4f85e790a326f88fb98943c7b9f2683175d74d5ffd642140a9525 +2729200 00558164c2e4297606fafd8803fe147b88cba14380cd0444fc7fd5f2f1ab3a55 +2729600 003e8931b42158e0124a7951e94b658714130785d83fab2d53394d53c8b1676d +2730000 001f4a32582e881b54a1f7464b97ba67b34ec2ffef738a8af666fc4fefef1bab +2730400 002b2194edea7a6bc681cdf452d8fea947f1ec1ba8cc3b42f9cbb3761838680f +2730800 0046e27427e5935272cf9ee2e11cd048fb81d057abace3a1ddace7d7b10db2d1 +2731200 002607100755bbf0959d5485e7d9b38840f45057510a992640d8ee5376ce7cfa +2731600 000a86e7206c0024dcf85f87f2008389a6d73a3a29ea051c48ef484366204201 +2732000 003d6668b7f55d5f9c661d4403964261242e2bf90177e8bfd3665babee563ec7 +2732400 0039aa2b03bebec032523a0fe1dfb5fed2e74cd0150184a65a5bba27e4b2135e +2732800 00149d91b3e43ab7a7be963e700636d89143d8a8b23b4024266a816cd0596969 +2733200 003373f89a8a80970724b89778d0794d4699b6ad25e1d6aafb5894884e46d52a +2733600 0026f9f1a463b3e64f399c68f63f4901f31c8696f4e362e7373ebfea2c033c6b +2734000 0042cfbb513c3dd6a4a10b4931a5098b5ed2983725a43706be22a0da7f0c718f +2734400 001a3949e039e1492d09bc553f687809647753d16388069938e43a0d62f653c6 +2734800 0037834d2acf86ad1073c1322a2d76074b849cc5a68a09435b395d56365c0027 +2735200 002c32c6390b7ed382f672adfc83e63b9a1c49e5a9fc17db86c19c53f0e41c09 +2735600 0047aa19210fde08185177d49cdf0f2bd8c942850612b487544158e5456a64c5 +2736000 00071182b76afa5196b5a0bbd903734cfd8a3fc6ca956e1a1f9a38350b0826f0 +2736400 003a901b465c6f15a7e55c0bc55b691a28e8ee98fd71522037000339555e0242 +2736800 001f4bb9adcf6a2d69861506304651a1f3c4e8dc958e8f11013c87f055eae120 +2737200 003b950d2cfe2ad2715e621834e7c7f60dbdc8af69057a73f7b507505c8ef637 +2737600 000e44bffc67a5a393728fb218d21cd28345f4fc011cebdad5b5d588975a40d0 +2738000 0018463f50dabebd7fa87ebaf61a824fb089163852a50d8aa3e4dbed895af600 +2738400 0025821e9d5e0ed193d44073fa51618c49f335ecff9505a592fb3332378790e6 +2738800 002459e7ac3f072a3ed5469409189694d14b567b82cdb85e6ad76a1860d6eda7 +2739200 0014b66bffae34258943acbf2e3a074ea606f8248f892c1bdfb7be3aab2046ed +2739600 0034603897c22fb3a2a41537af26d5949322d45fbfaac43569c20c7af0308860 +2740000 000b5ac1464ea55e427c0abc0924980355bb6cee42ac771b2c6d8d1f2ff46fe6 +2740400 0025b135d0965654f3c1810d3eac6e40c9fea4af1b5268cc8f8e9bef59777360 +2740800 00161967672918993f033648a6a2aad5cb63fbbc746eb94e9807f93c61a027fb +2741200 00220c4c9514df99597a2df5ef00cdaf3a53ce2c211117e183aa3126b47a7df3 +2741600 001baaf39b8e07049ceaef793c180b84d7c0dacf68d6eb579df9e388015002aa +2742000 00023cbffb5c7b61c0245fdad410a38094f73faf8eea2ae101fd4d4cf4e536ed +2742400 005e5915b6cfe48ec20de0ade68fc8886c30c172926d799e3593d01551f9efeb +2742800 002235e235b19a36c8e84711721234311606a699e8154a72f82e3ea29564b1e4 +2743200 002e3158e91bfef2cf5ab486e7c28009e08f92c490d64bfd7e42f2b1f6fcf4d1 +2743600 003c77886bf67edc3f653f1b6b039eb4af8439366e846d864142c6bc465cd0e7 +2744000 001c23231bd59c1a38399f98a1385d0bda4bd81ef68acadbf655a472f99133e7 +2744400 000933be2dc5c299b0dcf4a659f4f2ac4abf44da6c8988816ac442ce79d74cbf +2744800 0026d645d48cc816799f2e09a871d77df8845b197e8abeeff833fd1d4ec4bc59 +2745200 000e8791186a8837d38f6db3de6e88a9cc9bb0131514ffc5649f2923caeee9ec +2745600 002888e0a7d1fdd99e5ee5e330f724c002ef04d77b420e0e37c6e3797fee224d +2746000 005e28e762ce9aa53a6c185914bb08b03c6fd6b229979d1e5a0d6068863410c0 +2746400 0047a5a1f107c96461ae8371e05a8b561588dfae8eb073da4bb147959c8a5770 +2746800 0072679856c07eebdf2b7b294cae85513ff7b53e4f92553700f086c7373c7bc3 +2747200 001a7ebd016e5bdc430c4528cab9ddded57c1ac6094abc0ccf6c6637480a8d11 +2747600 0010769521bb19d13bf6feb44c7d83448c399c7971409bebbac0285d15bb939c +2748000 001c22beb1e591232a37246c95b67cc1d9181c0381e06c963f2fdbfad7f669c0 +2748400 00237c029f870963c876a8f69b27b5d0ae6c910edd87e246ccbbc6c5ed6b55bd +2748800 003130019f1e2585366dcfdbb627429448633ad1c8f567cca723fdc9a423e550 +2749200 0006d0a5d8e37222eb5335ee0a0f35172904dae8ea9e9495abada7636cf9c453 +2749600 0008175daae8f5e1b59be6cbceca78e50608541f3a81fb0619b15c024eaddfcd +2750000 0032ee34dff008317a8b7078198e3e62a30d41b041bc821c07f2481d93fbcb59 +2750400 00042c6d534f987a84309063bef3ec6ad0e065dfe0f6e90866c82263a1b4a293 +2750800 0023c6745ff308fea1d7683f6d6447fc9cb63f0d4f310745b47adef115634d7a +2751200 0065206f70020fe32270308dda9e6945585ddb7028d2d326f352309d3cf6e37e +2751600 00124cb5312c29e6683f6788d48ef968d1b3cd2fc279706c56f7a39d682ad300 +2752000 00011b56eb432b205847b0fe97cc9d36ed97b90fa5acb9ad3e5a91439ea756de +2752400 001060b420686a8ab5ee083c7277f44abb6456843009e9102971eee0941d6a6b +2752800 000e9c59040626307dde9b2337e8199d72d297924d26607e73ba821ccea3a87e +2753200 0043cceddcf9010f553f5ca5019a2ad01e9ce6d2909eb12576cd9f339d073256 +2753600 001692dabbe0bc0912c473c35f98f47dcbafe4425ff8696a08bacef61db6c7d7 +2754000 00544dc51357a4550a4bdb253b829ad483cd42674f4102c19ace8bfad4b97756 +2754400 001060a37e6446f0e61939bf4158e81e163f8a2792751b0658a8d882026ca3ea +2754800 001d66a0661010b163ce424e870bf7f49c3e1fbd54b08a9380f590fb6c20fdfe +2755200 000d357dc58c57fc0ab4521915d809ea9bc0959ca4b3bbf530191341d938dbe8 +2755600 002970721b97cafa5f1c6e7242c144c31be7dcc662935cfc99603ed484269f28 +2756000 00919841bcc46f9409d93295ce8ea3e2f694f32afca33073ebae350368faec81 +2756400 001785d0f87995442b44044db726b92dc7359bb9a12b5ea277fa23a69c85be0c +2756800 000ccb38f6d2d1280bc77a0067104ed9ded423c6a9ba3ac6b249b4fa499307d8 +2757200 00148d2cf210fb75976ffff61532791578fbcfaba65c4097c13c38b23b227ddf +2757600 001ba9b97575462e3bcd94d5d54539a4b7db533d433cec53a54b7b024d966b8f +2758000 001167c9b120cf865676892ff5e2ac34ad71e68b442b2a0a64a1f1b702cf1013 +2758400 000c2abbc8d6d3d956e5cff3af422e65c4775259d894c95ac6878c9214267adb +2758800 004cf7350052198bbb492d4f209b7c2f4f81fba883919ceba55ec05c612a1a10 +2759200 00233cf0c255a901be660bb1e12728696d9ac6993be542b0d7654f28a6df7765 +2759600 002395ab3759acdd453bb4208518fe1b336348ad46bef826033c894acce8c6e3 +2760000 001e7783656e6d9801bbd49483da9798b321626ebdf606993a5c68b40f2e636f +2760400 0025e0e383fc89d148b10e088889cbc550ceb6ab7f58fb78340be096ce4b11b9 +2760800 00af0b72822c54ade5ce8fb34a16cef9a4e36f9e2a6869a1b96a64ed4753e5d8 +2761200 0029da38b04d7b032a77b6dd63b4e31f3f3e2c3058ee234fb14618f7ff6ba48d +2761600 002662941799bace08e615b8f56ebc51f70fdf0d995be2b2bc1c6dac5c9933e9 +2762000 00371877e48632aa03258230bf1aea843ab87f246a158b682b51a6ffeb976fad +2762400 0043408a0b98c874dc821569367cb1c0d84e3512e916c940d49e85b7d3891bc1 +2762800 005df256b86a0f984c4630d875d21f98f08584fa3de860a62d19f59be103a2ff +2763200 005211d034b867c267917f575b1d0816cb40872ab52c180ef9d35150c2de19c9 +2763600 0003bb6beb79d89dffd9361d321e30a3e15d621fcf26057f5dd61df58a8748b8 +2764000 001ea2dec933efc5e96623ae56704588ba4f999e77e34670c1bd905506d1fddb +2764400 0032e1f3ea89426b0a136cc5bf36d53bdba79a665d80bcff58bb5071d0eeec02 +2764800 0030a62350cf99ce7b72becfbb7819c94c2b843e465f18e21277100ed17ad3b9 +2765200 003345714fa6abcb13b28a065ee859c3044fa9e308d2e17a5a11d52873292607 +2765600 0017fe72837cfcfb5ecc543a94f52ac74e3743690292468acf5e848baf34cc09 +2766000 004789d79e5952a33ff4760a9ab45109958edf9b6ee5117fd746f293957933ae +2766400 0016daf4df4c595a9c162394c2e523b8c7a9eb765107b9b2512e5e45732fcfe9 +2766800 003a0cb9f4f336d49a80aea928d02e79844829af10a939a54e7eb0721270563a +2767200 003e4de107a3c849b2c0acd7429189fb36192d5ccfd60a39439ecdcad98f7999 +2767600 00109abb77207adf66bf341e430f9569ba6a81ac827f0fc946c41da5498a853d +2768000 00243f17e95a8041c4677810a4ed6dbdec3f89b1fca5ab0069422714d782394e +2768400 000474b4ae0b639d6e036958c1640863e3268207cc824769e43656cb0a074f5e +2768800 005e7abb54ca7c9f077545c9a00ab8fdee1645db669441813ba61eb96902c8df +2769200 002c7507abf2700bfbd8fb5aadf690e4e1f37bfa2cbad9e5286622af1d49aa71 +2769600 000cf689fa85257bf4e856ad977d716296068d7c17f2b62f079b45ab19bb02d1 +2770000 00065215d6079640ddf94ac7414130f35efabc9d24c9fa8feefa86030f5e5dcf +2770400 0026d6313550930c7798864eccc3f0186d0f220b32c6f94781917ca45b751bf4 +2770800 002c58eedaaa3fdc9d9d2dccbd51c9d28ba2b9863f6590dcbd3771a17db2df8f +2771200 0089494aade7d8eb8991c67f71f91f852c631c22e320668a9dfbf5f020a83a2a +2771600 0050c38ac49440d54f205c092df67786505b35ec480c4feb565e324454d369c1 +2772000 003d3e1801172885f0f8d521285da0920bf50bc6ba48f4bb7363c19ed6b92fb5 +2772400 00692ed252c7040035f1e2ae286eb00ea99a12d3ed4d4b4789064e9a342f0d51 +2772800 00247b923fb37bc40c0e16402f8980c998ee6a8ab69bb5f84c106751900eafc5 +2773200 00276af537e7c710c491c5d8e438dc6b20011ff45f6e3d059903e6132377ee43 +2773600 004f3c81eb23ceb4e806d0685e7528c23481c134185d75f9fd06315f424ddc4c +2774000 003c21992873ae7d8ddb3f82596c3a9465f55d62168cbc97f73c8198c71764d8 +2774400 002e8ad206d2a28181f3e5994eac43c7290564e3e0b47a75c0c728e83932f16c +2774800 003bd9a6c1373390f9198ff3e28e9ecc9e73957f864c13635539253d721dd2cf +2775200 00455c81cb1e55607d79d8781d9f7e7e0f70199bf320262c8122d007578dced0 +2775600 00182954bfe6da522c4b68763454f176181d74686cd752be83797cc3cef255c0 +2776000 0015aac5c94746c408669130a2eb6d4463f189960577d1ae70541a79ea4c8a1a +2776400 002d59eb4b740f3638a8869a574f7dd668e8820b476a02ebba85429adc80bb4f +2776800 00066cb0036f8513b23480407a78a898127f4cee67d3d0fa71afd60c45bf6b42 +2777200 0026c2e20a5c2589e5dde4360545410cea76bfeb8c27ef8116484c0a588c18e4 +2777600 002e2526b2bfe2e86ac49be6ccf34ced320cee53b0c493313c3b5ef8d479b740 +2778000 0018e0d2b9edcc5dbd931476f104c9ad02c0d86eac33f63281e438f1be2543e9 +2778400 002899655041fd7f0d06e38929b0fc56a544a61e4c85b6ad7f620229448e1579 +2778800 00248fc2a7ab2d83051f29422c818cfa6a73f038a53f3e132515da5ba33af9c9 +2779200 00310a74e66de833eba7eb6c5bbb4ecf994305776724456d1f028e602020260d +2779600 000c3a7d599c417ccf9d2db9643486afcc2568e6f4358d2f202b244ff947b0ed +2780000 0018911742e8545373e08277fc39ef43512a59798aa9fa56d772d9959db61ce3 +2780400 000d8e3cbe9868ef07354aa5fee6a609743f0bf79046211b313c60f1184993a1 +2780800 002ec50ed16e590365711091a526155c86e64b73e8bc22850cf920454fda9ae8 +2781200 00269b875de5ef7946145a27a257979ca236ea34f07a4bcb246190e897c9f5ae +2781600 002744e09c8c404667bc7e30b0957ae1972bb401557d25248d3aacc2095672a2 +2782000 001fb8589142dc1c09a71c93c6b2253522c48b0777d226fedac9bece5b2f5047 +2782400 001f775bf5b10ba0d578ac10c5da5fabcd81e624bd5e2befd25d37605a66e4fc +2782800 000b08da4a21b433b7089e6dc7392471fb485f32299ae42bd0e805a5ba1f0eb0 +2783200 0002a57bff3fe8c6b453ef52871bbe8b7eccfda7fec797d41de30312d327eff9 +2783600 000807674997686cca4baa0e1f8fbd51e0b3e8374d68f0b9f1f8cf0366ef0650 +2784000 000469a430c8bb1242cc0a403c01b51db446e57cd991af38d3cbb1c7120afa1a +2784400 001dea4d46f46305ec4625b7f445ff5086c2875278458d945cd1c0e12b031de2 +2784800 0010bd18282ecd2689e1c8cc183f5e79bc2ada4160eb2e07383faf2fda06a2ba +2785200 003a642b7443d93fef797dd6b16e17cc64456f5a732abbb87ff2ad96cff8a6d3 +2785600 0036213f45a41a5e02effade1579069152e18185769f19cc66bdba26e234197c +2786000 0026c6febd7908769719ee22a5787f33fb182a615d117b3a8a09ef76067a976a +2786400 002b0c91006f7c8c6bb550fdbc8338ed836d0ffaff661e5ecfb2fb69423196da +2786800 00132fc711523f9dc23e291bec131c5d8cd947a1df04fd2b4006c71d0437558e +2787200 001d83e45b31780f00d94fed29fc0caee43a1d39a59a7f4cc9952803f56daba4 +2787600 00d6220883941505b95604cf85541423ca3c86205adb8264c0e523e195fd3f37 +2788000 0002a5318231f41e258f61ee93c224d048b820577ce34de7cc421c52f1c06eed +2788400 0033b1fe9d2b860f071f67f184aaf17a6c39227b9ea98c47803a6d3a11370b42 +2788800 000b5351712d4f937b768cb7202573e2df5da505353a23d86434b42c9922495a +2789200 00c65ff2718eb57330b1fe34a31606eec0c5e0caf928af8f0f7e30337f99adf5 +2789600 000678548d6ca746d9f647f8a1bcd31bfdac24aa1efe8b6f83fcfa476bba161d +2790000 0026e52313025206955edf9bc9e68f90385c8ac8232ca27c9069605f003fb50a +2790400 0023122740faa5567495b175b7dedae4f268920e8ee747b61b4d712a5fd65389 +2790800 0011c31eb7f86a3aac19967168115654d44391af29ccca83c34bb0816401a71d +2791200 00316c98e2e95be4f2d7850b5334d22191cfb44196e8a80620df97000432f0c0 +2791600 0009167495f5086c49f88a1e3f93676f65c78f0d9fca7d5fb9ff376860e8c822 +2792000 0094fbd3561594cbe2ca62b6323dad5dc050adb340d0ca7057d29f90b0989230 +2792400 0036a56516cca83c1e5aa6905d777f4bfe0ffbb93c8455add0c74aee9219c091 +2792800 0009434b97090363a040f1dd5fbed43cd99ac0f32685c05c20e35bd493e409a5 \ No newline at end of file diff --git a/zebra-consensus/src/checkpoint/tests.rs b/zebra-consensus/src/checkpoint/tests.rs index b2493540f..e13629c49 100644 --- a/zebra-consensus/src/checkpoint/tests.rs +++ b/zebra-consensus/src/checkpoint/tests.rs @@ -1,14 +1,10 @@ //! Tests for checkpoint-based block verification -use std::{cmp::min, mem::drop, time::Duration}; +use std::{cmp::min, time::Duration}; use color_eyre::eyre::{eyre, Report}; -use futures::{ - future::TryFutureExt, - stream::{FuturesUnordered, StreamExt}, -}; +use futures::stream::{FuturesUnordered, StreamExt}; use tokio::time::timeout; -use tower::{Service, ServiceExt}; use tracing_futures::Instrument; use zebra_chain::{parameters::Network::*, serialization::ZcashDeserialize}; @@ -205,8 +201,9 @@ async fn multi_item_checkpoint_list() -> Result<(), Report> { #[tokio::test(flavor = "multi_thread")] async fn continuous_blockchain_no_restart() -> Result<(), Report> { - continuous_blockchain(None, Mainnet).await?; - continuous_blockchain(None, Testnet).await?; + for network in Network::iter() { + continuous_blockchain(None, network).await?; + } Ok(()) } @@ -216,7 +213,11 @@ async fn continuous_blockchain_restart() -> Result<(), Report> { continuous_blockchain(Some(block::Height(height.try_into().unwrap())), Mainnet).await?; } for height in 0..zebra_test::vectors::CONTINUOUS_TESTNET_BLOCKS.len() { - continuous_blockchain(Some(block::Height(height.try_into().unwrap())), Testnet).await?; + continuous_blockchain( + Some(block::Height(height.try_into().unwrap())), + Network::new_default_testnet(), + ) + .await?; } Ok(()) } diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index 8dfd42bd9..e7cf8f91b 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -7,7 +7,7 @@ use lazy_static::lazy_static; use zebra_chain::{ amount::COIN, block::{Height, HeightDiff}, - parameters::{Network, NetworkUpgrade}, + parameters::{Network, NetworkKind, NetworkUpgrade}, }; /// An initial period from Genesis to this Height where the block subsidy is gradually incremented. [What is slow-start mining][slow-mining] @@ -104,15 +104,18 @@ lazy_static! { /// as described in [protocol specification §7.10.1][7.10.1]. /// /// [7.10.1]: https://zips.z.cash/protocol/protocol.pdf#zip214fundingstreams - pub static ref FUNDING_STREAM_HEIGHT_RANGES: HashMap> = { + // TODO: Move the value here to a field on `testnet::Parameters` (#8367) + pub static ref FUNDING_STREAM_HEIGHT_RANGES: HashMap> = { let mut hash_map = HashMap::new(); - hash_map.insert(Network::Mainnet, Height(1_046_400)..Height(2_726_400)); - hash_map.insert(Network::Testnet, Height(1_028_500)..Height(2_796_000)); + hash_map.insert(NetworkKind::Mainnet, Height(1_046_400)..Height(2_726_400)); + hash_map.insert(NetworkKind::Testnet, Height(1_028_500)..Height(2_796_000)); hash_map }; /// Convenient storage for all addresses, for all receivers and networks - pub static ref FUNDING_STREAM_ADDRESSES: HashMap>> = { + // TODO: Move the value here to a field on `testnet::Parameters` (#8367) + // There are no funding stream addresses on Regtest in zcashd, zebrad should do the same for compatibility. + pub static ref FUNDING_STREAM_ADDRESSES: HashMap>> = { let mut addresses_by_network = HashMap::with_capacity(2); // Mainnet addresses @@ -120,14 +123,14 @@ lazy_static! { mainnet_addresses.insert(FundingStreamReceiver::Ecc, FUNDING_STREAM_ECC_ADDRESSES_MAINNET.iter().map(|a| a.to_string()).collect()); mainnet_addresses.insert(FundingStreamReceiver::ZcashFoundation, FUNDING_STREAM_ZF_ADDRESSES_MAINNET.iter().map(|a| a.to_string()).collect()); mainnet_addresses.insert(FundingStreamReceiver::MajorGrants, FUNDING_STREAM_MG_ADDRESSES_MAINNET.iter().map(|a| a.to_string()).collect()); - addresses_by_network.insert(Network::Mainnet, mainnet_addresses); + addresses_by_network.insert(NetworkKind::Mainnet, mainnet_addresses); // Testnet addresses let mut testnet_addresses = HashMap::with_capacity(3); testnet_addresses.insert(FundingStreamReceiver::Ecc, FUNDING_STREAM_ECC_ADDRESSES_TESTNET.iter().map(|a| a.to_string()).collect()); testnet_addresses.insert(FundingStreamReceiver::ZcashFoundation, FUNDING_STREAM_ZF_ADDRESSES_TESTNET.iter().map(|a| a.to_string()).collect()); testnet_addresses.insert(FundingStreamReceiver::MajorGrants, FUNDING_STREAM_MG_ADDRESSES_TESTNET.iter().map(|a| a.to_string()).collect()); - addresses_by_network.insert(Network::Testnet, testnet_addresses); + addresses_by_network.insert(NetworkKind::Testnet, testnet_addresses); addresses_by_network }; @@ -215,9 +218,11 @@ impl ParameterSubsidy for Network { fn num_funding_streams(&self) -> usize { match self { Network::Mainnet => FUNDING_STREAMS_NUM_ADDRESSES_MAINNET, - Network::Testnet => FUNDING_STREAMS_NUM_ADDRESSES_TESTNET, + // TODO: Check what zcashd does here, consider adding a field to `NetworkParamters` to make this configurable. + Network::Testnet(_params) => FUNDING_STREAMS_NUM_ADDRESSES_TESTNET, } } + fn height_for_first_halving(&self) -> Height { // First halving on Mainnet is at Canopy // while in Testnet is at block constant height of `1_116_000` @@ -226,7 +231,8 @@ impl ParameterSubsidy for Network { Network::Mainnet => NetworkUpgrade::Canopy .activation_height(self) .expect("canopy activation height should be available"), - Network::Testnet => FIRST_HALVING_TESTNET, + // TODO: Check what zcashd does here, consider adding a field to `testnet::Parameters` to make this configurable. + Network::Testnet(_params) => FIRST_HALVING_TESTNET, } } } diff --git a/zebra-consensus/src/primitives/ed25519.rs b/zebra-consensus/src/primitives/ed25519.rs index d51113276..10926db67 100644 --- a/zebra-consensus/src/primitives/ed25519.rs +++ b/zebra-consensus/src/primitives/ed25519.rs @@ -15,7 +15,7 @@ use tokio::sync::watch; use tower::{util::ServiceFn, Service}; use tower_batch_control::{Batch, BatchControl}; use tower_fallback::Fallback; -use zebra_chain::primitives::ed25519::{batch, *}; +use zebra_chain::primitives::ed25519::*; use crate::BoxError; diff --git a/zebra-consensus/src/primitives/ed25519/tests.rs b/zebra-consensus/src/primitives/ed25519/tests.rs index cc75e71fa..58d7e8286 100644 --- a/zebra-consensus/src/primitives/ed25519/tests.rs +++ b/zebra-consensus/src/primitives/ed25519/tests.rs @@ -5,7 +5,6 @@ use std::time::Duration; use color_eyre::eyre::{eyre, Report, Result}; use futures::stream::{FuturesOrdered, StreamExt}; use tower::ServiceExt; -use tower_batch_control::Batch; use crate::primitives::ed25519::*; diff --git a/zebra-consensus/src/primitives/groth16/vectors.rs b/zebra-consensus/src/primitives/groth16/vectors.rs index e46e5b268..57c61c1ad 100644 --- a/zebra-consensus/src/primitives/groth16/vectors.rs +++ b/zebra-consensus/src/primitives/groth16/vectors.rs @@ -1,5 +1,3 @@ -use std::convert::TryFrom; - use crate::groth16::h_sig; #[test] diff --git a/zebra-consensus/src/primitives/redjubjub.rs b/zebra-consensus/src/primitives/redjubjub.rs index 31641a9f7..3958647b5 100644 --- a/zebra-consensus/src/primitives/redjubjub.rs +++ b/zebra-consensus/src/primitives/redjubjub.rs @@ -16,7 +16,7 @@ use tower::{util::ServiceFn, Service}; use tower_batch_control::{Batch, BatchControl}; use tower_fallback::Fallback; -use zebra_chain::primitives::redjubjub::{batch, *}; +use zebra_chain::primitives::redjubjub::*; use crate::BoxError; diff --git a/zebra-consensus/src/primitives/redjubjub/tests.rs b/zebra-consensus/src/primitives/redjubjub/tests.rs index eb32a1db8..97d290431 100644 --- a/zebra-consensus/src/primitives/redjubjub/tests.rs +++ b/zebra-consensus/src/primitives/redjubjub/tests.rs @@ -7,7 +7,6 @@ use std::time::Duration; use color_eyre::eyre::{eyre, Result}; use futures::stream::{FuturesUnordered, StreamExt}; use tower::ServiceExt; -use tower_batch_control::Batch; async fn sign_and_verify(mut verifier: V, n: usize) -> Result<(), V::Error> where diff --git a/zebra-consensus/src/primitives/redpallas/tests.rs b/zebra-consensus/src/primitives/redpallas/tests.rs index 6ae0717d6..a8e03d475 100644 --- a/zebra-consensus/src/primitives/redpallas/tests.rs +++ b/zebra-consensus/src/primitives/redpallas/tests.rs @@ -7,7 +7,6 @@ use std::time::Duration; use color_eyre::eyre::{eyre, Result}; use futures::stream::{FuturesUnordered, StreamExt}; use tower::ServiceExt; -use tower_batch_control::Batch; use zebra_chain::primitives::reddsa::{ orchard::{Binding, SpendAuth}, diff --git a/zebra-consensus/src/router.rs b/zebra-consensus/src/router.rs index d85873096..d9545ff09 100644 --- a/zebra-consensus/src/router.rs +++ b/zebra-consensus/src/router.rs @@ -240,13 +240,9 @@ where // Make sure the state contains the known best chain checkpoints, in a separate thread. - let (checkpoint_state_service, checkpoint_sync, network_clone) = { - let checkpoint_state_service = state_service.clone(); - let checkpoint_sync = config.checkpoint_sync; - let network_clone = network.clone(); - - (checkpoint_state_service, checkpoint_sync, network_clone) - }; + let checkpoint_state_service = state_service.clone(); + let checkpoint_sync = config.checkpoint_sync; + let checkpoint_network = network.clone(); let state_checkpoint_verify_handle = tokio::task::spawn( // TODO: move this into an async function? @@ -269,7 +265,7 @@ where // > activation block hashes given in § 3.12 ‘Mainnet and Testnet’ on p. 20. // // - let full_checkpoints = network_clone.checkpoint_list(); + let full_checkpoints = checkpoint_network.checkpoint_list(); let mut already_warned = false; for (height, checkpoint_hash) in full_checkpoints.iter() { diff --git a/zebra-consensus/src/router/tests.rs b/zebra-consensus/src/router/tests.rs index 6fe88361f..8fe304e33 100644 --- a/zebra-consensus/src/router/tests.rs +++ b/zebra-consensus/src/router/tests.rs @@ -4,18 +4,15 @@ use std::{sync::Arc, time::Duration}; use color_eyre::eyre::Report; use once_cell::sync::Lazy; -use tower::{layer::Layer, timeout::TimeoutLayer, Service}; +use tower::{layer::Layer, timeout::TimeoutLayer}; use zebra_chain::{ - block::{self, Block}, - parameters::Network, + block::Block, serialization::{ZcashDeserialize, ZcashDeserializeInto}, }; use zebra_state as zs; use zebra_test::transcript::{ExpectedTranscriptError, Transcript}; -use crate::Config; - use super::*; /// The timeout we apply to each verify future during testing. diff --git a/zebra-consensus/src/transaction.rs b/zebra-consensus/src/transaction.rs index 076f47ce7..4dc1f1e1c 100644 --- a/zebra-consensus/src/transaction.rs +++ b/zebra-consensus/src/transaction.rs @@ -3,7 +3,6 @@ use std::{ collections::HashMap, future::Future, - iter::FromIterator, pin::Pin, sync::Arc, task::{Context, Poll}, diff --git a/zebra-consensus/src/transaction/tests.rs b/zebra-consensus/src/transaction/tests.rs index 758c13fa9..6f5c3639e 100644 --- a/zebra-consensus/src/transaction/tests.rs +++ b/zebra-consensus/src/transaction/tests.rs @@ -42,13 +42,8 @@ mod prop; fn v5_fake_transactions() -> Result<(), Report> { let _init_guard = zebra_test::init(); - let networks = vec![ - (Network::Mainnet, zebra_test::vectors::MAINNET_BLOCKS.iter()), - (Network::Testnet, zebra_test::vectors::TESTNET_BLOCKS.iter()), - ]; - - for (network, blocks) in networks { - for transaction in fake_v5_transactions_for_network(&network, blocks) { + for network in Network::iter() { + for transaction in fake_v5_transactions_for_network(&network, network.block_iter()) { match check::has_inputs_and_outputs(&transaction) { Ok(()) => (), Err(TransactionError::NoInputs) | Err(TransactionError::NoOutputs) => (), @@ -858,16 +853,12 @@ async fn v5_transaction_is_rejected_before_nu5_activation() { const V5_TRANSACTION_VERSION: u32 = 5; let canopy = NetworkUpgrade::Canopy; - let networks = vec![ - (Network::Mainnet, zebra_test::vectors::MAINNET_BLOCKS.iter()), - (Network::Testnet, zebra_test::vectors::TESTNET_BLOCKS.iter()), - ]; - for (network, blocks) in networks { + for network in Network::iter() { let state_service = service_fn(|_| async { unreachable!("Service should not be called") }); let verifier = Verifier::new(&network, state_service); - let transaction = fake_v5_transactions_for_network(&network, blocks) + let transaction = fake_v5_transactions_for_network(&network, network.block_iter()) .next_back() .expect("At least one fake V5 transaction in the test vectors"); @@ -899,7 +890,7 @@ fn v5_transaction_is_accepted_after_nu5_activation_mainnet() { #[test] fn v5_transaction_is_accepted_after_nu5_activation_testnet() { - v5_transaction_is_accepted_after_nu5_activation_for_network(Network::Testnet) + v5_transaction_is_accepted_after_nu5_activation_for_network(Network::new_default_testnet()) } fn v5_transaction_is_accepted_after_nu5_activation_for_network(network: Network) { @@ -1544,7 +1535,7 @@ fn v4_transaction_with_conflicting_sprout_nullifier_across_joinsplits_is_rejecte /// Test if V5 transaction with transparent funds is accepted. #[tokio::test] async fn v5_transaction_with_transparent_transfer_is_accepted() { - let network = Network::Testnet; + let network = Network::new_default_testnet(); let network_upgrade = NetworkUpgrade::Nu5; let nu5_activation_height = network_upgrade @@ -1601,12 +1592,13 @@ async fn v5_transaction_with_transparent_transfer_is_accepted() { /// accepted. #[tokio::test] async fn v5_transaction_with_last_valid_expiry_height() { + let network = Network::new_default_testnet(); let state_service = service_fn(|_| async { unreachable!("State service should not be called") }); - let verifier = Verifier::new(&Network::Testnet, state_service); + let verifier = Verifier::new(&network, state_service); let block_height = NetworkUpgrade::Nu5 - .activation_height(&Network::Testnet) + .activation_height(&network) .expect("Nu5 activation height for testnet is specified"); let fund_height = (block_height - 1).expect("fake source fund block height is too small"); let (input, output, known_utxos) = mock_transparent_transfer( @@ -1646,12 +1638,13 @@ async fn v5_transaction_with_last_valid_expiry_height() { /// is equal to the height of the block the transaction belongs to. #[tokio::test] async fn v5_coinbase_transaction_expiry_height() { + let network = Network::new_default_testnet(); let state_service = service_fn(|_| async { unreachable!("State service should not be called") }); - let verifier = Verifier::new(&Network::Testnet, state_service); + let verifier = Verifier::new(&network, state_service); let block_height = NetworkUpgrade::Nu5 - .activation_height(&Network::Testnet) + .activation_height(&network) .expect("Nu5 activation height for testnet is specified"); let (input, output) = mock_coinbase_transparent_output(block_height); @@ -1761,12 +1754,14 @@ async fn v5_coinbase_transaction_expiry_height() { /// Tests if an expired non-coinbase V5 transaction is rejected. #[tokio::test] async fn v5_transaction_with_too_low_expiry_height() { + let network = Network::new_default_testnet(); + let state_service = service_fn(|_| async { unreachable!("State service should not be called") }); - let verifier = Verifier::new(&Network::Testnet, state_service); + let verifier = Verifier::new(&network, state_service); let block_height = NetworkUpgrade::Nu5 - .activation_height(&Network::Testnet) + .activation_height(&network) .expect("Nu5 activation height for testnet is specified"); let fund_height = (block_height - 1).expect("fake source fund block height is too small"); let (input, output, known_utxos) = mock_transparent_transfer( @@ -1864,7 +1859,7 @@ async fn v5_transaction_with_exceeding_expiry_height() { /// Test if V5 coinbase transaction is accepted. #[tokio::test] async fn v5_coinbase_transaction_is_accepted() { - let network = Network::Testnet; + let network = Network::new_default_testnet(); let network_upgrade = NetworkUpgrade::Nu5; let nu5_activation_height = network_upgrade @@ -1916,7 +1911,7 @@ async fn v5_coinbase_transaction_is_accepted() { /// script prevents spending the source UTXO. #[tokio::test] async fn v5_transaction_with_transparent_transfer_is_rejected_by_the_script() { - let network = Network::Testnet; + let network = Network::new_default_testnet(); let network_upgrade = NetworkUpgrade::Nu5; let nu5_activation_height = network_upgrade @@ -2759,8 +2754,9 @@ fn add_to_sprout_pool_after_nu() { fn coinbase_outputs_are_decryptable_for_historical_blocks() -> Result<(), Report> { let _init_guard = zebra_test::init(); - coinbase_outputs_are_decryptable_for_historical_blocks_for_network(Network::Mainnet)?; - coinbase_outputs_are_decryptable_for_historical_blocks_for_network(Network::Testnet)?; + for network in Network::iter() { + coinbase_outputs_are_decryptable_for_historical_blocks_for_network(network)?; + } Ok(()) } @@ -2844,7 +2840,7 @@ fn fill_action_with_note_encryption_test_vector( /// viewing key. #[test] fn coinbase_outputs_are_decryptable_for_fake_v5_blocks() { - let network = Network::Testnet; + let network = Network::new_default_testnet(); for v in zebra_test::vectors::ORCHARD_NOTE_ENCRYPTION_ZERO_VECTOR.iter() { // Find a transaction with no inputs or outputs to use as base @@ -2886,7 +2882,7 @@ fn coinbase_outputs_are_decryptable_for_fake_v5_blocks() { /// viewing key. #[test] fn shielded_outputs_are_not_decryptable_for_fake_v5_blocks() { - let network = Network::Testnet; + let network = Network::new_default_testnet(); for v in zebra_test::vectors::ORCHARD_NOTE_ENCRYPTION_VECTOR.iter() { // Find a transaction with no inputs or outputs to use as base diff --git a/zebra-grpc/Cargo.toml b/zebra-grpc/Cargo.toml index 310da0024..44a0fbc46 100644 --- a/zebra-grpc/Cargo.toml +++ b/zebra-grpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-grpc" -version = "0.1.0-alpha.2" +version = "0.1.0-alpha.3" authors = ["Zcash Foundation "] description = "Zebra gRPC interface" license = "MIT OR Apache-2.0" @@ -19,23 +19,23 @@ categories = ["cryptography::cryptocurrencies"] futures-util = "0.3.28" tonic = "0.11.0" tonic-reflection = "0.11.0" -prost = "0.12.3" +prost = "0.12.4" serde = { version = "1.0.196", features = ["serde_derive"] } -tokio = { version = "1.36.0", features = ["macros", "rt-multi-thread"] } -tokio-stream = "0.1.14" +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" } -zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.35", features = ["shielded-scan"] } -zebra-chain = { path = "../zebra-chain" , version = "1.0.0-beta.35" } +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" } [build-dependencies] tonic-build = "0.11.0" [dev-dependencies] -insta = { version = "1.36.1", features = ["redactions", "json", "ron"] } +insta = { version = "1.38.0", features = ["redactions", "json", "ron"] } zebra-chain = { path = "../zebra-chain", features = ["proptest-impl"] } zebra-state = { path = "../zebra-state" } diff --git a/zebra-grpc/src/tests/snapshot.rs b/zebra-grpc/src/tests/snapshot.rs index 37acb59fe..6b81a3c70 100644 --- a/zebra-grpc/src/tests/snapshot.rs +++ b/zebra-grpc/src/tests/snapshot.rs @@ -38,7 +38,7 @@ async fn test_grpc_response_data() { zebra_test::net::random_known_port() ), test_mocked_rpc_response_data_for_network( - Network::Testnet, + Network::new_default_testnet(), zebra_test::net::random_known_port() ), ); diff --git a/zebra-network/Cargo.toml b/zebra-network/Cargo.toml index d5215a1b5..40c912e39 100644 --- a/zebra-network/Cargo.toml +++ b/zebra-network/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-network" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation ", "Tower Maintainers "] description = "Networking code for Zebra" # # Legal @@ -40,29 +40,29 @@ progress-bar = [ proptest-impl = ["proptest", "proptest-derive", "zebra-chain/proptest-impl"] [dependencies] -bitflags = "2.4.2" +bitflags = "2.5.0" byteorder = "1.5.0" -bytes = "1.5.0" +bytes = "1.6.0" chrono = { version = "0.4.34", default-features = false, features = ["clock", "std"] } dirs = "5.0.1" hex = "0.4.3" humantime-serde = "1.1.1" -indexmap = { version = "2.2.5", features = ["serde"] } +indexmap = { version = "2.2.6", features = ["serde"] } itertools = "0.12.1" lazy_static = "1.4.0" num-integer = "0.1.46" ordered-map = "0.4.2" pin-project = "1.1.5" rand = "0.8.5" -rayon = "1.9.0" -regex = "1.10.3" +rayon = "1.10.0" +regex = "1.10.4" serde = { version = "1.0.196", features = ["serde_derive"] } tempfile = "3.10.1" thiserror = "1.0.58" futures = "0.3.30" -tokio = { version = "1.36.0", features = ["fs", "io-util", "net", "time", "tracing", "macros", "rt-multi-thread"] } -tokio-stream = { version = "0.1.14", features = ["sync", "time"] } +tokio = { version = "1.37.0", features = ["fs", "io-util", "net", "time", "tracing", "macros", "rt-multi-thread"] } +tokio-stream = { version = "0.1.15", features = ["sync", "time"] } tokio-util = { version = "0.7.10", features = ["codec"] } tower = { version = "0.4.13", features = ["retry", "discover", "load", "load-shed", "timeout", "util", "buffer"] } @@ -83,14 +83,14 @@ howudoin = { version = "0.1.2", optional = true } proptest = { version = "1.4.0", optional = true } proptest-derive = { version = "0.4.0", optional = true } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["async-error"] } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["async-error"] } [dev-dependencies] proptest = "1.4.0" proptest-derive = "0.4.0" static_assertions = "1.1.0" -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } toml = "0.8.11" zebra-chain = { path = "../zebra-chain", features = ["proptest-impl"] } diff --git a/zebra-network/src/address_book.rs b/zebra-network/src/address_book.rs index f19cdcbc8..9ecf5aa24 100644 --- a/zebra-network/src/address_book.rs +++ b/zebra-network/src/address_book.rs @@ -4,7 +4,6 @@ use std::{ cmp::Reverse, collections::HashMap, - iter::Extend, net::{IpAddr, SocketAddr}, sync::{Arc, Mutex}, time::Instant, diff --git a/zebra-network/src/config.rs b/zebra-network/src/config.rs index da989f990..fa1e20568 100644 --- a/zebra-network/src/config.rs +++ b/zebra-network/src/config.rs @@ -5,7 +5,6 @@ use std::{ ffi::OsString, io::{self, ErrorKind}, net::{IpAddr, SocketAddr}, - string::String, time::Duration, }; @@ -15,7 +14,10 @@ use tempfile::NamedTempFile; use tokio::{fs, io::AsyncWriteExt}; use tracing::Span; -use zebra_chain::parameters::Network; +use zebra_chain::parameters::{ + testnet::{self, ConfiguredActivationHeights}, + Network, NetworkKind, +}; use crate::{ constants::{ @@ -222,10 +224,16 @@ impl Config { } /// Returns the initial seed peer hostnames for the configured network. - pub fn initial_peer_hostnames(&self) -> &IndexSet { - match self.network { - Network::Mainnet => &self.initial_mainnet_peers, - Network::Testnet => &self.initial_testnet_peers, + pub fn initial_peer_hostnames(&self) -> IndexSet { + match &self.network { + Network::Mainnet => self.initial_mainnet_peers.clone(), + Network::Testnet(params) if params.is_default_testnet() => { + self.initial_testnet_peers.clone() + } + // TODO: Check if the network is an incompatible custom testnet (_not_ Regtest), then panic if `initial_testnet_peers` + // contains any of the default testnet peers, or return `initial_testnet_peers` otherwise. See: + // + Network::Testnet(_params) => IndexSet::new(), } } @@ -619,11 +627,18 @@ impl<'de> Deserialize<'de> for Config { where D: Deserializer<'de>, { + #[derive(Deserialize)] + struct DTestnetParameters { + #[serde(default)] + pub(super) activation_heights: ConfiguredActivationHeights, + } + #[derive(Deserialize)] #[serde(deny_unknown_fields, default)] struct DConfig { listen_addr: String, - network: Network, + network: NetworkKind, + testnet_parameters: Option, initial_mainnet_peers: IndexSet, initial_testnet_peers: IndexSet, cache_dir: CacheDir, @@ -638,7 +653,8 @@ impl<'de> Deserialize<'de> for Config { let config = Config::default(); Self { listen_addr: "0.0.0.0".to_string(), - network: config.network, + network: Default::default(), + testnet_parameters: None, initial_mainnet_peers: config.initial_mainnet_peers, initial_testnet_peers: config.initial_testnet_peers, cache_dir: config.cache_dir, @@ -651,7 +667,8 @@ impl<'de> Deserialize<'de> for Config { let DConfig { listen_addr, - network, + network: network_kind, + testnet_parameters, initial_mainnet_peers, initial_testnet_peers, cache_dir, @@ -660,6 +677,26 @@ 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" + ); + + 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"), + } + }; + let listen_addr = match listen_addr.parse::() { Ok(socket) => Ok(socket), Err(_) => match listen_addr.parse::() { diff --git a/zebra-network/src/constants.rs b/zebra-network/src/constants.rs index 7d7543d84..363c05717 100644 --- a/zebra-network/src/constants.rs +++ b/zebra-network/src/constants.rs @@ -16,6 +16,7 @@ use crate::protocol::external::types::*; use zebra_chain::{ parameters::{ Network::{self, *}, + NetworkKind, NetworkUpgrade::*, }, serialization::Duration32, @@ -392,11 +393,12 @@ lazy_static! { /// /// The minimum network protocol version typically changes after Mainnet and /// Testnet network upgrades. - pub static ref INITIAL_MIN_NETWORK_PROTOCOL_VERSION: HashMap = { + // TODO: Move the value here to a field on `testnet::Parameters` (#8367) + pub static ref INITIAL_MIN_NETWORK_PROTOCOL_VERSION: HashMap = { let mut hash_map = HashMap::new(); - hash_map.insert(Mainnet, Version::min_specified_for_upgrade(&Mainnet, Nu5)); - hash_map.insert(Testnet, Version::min_specified_for_upgrade(&Testnet, Nu5)); + hash_map.insert(NetworkKind::Mainnet, Version::min_specified_for_upgrade(&Mainnet, Nu5)); + hash_map.insert(NetworkKind::Testnet, Version::min_specified_for_upgrade(&Network::new_default_testnet(), Nu5)); hash_map }; diff --git a/zebra-network/src/isolated/tests/vectors.rs b/zebra-network/src/isolated/tests/vectors.rs index 94f75fe57..a037fcb5e 100644 --- a/zebra-network/src/isolated/tests/vectors.rs +++ b/zebra-network/src/isolated/tests/vectors.rs @@ -14,8 +14,6 @@ use crate::{ use super::super::*; -use Network::*; - /// Test that `connect_isolated` sends a version message with minimal distinguishing features, /// when sent over TCP. #[tokio::test] @@ -26,8 +24,9 @@ async fn connect_isolated_sends_anonymised_version_message_tcp() { return; } - connect_isolated_sends_anonymised_version_message_tcp_net(Mainnet).await; - connect_isolated_sends_anonymised_version_message_tcp_net(Testnet).await; + for network in Network::iter() { + connect_isolated_sends_anonymised_version_message_tcp_net(network).await; + } } async fn connect_isolated_sends_anonymised_version_message_tcp_net(network: Network) { @@ -82,9 +81,9 @@ async fn connect_isolated_sends_anonymised_version_message_tcp_net(network: Netw #[tokio::test] async fn connect_isolated_sends_anonymised_version_message_mem() { let _init_guard = zebra_test::init(); - - connect_isolated_sends_anonymised_version_message_mem_net(Mainnet).await; - connect_isolated_sends_anonymised_version_message_mem_net(Testnet).await; + for network in Network::iter() { + connect_isolated_sends_anonymised_version_message_mem_net(network).await; + } } async fn connect_isolated_sends_anonymised_version_message_mem_net(network: Network) { diff --git a/zebra-network/src/meta_addr.rs b/zebra-network/src/meta_addr.rs index 8c0336f4a..1171ceee2 100644 --- a/zebra-network/src/meta_addr.rs +++ b/zebra-network/src/meta_addr.rs @@ -1,7 +1,7 @@ //! An address-with-metadata type used in Bitcoin networking. use std::{ - cmp::{max, Ord, Ordering}, + cmp::{max, Ordering}, time::Instant, }; diff --git a/zebra-network/src/meta_addr/arbitrary.rs b/zebra-network/src/meta_addr/arbitrary.rs index 3f314f367..27afb7992 100644 --- a/zebra-network/src/meta_addr/arbitrary.rs +++ b/zebra-network/src/meta_addr/arbitrary.rs @@ -2,7 +2,7 @@ use std::net::IpAddr; -use proptest::{arbitrary::any, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; use zebra_chain::{parameters::Network::*, serialization::DateTime32}; diff --git a/zebra-network/src/peer/connection.rs b/zebra-network/src/peer/connection.rs index f5ea2d0a4..2d9961020 100644 --- a/zebra-network/src/peer/connection.rs +++ b/zebra-network/src/peer/connection.rs @@ -9,11 +9,7 @@ use std::{borrow::Cow, collections::HashSet, fmt, pin::Pin, sync::Arc, time::Instant}; -use futures::{ - future::{self, Either}, - prelude::*, - stream::Stream, -}; +use futures::{future::Either, prelude::*}; use rand::{seq::SliceRandom, thread_rng, Rng}; use tokio::time::{sleep, Sleep}; use tower::{Service, ServiceExt}; diff --git a/zebra-network/src/peer/connector.rs b/zebra-network/src/peer/connector.rs index 67947f9e4..e167d97b9 100644 --- a/zebra-network/src/peer/connector.rs +++ b/zebra-network/src/peer/connector.rs @@ -1,7 +1,6 @@ //! Wrapper around handshake logic that also opens a TCP connection. use std::{ - future::Future, pin::Pin, task::{Context, Poll}, }; diff --git a/zebra-network/src/peer_set/initialize/tests/vectors.rs b/zebra-network/src/peer_set/initialize/tests/vectors.rs index 54fd25a26..c9e0c26fb 100644 --- a/zebra-network/src/peer_set/initialize/tests/vectors.rs +++ b/zebra-network/src/peer_set/initialize/tests/vectors.rs @@ -80,8 +80,9 @@ async fn local_listener_unspecified_port_unspecified_addr_v4() { // these tests might fail on machines with no configured IPv4 addresses // (localhost should be enough) - local_listener_port_with("0.0.0.0:0".parse().unwrap(), Mainnet).await; - local_listener_port_with("0.0.0.0:0".parse().unwrap(), Testnet).await; + for network in Network::iter() { + local_listener_port_with("0.0.0.0:0".parse().unwrap(), network).await; + } } /// Test that zebra-network discovers dynamic bind-to-all-interfaces listener ports, @@ -101,8 +102,9 @@ async fn local_listener_unspecified_port_unspecified_addr_v6() { } // these tests might fail on machines with no configured IPv6 addresses - local_listener_port_with("[::]:0".parse().unwrap(), Mainnet).await; - local_listener_port_with("[::]:0".parse().unwrap(), Testnet).await; + for network in Network::iter() { + local_listener_port_with("[::]:0".parse().unwrap(), network).await; + } } /// Test that zebra-network discovers dynamic localhost listener ports, @@ -116,8 +118,9 @@ async fn local_listener_unspecified_port_localhost_addr_v4() { } // these tests might fail on machines with unusual IPv4 localhost configs - local_listener_port_with("127.0.0.1:0".parse().unwrap(), Mainnet).await; - local_listener_port_with("127.0.0.1:0".parse().unwrap(), Testnet).await; + for network in Network::iter() { + local_listener_port_with("127.0.0.1:0".parse().unwrap(), network).await; + } } /// Test that zebra-network discovers dynamic localhost listener ports, @@ -135,8 +138,9 @@ async fn local_listener_unspecified_port_localhost_addr_v6() { } // these tests might fail on machines with no configured IPv6 addresses - local_listener_port_with("[::1]:0".parse().unwrap(), Mainnet).await; - local_listener_port_with("[::1]:0".parse().unwrap(), Testnet).await; + for network in Network::iter() { + local_listener_port_with("[::1]:0".parse().unwrap(), network).await; + } } /// Test that zebra-network propagates fixed localhost listener ports to the `AddressBook`. @@ -150,8 +154,9 @@ async fn local_listener_fixed_port_localhost_addr_v4() { return; } - local_listener_port_with(SocketAddr::new(localhost_v4, random_known_port()), Mainnet).await; - local_listener_port_with(SocketAddr::new(localhost_v4, random_known_port()), Testnet).await; + for network in Network::iter() { + local_listener_port_with(SocketAddr::new(localhost_v4, random_known_port()), network).await; + } } /// Test that zebra-network propagates fixed localhost listener ports to the `AddressBook`. @@ -169,8 +174,9 @@ async fn local_listener_fixed_port_localhost_addr_v6() { return; } - local_listener_port_with(SocketAddr::new(localhost_v6, random_known_port()), Mainnet).await; - local_listener_port_with(SocketAddr::new(localhost_v6, random_known_port()), Testnet).await; + for network in Network::iter() { + local_listener_port_with(SocketAddr::new(localhost_v6, random_known_port()), network).await; + } } /// Test zebra-network with a peer limit of zero peers on mainnet. @@ -207,8 +213,15 @@ async fn peer_limit_zero_testnet() { let unreachable_inbound_service = service_fn(|_| async { unreachable!("inbound service should never be called") }); - let address_book = - init_with_peer_limit(0, unreachable_inbound_service, Testnet, None, None).await; + let address_book = init_with_peer_limit( + 0, + unreachable_inbound_service, + Network::new_default_testnet(), + None, + None, + ) + .await; + assert_eq!( address_book.lock().unwrap().peers().count(), 0, @@ -247,7 +260,14 @@ async fn peer_limit_one_testnet() { let nil_inbound_service = service_fn(|_| async { Ok(Response::Nil) }); - let _ = init_with_peer_limit(1, nil_inbound_service, Testnet, None, None).await; + let _ = init_with_peer_limit( + 1, + nil_inbound_service, + Network::new_default_testnet(), + None, + None, + ) + .await; // Let the crawler run for a while. tokio::time::sleep(CRAWLER_TEST_DURATION).await; @@ -285,7 +305,14 @@ async fn peer_limit_two_testnet() { let nil_inbound_service = service_fn(|_| async { Ok(Response::Nil) }); - let _ = init_with_peer_limit(2, nil_inbound_service, Testnet, None, None).await; + let _ = init_with_peer_limit( + 2, + nil_inbound_service, + Network::new_default_testnet(), + None, + None, + ) + .await; // Let the crawler run for a while. tokio::time::sleep(CRAWLER_TEST_DURATION).await; diff --git a/zebra-network/src/peer_set/set.rs b/zebra-network/src/peer_set/set.rs index 722e09b6e..1cac476ff 100644 --- a/zebra-network/src/peer_set/set.rs +++ b/zebra-network/src/peer_set/set.rs @@ -106,7 +106,7 @@ use std::{ use futures::{ channel::{mpsc, oneshot}, - future::{Future, FutureExt, TryFutureExt}, + future::{FutureExt, TryFutureExt}, prelude::*, stream::FuturesUnordered, task::noop_waker, diff --git a/zebra-network/src/protocol/external/arbitrary.rs b/zebra-network/src/protocol/external/arbitrary.rs index a8706aa4b..373c527ef 100644 --- a/zebra-network/src/protocol/external/arbitrary.rs +++ b/zebra-network/src/protocol/external/arbitrary.rs @@ -2,7 +2,7 @@ use std::net::SocketAddr; -use proptest::{arbitrary::any, arbitrary::Arbitrary, collection::vec, prelude::*}; +use proptest::{collection::vec, prelude::*}; use zebra_chain::{block, transaction}; diff --git a/zebra-network/src/protocol/external/tests/prop.rs b/zebra-network/src/protocol/external/tests/prop.rs index 1ab9a6e67..b85208733 100644 --- a/zebra-network/src/protocol/external/tests/prop.rs +++ b/zebra-network/src/protocol/external/tests/prop.rs @@ -1,7 +1,5 @@ //! Randomised property tests for Zebra's Zcash network protocol types. -use std::convert::TryInto; - use bytes::BytesMut; use proptest::{collection::vec, prelude::*}; use tokio_util::codec::{Decoder, Encoder}; diff --git a/zebra-network/src/protocol/external/tests/vectors.rs b/zebra-network/src/protocol/external/tests/vectors.rs index 4f8e275e0..58d9c0b1d 100644 --- a/zebra-network/src/protocol/external/tests/vectors.rs +++ b/zebra-network/src/protocol/external/tests/vectors.rs @@ -1,6 +1,6 @@ //! Fixed test vectors for external protocol messages. -use std::{convert::TryInto, io::Write}; +use std::io::Write; use byteorder::{LittleEndian, WriteBytesExt}; diff --git a/zebra-network/src/protocol/external/types.rs b/zebra-network/src/protocol/external/types.rs index 08e2aa380..0e35698a7 100644 --- a/zebra-network/src/protocol/external/types.rs +++ b/zebra-network/src/protocol/external/types.rs @@ -8,7 +8,7 @@ use zebra_chain::{ }, }; -use crate::constants::{self, magics}; +use crate::constants::{self, magics, CURRENT_NETWORK_PROTOCOL_VERSION}; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; @@ -31,7 +31,8 @@ impl ParameterMagic for Network { fn magic_value(&self) -> Magic { match self { Network::Mainnet => magics::MAINNET, - Network::Testnet => magics::TESTNET, + // TODO: Move `Magic` struct definition to `zebra-chain`, add it as a field in `testnet::Parameters`, and return it here. + Network::Testnet(_params) => magics::TESTNET, } } } @@ -80,7 +81,7 @@ impl Version { /// - after Zebra's local network is slow or shut down. fn initial_min_for_network(network: &Network) -> Version { *constants::INITIAL_MIN_NETWORK_PROTOCOL_VERSION - .get(network) + .get(&network.kind()) .expect("We always have a value for testnet or mainnet") } @@ -103,17 +104,22 @@ impl Version { // sync? zcashd accepts 170_002 or later during its initial sync. Version(match (network, network_upgrade) { (_, Genesis) | (_, BeforeOverwinter) => 170_002, - (Testnet, Overwinter) => 170_003, + (Testnet(params), Overwinter) if params.is_default_testnet() => 170_003, (Mainnet, Overwinter) => 170_005, + // TODO: Use 170_006 for (Testnet(params), Sapling) if params.is_regtest() (`Regtest` in zcashd uses + // version 170_006 for Sapling, and the same values as Testnet for other network upgrades.) (_, Sapling) => 170_007, - (Testnet, Blossom) => 170_008, + (Testnet(params), Blossom) if params.is_default_testnet() => 170_008, (Mainnet, Blossom) => 170_009, - (Testnet, Heartwood) => 170_010, + (Testnet(params), Heartwood) if params.is_default_testnet() => 170_010, (Mainnet, Heartwood) => 170_011, - (Testnet, Canopy) => 170_012, + (Testnet(params), Canopy) if params.is_default_testnet() => 170_012, (Mainnet, Canopy) => 170_013, - (Testnet, Nu5) => 170_050, + (Testnet(params), Nu5) if params.is_default_testnet() => 170_050, (Mainnet, Nu5) => 170_100, + + // It should be fine to reject peers with earlier network protocol versions on custom testnets for now. + (Testnet(_params), _) => CURRENT_NETWORK_PROTOCOL_VERSION.0, }) } } @@ -201,7 +207,7 @@ mod test { #[test] fn version_extremes_testnet() { - version_extremes(&Testnet) + version_extremes(&Network::new_default_testnet()) } /// Test the min_specified_for_upgrade and min_specified_for_height functions for `network` with @@ -229,7 +235,7 @@ mod test { #[test] fn version_consistent_testnet() { - version_consistent(&Testnet) + version_consistent(&Network::new_default_testnet()) } /// Check that the min_specified_for_upgrade and min_specified_for_height functions diff --git a/zebra-node-services/Cargo.toml b/zebra-node-services/Cargo.toml index dc67538fc..c455e262e 100644 --- a/zebra-node-services/Cargo.toml +++ b/zebra-node-services/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-node-services" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "The interfaces of some Zebra node services" license = "MIT OR Apache-2.0" @@ -37,7 +37,7 @@ rpc-client = [ shielded-scan = ["tokio"] [dependencies] -zebra-chain = { path = "../zebra-chain" , version = "1.0.0-beta.35" } +zebra-chain = { path = "../zebra-chain" , version = "1.0.0-beta.36" } # Optional dependencies @@ -47,8 +47,8 @@ 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.113", optional = true } -tokio = { version = "1.36.0", features = ["time"], optional = true } +serde_json = { version = "1.0.115", optional = true } +tokio = { version = "1.37.0", features = ["time"], optional = true } [dev-dependencies] @@ -56,4 +56,4 @@ 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.113" +serde_json = "1.0.115" diff --git a/zebra-rpc/Cargo.toml b/zebra-rpc/Cargo.toml index 0f5b210c9..361d24a92 100644 --- a/zebra-rpc/Cargo.toml +++ b/zebra-rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-rpc" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "A Zebra JSON Remote Procedure Call (JSON-RPC) interface" license = "MIT OR Apache-2.0" @@ -53,10 +53,10 @@ 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.113", features = ["preserve_order"] } -indexmap = { version = "2.2.5", features = ["serde"] } +serde_json = { version = "1.0.115", features = ["preserve_order"] } +indexmap = { version = "2.2.6", features = ["serde"] } -tokio = { version = "1.36.0", features = ["time", "rt-multi-thread", "macros", "tracing"] } +tokio = { version = "1.37.0", features = ["time", "rt-multi-thread", "macros", "tracing"] } tower = "0.4.13" tracing = "0.1.39" @@ -67,29 +67,29 @@ serde = { version = "1.0.196", features = ["serde_derive"] } # Experimental feature getblocktemplate-rpcs rand = { version = "0.8.5", optional = true } # ECC deps used by getblocktemplate-rpcs feature -zcash_address = { version = "0.3.1", optional = true } +zcash_address = { version = "0.3.2", optional = true } # Test-only feature proptest-impl proptest = { version = "1.4.0", optional = true } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["json-conversion"] } -zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.35" } -zebra-network = { path = "../zebra-network", version = "1.0.0-beta.35" } -zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.35" } -zebra-script = { path = "../zebra-script", version = "1.0.0-beta.35" } -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35" } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["json-conversion"] } +zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.36" } +zebra-network = { path = "../zebra-network", version = "1.0.0-beta.36" } +zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36" } +zebra-script = { path = "../zebra-script", version = "1.0.0-beta.36" } +zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36" } [dev-dependencies] -insta = { version = "1.36.1", features = ["redactions", "json", "ron"] } +insta = { version = "1.38.0", features = ["redactions", "json", "ron"] } proptest = "1.4.0" thiserror = "1.0.58" -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-network = { path = "../zebra-network", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35", features = ["proptest-impl"] } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-network = { path = "../zebra-network", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36", features = ["proptest-impl"] } -zebra-test = { path = "../zebra-test", version = "1.0.0-beta.35" } +zebra-test = { path = "../zebra-test", version = "1.0.0-beta.36" } diff --git a/zebra-rpc/src/methods.rs b/zebra-rpc/src/methods.rs index b4105c29d..d1dd05649 100644 --- a/zebra-rpc/src/methods.rs +++ b/zebra-rpc/src/methods.rs @@ -6,7 +6,7 @@ //! Some parts of the `zcashd` RPC documentation are outdated. //! So this implementation follows the `zcashd` server and `lightwalletd` client implementations. -use std::{collections::HashSet, default::Default, fmt::Debug, sync::Arc}; +use std::{collections::HashSet, fmt::Debug, sync::Arc}; use chrono::Utc; use futures::{stream::FuturesOrdered, FutureExt, StreamExt, TryFutureExt}; @@ -38,6 +38,10 @@ use crate::{ queue::Queue, }; +mod errors; + +use errors::{MapServerError, OkOrServerError}; + // We don't use a types/ module here, because it is redundant. pub mod trees; @@ -675,7 +679,6 @@ where } // TODO: - // - use a generic error constructor (#5548) // - use `height_from_signed_int()` to handle negative heights // (this might be better in the state request, because it needs the state height) // - create a function that handles block hashes or heights, and use it in `z_get_treestate()` @@ -727,7 +730,7 @@ where }), _ => unreachable!("unmatched response to a block request"), } - } else if verbosity == 1 { + } else if verbosity == 1 || verbosity == 2 { // # Performance // // This RPC is used in `lightwalletd`'s initial sync of 2 million blocks, @@ -748,6 +751,8 @@ where // must be able to handle chain forks, including a hash for a block that is // later discovered to be on a side chain. + let should_read_block_header = verbosity == 2; + let hash = match hash_or_height { HashOrHeight::Hash(hash) => hash, HashOrHeight::Height(height) => { @@ -776,120 +781,80 @@ where } }; - // Get transaction IDs from the transaction index by block hash - // - // # Concurrency - // - // We look up by block hash so the hash, transaction IDs, and confirmations - // are consistent. - // - // A block's transaction IDs are never modified, so all possible responses are - // valid. Clients that query block heights must be able to handle chain forks, - // including getting transaction IDs from any chain fork. - let request = zebra_state::ReadRequest::TransactionIdsForBlock(hash.into()); - let tx_ids_response_fut = state.clone().oneshot(request); + // TODO: look up the height if we only have a hash, + // this needs a new state request for the height -> hash index + let height = hash_or_height.height(); - // Get block confirmations from the block height index - // // # Concurrency // // We look up by block hash so the hash, transaction IDs, and confirmations // are consistent. - // - // All possible responses are valid, even if a block is added to the chain, or - // the best chain changes. Clients must be able to handle chain forks, including - // different confirmation values before or after added blocks, and switching - // between -1 and multiple different confirmation values. + let mut requests = vec![ + // Get transaction IDs from the transaction index by block hash + // + // # Concurrency + // + // A block's transaction IDs are never modified, so all possible responses are + // valid. Clients that query block heights must be able to handle chain forks, + // including getting transaction IDs from any chain fork. + zebra_state::ReadRequest::TransactionIdsForBlock(hash.into()), + // Sapling trees + zebra_state::ReadRequest::SaplingTree(hash.into()), + // Orchard trees + zebra_state::ReadRequest::OrchardTree(hash.into()), + // Get block confirmations from the block height index + // + // # Concurrency + // + // All possible responses are valid, even if a block is added to the chain, or + // the best chain changes. Clients must be able to handle chain forks, including + // different confirmation values before or after added blocks, and switching + // between -1 and multiple different confirmation values. + zebra_state::ReadRequest::Depth(hash), + ]; + + if should_read_block_header { + // Block header + requests.push(zebra_state::ReadRequest::BlockHeader(hash.into())) + } + + let mut futs = FuturesOrdered::new(); + + for request in requests { + futs.push_back(state.clone().oneshot(request)); + } + + let tx_ids_response = futs.next().await.expect("`futs` should not be empty"); + let tx = match tx_ids_response.map_server_error()? { + zebra_state::ReadResponse::TransactionIdsForBlock(tx_ids) => tx_ids + .ok_or_server_error("Block not found")? + .iter() + .map(|tx_id| tx_id.encode_hex()) + .collect(), + _ => unreachable!("unmatched response to a transaction_ids_for_block request"), + }; + + let sapling_tree_response = futs.next().await.expect("`futs` should not be empty"); + let sapling_note_commitment_tree_count = + match sapling_tree_response.map_server_error()? { + zebra_state::ReadResponse::SaplingTree(Some(nct)) => nct.count(), + zebra_state::ReadResponse::SaplingTree(None) => 0, + _ => unreachable!("unmatched response to a SaplingTree request"), + }; + + let orchard_tree_response = futs.next().await.expect("`futs` should not be empty"); + let orchard_note_commitment_tree_count = + match orchard_tree_response.map_server_error()? { + zebra_state::ReadResponse::OrchardTree(Some(nct)) => nct.count(), + zebra_state::ReadResponse::OrchardTree(None) => 0, + _ => unreachable!("unmatched response to a OrchardTree request"), + }; // From const NOT_IN_BEST_CHAIN_CONFIRMATIONS: i64 = -1; - let request = zebra_state::ReadRequest::Depth(hash); - let depth_response_fut = state.clone().oneshot(request); - - // Sapling trees - // - // # Concurrency - // - // We look up by block hash so the hash, transaction IDs, and confirmations - // are consistent. - let request = zebra_state::ReadRequest::SaplingTree(hash.into()); - let sapling_tree_response_fut = state.clone().oneshot(request); - - // Orchard trees - // - // # Concurrency - // - // We look up by block hash so the hash, transaction IDs, and confirmations - // are consistent. - let request = zebra_state::ReadRequest::OrchardTree(hash.into()); - let orchard_tree_response_fut = state.clone().oneshot(request); - - let mut futs = FuturesOrdered::new(); - futs.push_back(tx_ids_response_fut); - futs.push_back(sapling_tree_response_fut); - futs.push_back(orchard_tree_response_fut); - futs.push_back(depth_response_fut); - - let tx_ids_response = futs - .next() - .await - .expect("should have 4 items in futs") - .map_err(|error| Error { - code: ErrorCode::ServerError(0), - message: error.to_string(), - data: None, - })?; - - let sapling_tree_response = futs - .next() - .await - .expect("should have 3 items in futs") - .map_err(|error| Error { - code: ErrorCode::ServerError(0), - message: error.to_string(), - data: None, - })?; - - let orchard_tree_response = futs - .next() - .await - .expect("should have 2 items in futs") - .map_err(|error| Error { - code: ErrorCode::ServerError(0), - message: error.to_string(), - data: None, - })?; - - let depth_response = futs - .next() - .await - .expect("should have an item in futs") - .map_err(|error| Error { - code: ErrorCode::ServerError(0), - message: error.to_string(), - data: None, - })?; - - let tx = match tx_ids_response { - zebra_state::ReadResponse::TransactionIdsForBlock(Some(tx_ids)) => { - tx_ids.iter().map(|tx_id| tx_id.encode_hex()).collect() - } - zebra_state::ReadResponse::TransactionIdsForBlock(None) => Err(Error { - code: MISSING_BLOCK_ERROR_CODE, - message: "Block not found".to_string(), - data: None, - })?, - _ => unreachable!("unmatched response to a transaction_ids_for_block request"), - }; - - let sapling_note_commitment_tree_count = match sapling_tree_response { - zebra_state::ReadResponse::SaplingTree(Some(nct)) => nct.count(), - zebra_state::ReadResponse::SaplingTree(None) => 0, - _ => unreachable!("unmatched response to a SaplingTree request"), - }; - - let confirmations = match depth_response { + let depth_response = futs.next().await.expect("`futs` should not be empty"); + let confirmations = match depth_response.map_server_error()? { // Confirmations are one more than the depth. // Depth is limited by height, so it will never overflow an i64. zebra_state::ReadResponse::Depth(Some(depth)) => i64::from(depth) + 1, @@ -897,14 +862,21 @@ where _ => unreachable!("unmatched response to a depth request"), }; - // TODO: look up the height if we only have a hash, - // this needs a new state request for the height -> hash index - let height = hash_or_height.height(); + let time = if should_read_block_header { + let block_header_response = + futs.next().await.expect("`futs` should not be empty"); - let orchard_note_commitment_tree_count = match orchard_tree_response { - zebra_state::ReadResponse::OrchardTree(Some(nct)) => nct.count(), - zebra_state::ReadResponse::OrchardTree(None) => 0, - _ => unreachable!("unmatched response to a OrchardTree request"), + match block_header_response.map_server_error()? { + zebra_state::ReadResponse::BlockHeader(header) => Some( + header + .ok_or_server_error("Block not found")? + .time + .timestamp(), + ), + _ => unreachable!("unmatched response to a BlockHeader request"), + } + } else { + None }; let sapling = SaplingTrees { @@ -921,6 +893,7 @@ where hash: GetBlockHash(hash), confirmations, height, + time, tx, trees, }) @@ -1639,6 +1612,10 @@ pub enum GetBlock { #[serde(skip_serializing_if = "Option::is_none")] height: Option, + /// The height of the requested block. + #[serde(skip_serializing_if = "Option::is_none")] + time: Option, + /// List of transaction IDs in block order, hex-encoded. // // TODO: use a typed Vec here @@ -1655,6 +1632,7 @@ impl Default for GetBlock { hash: GetBlockHash::default(), confirmations: 0, height: None, + time: None, tx: Vec::new(), trees: GetBlockTrees::default(), } diff --git a/zebra-rpc/src/methods/errors.rs b/zebra-rpc/src/methods/errors.rs new file mode 100644 index 000000000..be9231d05 --- /dev/null +++ b/zebra-rpc/src/methods/errors.rs @@ -0,0 +1,37 @@ +//! Error conversions for Zebra's RPC methods. + +use jsonrpc_core::ErrorCode; + +pub(crate) trait MapServerError { + fn map_server_error(self) -> std::result::Result; +} + +pub(crate) trait OkOrServerError { + fn ok_or_server_error( + self, + message: S, + ) -> std::result::Result; +} + +impl MapServerError for Result +where + E: ToString, +{ + fn map_server_error(self) -> Result { + self.map_err(|error| jsonrpc_core::Error { + code: ErrorCode::ServerError(0), + message: error.to_string(), + data: None, + }) + } +} + +impl OkOrServerError for Option { + fn ok_or_server_error(self, message: S) -> Result { + self.ok_or(jsonrpc_core::Error { + code: ErrorCode::ServerError(0), + message: message.to_string(), + data: None, + }) + } +} diff --git a/zebra-rpc/src/methods/get_block_template_rpcs.rs b/zebra-rpc/src/methods/get_block_template_rpcs.rs index 9dba00aa0..9ef9c581e 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs.rs @@ -7,14 +7,14 @@ use jsonrpc_core::{self, BoxFuture, Error, ErrorCode, Result}; use jsonrpc_derive::rpc; use tower::{Service, ServiceExt}; -use zcash_address::{self, unified::Encoding, TryFromAddress}; +use zcash_address::{unified::Encoding, TryFromAddress}; use zebra_chain::{ amount::Amount, block::{self, Block, Height, TryIntoHeight}, chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, - parameters::{Network, POW_AVERAGING_WINDOW}, + parameters::{Network, NetworkKind, POW_AVERAGING_WINDOW}, primitives, serialization::ZcashDeserializeInto, transparent::{ @@ -449,13 +449,25 @@ where ) -> Self { // Prevent loss of miner funds due to an unsupported or incorrect address type. if let Some(miner_address) = mining_config.miner_address.clone() { - assert_eq!( - miner_address.network(), - network.clone(), - "incorrect miner address config: {miner_address} \ - network.network {network} and miner address network {} must match", - miner_address.network(), - ); + match network.kind() { + NetworkKind::Mainnet => assert_eq!( + miner_address.network_kind(), + NetworkKind::Mainnet, + "Incorrect config: Zebra is configured to run on a Mainnet network, \ + which implies the configured mining address needs to be for Mainnet, \ + but the provided address is for {}.", + miner_address.network_kind(), + ), + // `Regtest` uses `Testnet` transparent addresses. + network_kind @ (NetworkKind::Testnet | NetworkKind::Regtest) => assert_eq!( + miner_address.network_kind(), + NetworkKind::Testnet, + "Incorrect config: Zebra is configured to run on a {network_kind} network, \ + which implies the configured mining address needs to be for Testnet, \ + but the provided address is for {}.", + miner_address.network_kind(), + ), + } } // A limit on the configured extra coinbase data, regardless of the current block height. @@ -1084,7 +1096,7 @@ where return Ok(validate_address::Response::invalid()); } - if address.network() == network { + if address.network() == network.kind() { Ok(validate_address::Response { address: Some(raw_address), is_valid: true, @@ -1124,7 +1136,7 @@ where } }; - if address.network() == network { + if address.network() == network.kind() { Ok(z_validate_address::Response { is_valid: true, address: Some(raw_address), diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/types/long_poll.rs b/zebra-rpc/src/methods/get_block_template_rpcs/types/long_poll.rs index 9f9a31616..8817a8c12 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/types/long_poll.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/types/long_poll.rs @@ -227,9 +227,8 @@ fn update_checksum(checksum: &mut u32, item: [u8; 32]) { } } -impl ToString for LongPollId { - /// Exact conversion from LongPollId to a string. - fn to_string(&self) -> String { +impl std::fmt::Display for LongPollId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let LongPollId { tip_height, tip_hash_checksum, @@ -240,7 +239,8 @@ impl ToString for LongPollId { // We can't do this using `serde`, because it names each field, // but we want a single string containing all the fields. - format!( + write!( + f, // Height as decimal, padded with zeroes to the width of Height::MAX // Checksums as hex, padded with zeroes to the width of u32::MAX // Timestamp as decimal, padded with zeroes to the width of u32::MAX diff --git a/zebra-rpc/src/methods/tests/snapshot.rs b/zebra-rpc/src/methods/tests/snapshot.rs index 94e12cc80..b97880532 100644 --- a/zebra-rpc/src/methods/tests/snapshot.rs +++ b/zebra-rpc/src/methods/tests/snapshot.rs @@ -2,20 +2,17 @@ //! //! To update these snapshots, run: //! ```sh -//! cargo insta test --review +//! cargo insta test --review -p zebra-rpc --lib -- test_rpc_response_data //! ``` -use std::{collections::BTreeMap, sync::Arc}; +use std::collections::BTreeMap; use insta::dynamic_redaction; use tower::buffer::Buffer; use zebra_chain::{ - block::Block, - chain_tip::mock::MockChainTip, - parameters::Network::{Mainnet, Testnet}, - serialization::ZcashDeserializeInto, - subtree::NoteCommitmentSubtreeData, + block::Block, chain_tip::mock::MockChainTip, parameters::Network::Mainnet, + serialization::ZcashDeserializeInto, subtree::NoteCommitmentSubtreeData, }; use zebra_state::{ReadRequest, ReadResponse, MAX_ON_DISK_HEIGHT}; use zebra_test::mock_service::MockService; @@ -33,12 +30,13 @@ pub const EXCESSIVE_BLOCK_HEIGHT: u32 = MAX_ON_DISK_HEIGHT.0 + 1; #[tokio::test(flavor = "multi_thread")] async fn test_rpc_response_data() { let _init_guard = zebra_test::init(); + let default_testnet = Network::new_default_testnet(); tokio::join!( test_rpc_response_data_for_network(&Mainnet), - test_rpc_response_data_for_network(&Testnet), + test_rpc_response_data_for_network(&default_testnet), test_mocked_rpc_response_data_for_network(&Mainnet), - test_mocked_rpc_response_data_for_network(&Testnet), + test_mocked_rpc_response_data_for_network(&default_testnet), ); } @@ -167,6 +165,25 @@ async fn test_rpc_response_data_for_network(network: &Network) { .expect("We should have a GetBlock struct"); snapshot_rpc_getblock_verbose("hash_verbosity_1", get_block, &settings); + // `getblock`, verbosity=2, height + let get_block = rpc + .get_block(BLOCK_HEIGHT.to_string(), Some(2u8)) + .await + .expect("We should have a GetBlock struct"); + snapshot_rpc_getblock_verbose("height_verbosity_2", get_block, &settings); + + let get_block = rpc + .get_block(EXCESSIVE_BLOCK_HEIGHT.to_string(), Some(2u8)) + .await; + snapshot_rpc_getblock_invalid("excessive_height_verbosity_2", get_block, &settings); + + // `getblock`, verbosity=2, hash + let get_block = rpc + .get_block(block_hash.to_string(), Some(2u8)) + .await + .expect("We should have a GetBlock struct"); + snapshot_rpc_getblock_verbose("hash_verbosity_2", get_block, &settings); + // `getblock`, no verbosity - defaults to 1, height let get_block = rpc .get_block(BLOCK_HEIGHT.to_string(), None) diff --git a/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs b/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs index 3c2da6573..cc7d0b908 100644 --- a/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/tests/snapshot/get_block_template_rpcs.rs @@ -94,7 +94,10 @@ pub async fn test_responses( #[allow(clippy::unnecessary_struct_initialization)] let mining_config = crate::config::mining::Config { - miner_address: Some(transparent::Address::from_script_hash(network, [0xad; 20])), + miner_address: Some(transparent::Address::from_script_hash( + network.kind(), + [0xad; 20], + )), extra_coinbase_data: None, debug_like_zcashd: true, // TODO: Use default field values when optional features are enabled in tests #8183 diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_invalid_excessive_height_verbosity_2@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_invalid_excessive_height_verbosity_2@mainnet_10.snap new file mode 100644 index 000000000..5c2e6892a --- /dev/null +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_invalid_excessive_height_verbosity_2@mainnet_10.snap @@ -0,0 +1,10 @@ +--- +source: zebra-rpc/src/methods/tests/snapshot.rs +expression: response +--- +{ + "Err": { + "code": -8, + "message": "block height not in best chain" + } +} diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_invalid_excessive_height_verbosity_2@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_invalid_excessive_height_verbosity_2@testnet_10.snap new file mode 100644 index 000000000..5c2e6892a --- /dev/null +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_invalid_excessive_height_verbosity_2@testnet_10.snap @@ -0,0 +1,10 @@ +--- +source: zebra-rpc/src/methods/tests/snapshot.rs +expression: response +--- +{ + "Err": { + "code": -8, + "message": "block height not in best chain" + } +} diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_hash_verbosity_2@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_hash_verbosity_2@mainnet_10.snap new file mode 100644 index 000000000..3bcf968be --- /dev/null +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_hash_verbosity_2@mainnet_10.snap @@ -0,0 +1,13 @@ +--- +source: zebra-rpc/src/methods/tests/snapshot.rs +expression: block +--- +{ + "hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283", + "confirmations": 10, + "time": 1477671596, + "tx": [ + "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609" + ], + "trees": {} +} diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_hash_verbosity_2@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_hash_verbosity_2@testnet_10.snap new file mode 100644 index 000000000..7ea021d33 --- /dev/null +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_hash_verbosity_2@testnet_10.snap @@ -0,0 +1,13 @@ +--- +source: zebra-rpc/src/methods/tests/snapshot.rs +expression: block +--- +{ + "hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23", + "confirmations": 10, + "time": 1477674473, + "tx": [ + "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75" + ], + "trees": {} +} diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_height_verbosity_2@mainnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_height_verbosity_2@mainnet_10.snap new file mode 100644 index 000000000..f18b879f6 --- /dev/null +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_height_verbosity_2@mainnet_10.snap @@ -0,0 +1,14 @@ +--- +source: zebra-rpc/src/methods/tests/snapshot.rs +expression: block +--- +{ + "hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283", + "confirmations": 10, + "height": 1, + "time": 1477671596, + "tx": [ + "851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609" + ], + "trees": {} +} diff --git a/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_height_verbosity_2@testnet_10.snap b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_height_verbosity_2@testnet_10.snap new file mode 100644 index 000000000..013a4c09b --- /dev/null +++ b/zebra-rpc/src/methods/tests/snapshots/get_block_verbose_height_verbosity_2@testnet_10.snap @@ -0,0 +1,14 @@ +--- +source: zebra-rpc/src/methods/tests/snapshot.rs +expression: block +--- +{ + "hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23", + "confirmations": 10, + "height": 1, + "time": 1477674473, + "tx": [ + "f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75" + ], + "trees": {} +} diff --git a/zebra-rpc/src/methods/tests/vectors.rs b/zebra-rpc/src/methods/tests/vectors.rs index 28ca7b198..fe80a8dd2 100644 --- a/zebra-rpc/src/methods/tests/vectors.rs +++ b/zebra-rpc/src/methods/tests/vectors.rs @@ -1,8 +1,7 @@ //! Fixed test vectors for RPC methods. -use std::{ops::RangeInclusive, sync::Arc}; +use std::ops::RangeInclusive; -use jsonrpc_core::ErrorCode; use tower::buffer::Buffer; use zebra_chain::{ @@ -11,8 +10,7 @@ use zebra_chain::{ chain_tip::{mock::MockChainTip, NoChainTip}, parameters::Network::*, serialization::{ZcashDeserializeInto, ZcashSerialize}, - transaction::{UnminedTx, UnminedTxId}, - transparent, + transaction::UnminedTxId, }; use zebra_node_services::BoxError; @@ -140,6 +138,7 @@ async fn rpc_getblock() { hash: GetBlockHash(block.hash()), confirmations: (blocks.len() - i).try_into().expect("valid i64"), height: Some(Height(i.try_into().expect("valid u32"))), + time: None, tx: block .transactions .iter() @@ -163,6 +162,55 @@ async fn rpc_getblock() { hash: GetBlockHash(block.hash()), confirmations: (blocks.len() - i).try_into().expect("valid i64"), height: None, + time: None, + tx: block + .transactions + .iter() + .map(|tx| tx.hash().encode_hex()) + .collect(), + trees, + } + ); + } + + // Make height calls with verbosity=2 and check response + for (i, block) in blocks.iter().enumerate() { + let get_block = rpc + .get_block(i.to_string(), Some(2u8)) + .await + .expect("We should have a GetBlock struct"); + + assert_eq!( + get_block, + GetBlock::Object { + hash: GetBlockHash(block.hash()), + confirmations: (blocks.len() - i).try_into().expect("valid i64"), + height: Some(Height(i.try_into().expect("valid u32"))), + time: Some(block.header.time.timestamp()), + tx: block + .transactions + .iter() + .map(|tx| tx.hash().encode_hex()) + .collect(), + trees, + } + ); + } + + // Make hash calls with verbosity=2 and check response + for (i, block) in blocks.iter().enumerate() { + let get_block = rpc + .get_block(blocks[i].hash().to_string(), Some(2u8)) + .await + .expect("We should have a GetBlock struct"); + + assert_eq!( + get_block, + GetBlock::Object { + hash: GetBlockHash(block.hash()), + confirmations: (blocks.len() - i).try_into().expect("valid i64"), + height: None, + time: Some(block.header.time.timestamp()), tx: block .transactions .iter() @@ -186,6 +234,7 @@ async fn rpc_getblock() { hash: GetBlockHash(block.hash()), confirmations: (blocks.len() - i).try_into().expect("valid i64"), height: Some(Height(i.try_into().expect("valid u32"))), + time: None, tx: block .transactions .iter() @@ -209,6 +258,7 @@ async fn rpc_getblock() { hash: GetBlockHash(block.hash()), confirmations: (blocks.len() - i).try_into().expect("valid i64"), height: None, + time: None, tx: block .transactions .iter() @@ -654,7 +704,7 @@ async fn rpc_getaddresstxids_invalid_arguments() { async fn rpc_getaddresstxids_response() { let _init_guard = zebra_test::init(); - for network in [Mainnet, Testnet] { + for network in Network::iter() { let blocks: Vec> = network .blockchain_map() .iter() @@ -1193,6 +1243,7 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) { amount::NonNegative, block::{Hash, MAX_BLOCK_BYTES, ZCASH_BLOCK_VERSION}, chain_sync_status::MockSyncStatus, + parameters::NetworkKind, serialization::DateTime32, transaction::{zip317, VerifiedUnminedTx}, work::difficulty::{CompactDifficulty, ExpandedDifficulty, U256}, @@ -1223,11 +1274,10 @@ async fn rpc_getblocktemplate_mining_address(use_p2pkh: bool) { let mut mock_sync_status = MockSyncStatus::default(); mock_sync_status.set_is_close_to_tip(true); + let network = NetworkKind::Mainnet; let miner_address = match use_p2pkh { - false => Some(transparent::Address::from_script_hash(&Mainnet, [0x7e; 20])), - true => Some(transparent::Address::from_pub_key_hash( - &Mainnet, [0x7e; 20], - )), + false => Some(transparent::Address::from_script_hash(network, [0x7e; 20])), + true => Some(transparent::Address::from_pub_key_hash(network, [0x7e; 20])), }; #[allow(clippy::unnecessary_struct_initialization)] diff --git a/zebra-rpc/src/server.rs b/zebra-rpc/src/server.rs index c16ddd2a7..f440d7132 100644 --- a/zebra-rpc/src/server.rs +++ b/zebra-rpc/src/server.rs @@ -13,7 +13,7 @@ use jsonrpc_core::{Compatibility, MetaIoHandler}; use jsonrpc_http_server::{CloseHandle, ServerBuilder}; use tokio::task::JoinHandle; use tower::Service; -use tracing::{Instrument, *}; +use tracing::*; use zebra_chain::{ block, chain_sync_status::ChainSyncStatus, chain_tip::ChainTip, parameters::Network, diff --git a/zebra-scan/Cargo.toml b/zebra-scan/Cargo.toml index b9883398d..cadaeb6d9 100644 --- a/zebra-scan/Cargo.toml +++ b/zebra-scan/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-scan" -version = "0.1.0-alpha.4" +version = "0.1.0-alpha.5" authors = ["Zcash Foundation "] description = "Shielded transaction scanner for the Zcash blockchain" license = "MIT OR Apache-2.0" @@ -42,11 +42,11 @@ proptest-impl = [ [dependencies] color-eyre = "0.6.3" -indexmap = { version = "2.2.5", features = ["serde"] } +indexmap = { version = "2.2.6", features = ["serde"] } itertools = "0.12.1" semver = "1.0.22" serde = { version = "1.0.196", features = ["serde_derive"] } -tokio = { version = "1.36.0", features = ["time"] } +tokio = { version = "1.37.0", features = ["time"] } tower = "0.4.13" tracing = "0.1.39" futures = "0.3.30" @@ -54,10 +54,10 @@ futures = "0.3.30" zcash_client_backend = "0.10.0-rc.1" zcash_primitives = "0.13.0" -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["shielded-scan"] } -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35", features = ["shielded-scan"] } -zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.35", features = ["shielded-scan"] } -zebra-grpc = { path = "../zebra-grpc", version = "0.1.0-alpha.2" } +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"] } +zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36", features = ["shielded-scan"] } +zebra-grpc = { path = "../zebra-grpc", version = "0.1.0-alpha.3" } chrono = { version = "0.4.34", default-features = false, features = ["clock", "std", "serde"] } @@ -72,11 +72,11 @@ jubjub = { version = "0.10.0", optional = true } rand = { version = "0.8.5", optional = true } zcash_note_encryption = { version = "0.4.0", optional = true } -zebra-test = { path = "../zebra-test", version = "1.0.0-beta.35", optional = true } +zebra-test = { path = "../zebra-test", version = "1.0.0-beta.36", optional = true } [dev-dependencies] -insta = { version = "1.36.1", features = ["ron", "redactions"] } -tokio = { version = "1.36.0", features = ["test-util"] } +insta = { version = "1.38.0", features = ["ron", "redactions"] } +tokio = { version = "1.37.0", features = ["test-util"] } proptest = "1.4.0" proptest-derive = "0.4.0" @@ -87,5 +87,5 @@ jubjub = "0.10.0" rand = "0.8.5" zcash_note_encryption = "0.4.0" -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-test = { path = "../zebra-test", version = "1.0.0-beta.35" } +zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-test = { path = "../zebra-test", version = "1.0.0-beta.36" } diff --git a/zebra-scan/src/service/scan_task/scan.rs b/zebra-scan/src/service/scan_task/scan.rs index b1207ff09..12bbb86a1 100644 --- a/zebra-scan/src/service/scan_task/scan.rs +++ b/zebra-scan/src/service/scan_task/scan.rs @@ -384,8 +384,6 @@ pub fn scan_block( // TODO: Implement a check that returns early when the block height is below the Sapling // activation height. - let network: zcash_primitives::consensus::Network = network.into(); - let chain_metadata = ChainMetadata { sapling_commitment_tree_size: sapling_tree_size, // Orchard is not supported at the moment so the tree size can be 0. @@ -400,7 +398,7 @@ pub fn scan_block( .collect(); zcash_client_backend::scanning::scan_block( - &network, + network, block_to_compact(block, chain_metadata), scanning_keys.as_slice(), // Ignore whether notes are change from a viewer's own spends for now. diff --git a/zebra-scan/src/storage/db/tests/snapshot.rs b/zebra-scan/src/storage/db/tests/snapshot.rs index 81dc1a711..93f376785 100644 --- a/zebra-scan/src/storage/db/tests/snapshot.rs +++ b/zebra-scan/src/storage/db/tests/snapshot.rs @@ -28,10 +28,7 @@ use std::collections::BTreeMap; use itertools::Itertools; -use zebra_chain::{ - block::Height, - parameters::Network::{self, *}, -}; +use zebra_chain::{block::Height, parameters::Network}; use zebra_state::{RawBytes, ReadDisk, SaplingScannedDatabaseIndex, TransactionLocation, KV}; use crate::storage::{db::ScannerDb, Storage}; @@ -45,8 +42,9 @@ use crate::storage::{db::ScannerDb, Storage}; fn test_database_format() { let _init_guard = zebra_test::init(); - test_database_format_with_network(Mainnet); - test_database_format_with_network(Testnet); + for network in Network::iter() { + test_database_format_with_network(network); + } } /// Snapshot raw and typed database formats for `network`. diff --git a/zebra-script/Cargo.toml b/zebra-script/Cargo.toml index d62a38521..8edeb3239 100644 --- a/zebra-script/Cargo.toml +++ b/zebra-script/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-script" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "Zebra script verification wrapping zcashd's zcash_script library" license = "MIT OR Apache-2.0" @@ -18,7 +18,7 @@ categories = ["api-bindings", "cryptography::cryptocurrencies"] #zcash_script = "0.1.14" zcash_script = { git = "https://github.com/ZcashFoundation/zcash_script", branch = "bump_v0.1.15" } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35" } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36" } thiserror = "1.0.58" displaydoc = "0.2.4" @@ -26,4 +26,4 @@ displaydoc = "0.2.4" [dev-dependencies] hex = "0.4.3" lazy_static = "1.4.0" -zebra-test = { path = "../zebra-test", version = "1.0.0-beta.35" } +zebra-test = { path = "../zebra-test", version = "1.0.0-beta.36" } diff --git a/zebra-script/src/lib.rs b/zebra-script/src/lib.rs index 43ea2fa73..f34de6874 100644 --- a/zebra-script/src/lib.rs +++ b/zebra-script/src/lib.rs @@ -277,7 +277,6 @@ impl Drop for CachedFfiTransaction { #[cfg(test)] mod tests { use hex::FromHex; - use std::convert::TryInto; use std::sync::Arc; use zebra_chain::{ parameters::{ConsensusBranchId, NetworkUpgrade::*}, diff --git a/zebra-state/Cargo.toml b/zebra-state/Cargo.toml index e817d735a..e0e7046c8 100644 --- a/zebra-state/Cargo.toml +++ b/zebra-state/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-state" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "State contextual verification and storage code for Zebra" license = "MIT OR Apache-2.0" @@ -54,12 +54,12 @@ hex = "0.4.3" hex-literal = "0.4.1" humantime-serde = "1.1.1" human_bytes = { version = "0.4.3", default-features = false } -indexmap = "2.2.5" +indexmap = "2.2.6" itertools = "0.12.1" lazy_static = "1.4.0" metrics = "0.22.3" mset = "0.1.1" -regex = "1.10.3" +regex = "1.10.4" rlimit = "0.10.1" rocksdb = { version = "0.22.0", default-features = false, features = ["lz4"] } semver = "1.0.22" @@ -67,23 +67,23 @@ serde = { version = "1.0.196", features = ["serde_derive"] } tempfile = "3.10.1" thiserror = "1.0.58" -rayon = "1.9.0" -tokio = { version = "1.36.0", features = ["rt-multi-thread", "sync", "tracing"] } +rayon = "1.10.0" +tokio = { version = "1.37.0", features = ["rt-multi-thread", "sync", "tracing"] } tower = { version = "0.4.13", features = ["buffer", "util"] } 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.113", package = "serde_json", optional = true } +serde_json = { version = "1.0.115", package = "serde_json", optional = true } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["async-error"] } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["async-error"] } # prod feature progress-bar howudoin = { version = "0.1.2", optional = true } # test feature proptest-impl -zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.35", optional = true } +zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.36", optional = true } proptest = { version = "1.4.0", optional = true } proptest-derive = { version = "0.4.0", optional = true } @@ -97,7 +97,7 @@ once_cell = "1.18.0" spandoc = "0.2.2" hex = { version = "0.4.3", features = ["serde"] } -insta = { version = "1.36.1", features = ["ron", "redactions"] } +insta = { version = "1.38.0", features = ["ron", "redactions"] } proptest = "1.4.0" proptest-derive = "0.4.0" @@ -106,7 +106,7 @@ rand = "0.8.5" halo2 = { package = "halo2_proofs", version = "0.3.0" } jubjub = "0.10.0" -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.35" } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-test = { path = "../zebra-test/", version = "1.0.0-beta.36" } diff --git a/zebra-state/src/request.rs b/zebra-state/src/request.rs index 2a6b3b1a5..6f785a9d2 100644 --- a/zebra-state/src/request.rs +++ b/zebra-state/src/request.rs @@ -614,6 +614,16 @@ pub enum Request { /// [`block::Height`] using `.into()`. Block(HashOrHeight), + /// Looks up a block header by hash or height in the current best chain. + /// + /// Returns + /// + /// [`Response::BlockHeader(block::Header)`](Response::BlockHeader). + /// + /// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or + /// [`block::Height`] using `.into()`. + BlockHeader(HashOrHeight), + /// Request a UTXO identified by the given [`OutPoint`](transparent::OutPoint), /// waiting until it becomes available if it is unknown. /// @@ -725,6 +735,7 @@ impl Request { Request::Transaction(_) => "transaction", Request::UnspentBestChainUtxo { .. } => "unspent_best_chain_utxo", Request::Block(_) => "block", + Request::BlockHeader(_) => "block_header", Request::FindBlockHashes { .. } => "find_block_hashes", Request::FindBlockHeaders { .. } => "find_block_headers", Request::CheckBestChainTipNullifiersAndAnchors(_) => { @@ -776,6 +787,16 @@ pub enum ReadRequest { /// [`block::Height`] using `.into()`. Block(HashOrHeight), + /// Looks up a block header by hash or height in the current best chain. + /// + /// Returns + /// + /// [`Response::BlockHeader(block::Header)`](Response::BlockHeader). + /// + /// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or + /// [`block::Height`] using `.into()`. + BlockHeader(HashOrHeight), + /// Looks up a transaction by hash in the current best chain. /// /// Returns @@ -999,6 +1020,7 @@ impl ReadRequest { ReadRequest::Tip => "tip", ReadRequest::Depth(_) => "depth", ReadRequest::Block(_) => "block", + ReadRequest::BlockHeader(_) => "block_header", ReadRequest::Transaction(_) => "transaction", ReadRequest::TransactionIdsForBlock(_) => "transaction_ids_for_block", ReadRequest::UnspentBestChainUtxo { .. } => "unspent_best_chain_utxo", @@ -1052,6 +1074,7 @@ impl TryFrom for ReadRequest { Request::BestChainBlockHash(hash) => Ok(ReadRequest::BestChainBlockHash(hash)), Request::Block(hash_or_height) => Ok(ReadRequest::Block(hash_or_height)), + Request::BlockHeader(hash_or_height) => Ok(ReadRequest::BlockHeader(hash_or_height)), Request::Transaction(tx_hash) => Ok(ReadRequest::Transaction(tx_hash)), Request::UnspentBestChainUtxo(outpoint) => { Ok(ReadRequest::UnspentBestChainUtxo(outpoint)) diff --git a/zebra-state/src/response.rs b/zebra-state/src/response.rs index ad75287d8..242191f82 100644 --- a/zebra-state/src/response.rs +++ b/zebra-state/src/response.rs @@ -50,6 +50,9 @@ pub enum Response { /// Response to [`Request::Block`] with the specified block. Block(Option>), + /// The response to a `BlockHeader` request. + BlockHeader(Option>), + /// The response to a `AwaitUtxo` request, from any non-finalized chains, finalized chain, /// pending unverified blocks, or blocks received after the request was sent. Utxo(transparent::Utxo), @@ -131,6 +134,9 @@ pub enum ReadResponse { /// Response to [`ReadRequest::Block`] with the specified block. Block(Option>), + /// The response to a `BlockHeader` request. + BlockHeader(Option>), + /// Response to [`ReadRequest::Transaction`] with the specified transaction. Transaction(Option), @@ -265,6 +271,7 @@ impl TryFrom for Response { ReadResponse::BlockHash(hash) => Ok(Response::BlockHash(hash)), ReadResponse::Block(block) => Ok(Response::Block(block)), + ReadResponse::BlockHeader(header) => Ok(Response::BlockHeader(header)), ReadResponse::Transaction(tx_info) => { Ok(Response::Transaction(tx_info.map(|tx_info| tx_info.tx))) } diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index bd0abe867..203c1d34c 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -1120,6 +1120,7 @@ impl Service for StateService { | Request::Transaction(_) | Request::UnspentBestChainUtxo(_) | Request::Block(_) + | Request::BlockHeader(_) | Request::FindBlockHashes { .. } | Request::FindBlockHeaders { .. } | Request::CheckBestChainTipNullifiersAndAnchors(_) => { @@ -1288,6 +1289,31 @@ impl Service for ReadStateService { .wait_for_panics() } + // Used by the get_block (verbose) RPC and the StateService. + ReadRequest::BlockHeader(hash_or_height) => { + let state = self.clone(); + + tokio::task::spawn_blocking(move || { + span.in_scope(move || { + let header = state.non_finalized_state_receiver.with_watch_data( + |non_finalized_state| { + read::block_header( + non_finalized_state.best_chain(), + &state.db, + hash_or_height, + ) + }, + ); + + // The work is done in the future. + timer.finish(module_path!(), line!(), "ReadRequest::Block"); + + Ok(ReadResponse::BlockHeader(header)) + }) + }) + .wait_for_panics() + } + // For the get_raw_transaction RPC and the StateService. ReadRequest::Transaction(hash) => { let state = self.clone(); diff --git a/zebra-state/src/service/arbitrary.rs b/zebra-state/src/service/arbitrary.rs index 08eb42a83..308953ff0 100644 --- a/zebra-state/src/service/arbitrary.rs +++ b/zebra-state/src/service/arbitrary.rs @@ -89,13 +89,14 @@ impl PreparedChain { // The history tree only works with Heartwood onward. // Since the network will be chosen later, we pick the larger // between the mainnet and testnet Heartwood activation heights. - let main_height = NetworkUpgrade::Heartwood - .activation_height(&Network::Mainnet) - .expect("must have height"); - let test_height = NetworkUpgrade::Heartwood - .activation_height(&Network::Testnet) - .expect("must have height"); - let height = std::cmp::max(main_height, test_height); + let height = Network::iter() + .map(|network| { + NetworkUpgrade::Heartwood + .activation_height(&network) + .expect("must have height") + }) + .max() + .expect("Network::iter() must return non-empty iterator"); PreparedChain { ledger_strategy: Some(LedgerState::height_strategy( diff --git a/zebra-state/src/service/check/difficulty.rs b/zebra-state/src/service/check/difficulty.rs index 3f6cd9e96..8c48e25fb 100644 --- a/zebra-state/src/service/check/difficulty.rs +++ b/zebra-state/src/service/check/difficulty.rs @@ -5,7 +5,7 @@ //! * the Testnet minimum difficulty adjustment from ZIPs 205 and 208, and //! * `median-time-past`. -use std::{cmp::max, cmp::min, convert::TryInto}; +use std::{cmp::max, cmp::min}; use chrono::{DateTime, Duration, Utc}; @@ -183,10 +183,9 @@ impl AdjustedDifficulty { self.candidate_time, self.relevant_times[0], ) { - assert_eq!( - self.network, - Network::Testnet, - "invalid network: the minimum difficulty rule only applies on testnet" + assert!( + self.network.is_a_test_network(), + "invalid network: the minimum difficulty rule only applies on test networks" ); self.network.target_difficulty_limit().to_compact() } else { diff --git a/zebra-state/src/service/check/tests/nullifier.rs b/zebra-state/src/service/check/tests/nullifier.rs index 1a944d017..0392f1c8e 100644 --- a/zebra-state/src/service/check/tests/nullifier.rs +++ b/zebra-state/src/service/check/tests/nullifier.rs @@ -1,6 +1,6 @@ //! Randomised property tests for nullifier contextual validation -use std::{convert::TryInto, env, sync::Arc}; +use std::{env, sync::Arc}; use itertools::Itertools; use proptest::prelude::*; diff --git a/zebra-state/src/service/check/tests/vectors.rs b/zebra-state/src/service/check/tests/vectors.rs index a93081e03..5cab1aa01 100644 --- a/zebra-state/src/service/check/tests/vectors.rs +++ b/zebra-state/src/service/check/tests/vectors.rs @@ -1,7 +1,5 @@ //! Fixed test vectors for state contextual validation checks. -use std::sync::Arc; - use zebra_chain::serialization::ZcashDeserializeInto; use super::super::*; diff --git a/zebra-state/src/service/finalized_state.rs b/zebra-state/src/service/finalized_state.rs index 41c76e640..7256d89da 100644 --- a/zebra-state/src/service/finalized_state.rs +++ b/zebra-state/src/service/finalized_state.rs @@ -502,6 +502,12 @@ impl FinalizedState { let network = self.network(); rt.block_on(async move { + // Send a ping to the server to check if it is available before inserting. + if client.ping().send().await.is_err() { + tracing::error!("Elasticsearch is not available, skipping block indexing"); + return; + } + let response = client .bulk(elasticsearch::BulkParts::Index( format!("zcash_{}", network.to_string().to_lowercase()).as_str(), diff --git a/zebra-state/src/service/finalized_state/disk_format/chain.rs b/zebra-state/src/service/finalized_state/disk_format/chain.rs index cf1cbe7dc..2f04b5369 100644 --- a/zebra-state/src/service/finalized_state/disk_format/chain.rs +++ b/zebra-state/src/service/finalized_state/disk_format/chain.rs @@ -10,8 +10,12 @@ use std::collections::BTreeMap; use bincode::Options; use zebra_chain::{ - amount::NonNegative, block::Height, history_tree::NonEmptyHistoryTree, parameters::Network, - primitives::zcash_history, value_balance::ValueBalance, + amount::NonNegative, + block::Height, + history_tree::{HistoryTreeError, NonEmptyHistoryTree}, + parameters::{Network, NetworkKind}, + primitives::zcash_history, + value_balance::ValueBalance, }; use crate::service::finalized_state::disk_format::{FromDisk, IntoDisk}; @@ -39,42 +43,54 @@ impl FromDisk for ValueBalance { // https://docs.rs/bincode/1.3.3/bincode/config/index.html#options-struct-vs-bincode-functions #[derive(serde::Serialize, serde::Deserialize)] -struct HistoryTreeParts { - network: Network, +pub struct HistoryTreeParts { + network_kind: NetworkKind, size: u32, peaks: BTreeMap, current_height: Height, } -impl IntoDisk for NonEmptyHistoryTree { +impl HistoryTreeParts { + /// Converts [`HistoryTreeParts`] to a [`NonEmptyHistoryTree`]. + pub(crate) fn with_network( + self, + network: &Network, + ) -> Result { + assert_eq!( + self.network_kind, + network.kind(), + "history tree network kind should match current network" + ); + + NonEmptyHistoryTree::from_cache(network, self.size, self.peaks, self.current_height) + } +} + +impl From<&NonEmptyHistoryTree> for HistoryTreeParts { + fn from(history_tree: &NonEmptyHistoryTree) -> Self { + HistoryTreeParts { + network_kind: history_tree.network().kind(), + size: history_tree.size(), + peaks: history_tree.peaks().clone(), + current_height: history_tree.current_height(), + } + } +} + +impl IntoDisk for HistoryTreeParts { type Bytes = Vec; fn as_bytes(&self) -> Self::Bytes { - let data = HistoryTreeParts { - network: self.network(), - size: self.size(), - peaks: self.peaks().clone(), - current_height: self.current_height(), - }; bincode::DefaultOptions::new() - .serialize(&data) + .serialize(self) .expect("serialization to vec doesn't fail") } } -impl FromDisk for NonEmptyHistoryTree { +impl FromDisk for HistoryTreeParts { fn from_bytes(bytes: impl AsRef<[u8]>) -> Self { - let parts: HistoryTreeParts = bincode::DefaultOptions::new() + bincode::DefaultOptions::new() .deserialize(bytes.as_ref()) - .expect( - "deserialization format should match the serialization format used by IntoDisk", - ); - NonEmptyHistoryTree::from_cache( - &parts.network, - parts.size, - parts.peaks, - parts.current_height, - ) - .expect("deserialization format should match the serialization format used by IntoDisk") + .expect("deserialization format should match the serialization format used by IntoDisk") } } diff --git a/zebra-state/src/service/finalized_state/disk_format/scan/tests/prop.rs b/zebra-state/src/service/finalized_state/disk_format/scan/tests/prop.rs index c770daecb..e4ceb59f6 100644 --- a/zebra-state/src/service/finalized_state/disk_format/scan/tests/prop.rs +++ b/zebra-state/src/service/finalized_state/disk_format/scan/tests/prop.rs @@ -1,6 +1,6 @@ //! Randomised proptests for scanner database formats. -use proptest::{arbitrary::any, prelude::*}; +use proptest::prelude::*; use crate::{ service::finalized_state::arbitrary::assert_value_properties, SaplingScannedDatabaseIndex, diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs b/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs index 5067bcfe7..3ef15c625 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs +++ b/zebra-state/src/service/finalized_state/disk_format/tests/prop.rs @@ -1,6 +1,6 @@ //! Randomised tests for the finalized disk format. -use proptest::{arbitrary::any, prelude::*}; +use proptest::prelude::*; use zebra_chain::{ amount::{Amount, NonNegative}, diff --git a/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs b/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs index 4605faf7d..14a8dd6c2 100644 --- a/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs +++ b/zebra-state/src/service/finalized_state/disk_format/tests/snapshot.rs @@ -29,11 +29,7 @@ use std::{collections::BTreeMap, sync::Arc}; -use zebra_chain::{ - block::Block, - parameters::Network::{self, *}, - serialization::ZcashDeserializeInto, -}; +use zebra_chain::{block::Block, parameters::Network, serialization::ZcashDeserializeInto}; use crate::{ service::finalized_state::{ @@ -50,9 +46,9 @@ use crate::{ #[test] fn test_raw_rocksdb_column_families() { let _init_guard = zebra_test::init(); - - test_raw_rocksdb_column_families_with_network(Mainnet); - test_raw_rocksdb_column_families_with_network(Testnet); + for network in Network::iter() { + test_raw_rocksdb_column_families_with_network(network); + } } /// Snapshot raw column families for `network`. diff --git a/zebra-state/src/service/finalized_state/disk_format/transparent.rs b/zebra-state/src/service/finalized_state/disk_format/transparent.rs index 89620cdae..b45c211bc 100644 --- a/zebra-state/src/service/finalized_state/disk_format/transparent.rs +++ b/zebra-state/src/service/finalized_state/disk_format/transparent.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use zebra_chain::{ amount::{self, Amount, NonNegative}, block::Height, - parameters::Network::*, + parameters::NetworkKind, serialization::{ZcashDeserializeInto, ZcashSerialize}, transparent::{self, Address::*}, }; @@ -498,14 +498,18 @@ impl AddressTransaction { /// Returns a byte representing the [`transparent::Address`] variant. fn address_variant(address: &transparent::Address) -> u8 { + use NetworkKind::*; // Return smaller values for more common variants. // // (This probably doesn't matter, but it might help slightly with data compression.) - match (address.network(), address) { + match (address.network_kind(), address) { (Mainnet, PayToPublicKeyHash { .. }) => 0, (Mainnet, PayToScriptHash { .. }) => 1, - (Testnet, PayToPublicKeyHash { .. }) => 2, - (Testnet, PayToScriptHash { .. }) => 3, + // There's no way to distinguish between Regtest and Testnet for encoded transparent addresses, + // we can consider `Regtest` to use `Testnet` transparent addresses, so it's okay to use the `Testnet` + // address variant for `Regtest` transparent addresses in the db format + (Testnet | Regtest, PayToPublicKeyHash { .. }) => 2, + (Testnet | Regtest, PayToScriptHash { .. }) => 3, } } @@ -529,15 +533,15 @@ impl FromDisk for transparent::Address { let hash_bytes = hash_bytes.try_into().unwrap(); let network = if address_variant < 2 { - Mainnet + NetworkKind::Mainnet } else { - Testnet + NetworkKind::Testnet }; if address_variant % 2 == 0 { - transparent::Address::from_pub_key_hash(&network, hash_bytes) + transparent::Address::from_pub_key_hash(network, hash_bytes) } else { - transparent::Address::from_script_hash(&network, hash_bytes) + transparent::Address::from_script_hash(network, hash_bytes) } } } diff --git a/zebra-state/src/service/finalized_state/zebra_db.rs b/zebra-state/src/service/finalized_state/zebra_db.rs index 71c619e4f..17891e38f 100644 --- a/zebra-state/src/service/finalized_state/zebra_db.rs +++ b/zebra-state/src/service/finalized_state/zebra_db.rs @@ -215,7 +215,7 @@ impl ZebraDb { /// Returns the configured network for this database. pub fn network(&self) -> Network { - self.db.network().clone() + self.db.network() } /// Returns the `Path` where the files used by this database are located. diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs index f91ea5843..dbd0e7c1d 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs @@ -37,7 +37,7 @@ use serde::Serialize; use zebra_chain::{ block::{self, Block, Height, SerializedBlock}, orchard, - parameters::Network::{self, *}, + parameters::Network, sapling, serialization::{ZcashDeserializeInto, ZcashSerialize}, transaction::{self, Transaction}, @@ -153,9 +153,9 @@ impl TransactionData { #[test] fn test_block_and_transaction_data() { let _init_guard = zebra_test::init(); - - test_block_and_transaction_data_with_network(Mainnet); - test_block_and_transaction_data_with_network(Testnet); + for network in Network::iter() { + test_block_and_transaction_data_with_network(network); + } } /// Snapshot finalized block and transaction data for `network`. @@ -318,7 +318,7 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { // Skip these checks for empty history trees. if let Some(history_tree_at_tip) = history_tree_at_tip.as_ref().as_ref() { assert_eq!(history_tree_at_tip.current_height(), max_height); - assert_eq!(history_tree_at_tip.network(), state.network()); + assert_eq!(history_tree_at_tip.network(), &state.network()); } } diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs b/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs index 136121db3..1b4f7db9a 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/vectors.rs @@ -43,7 +43,7 @@ fn test_block_db_round_trip() { .map(|(_height, block)| block.zcash_deserialize_into().unwrap()); test_block_db_round_trip_with(&Mainnet, mainnet_test_cases); - test_block_db_round_trip_with(&Testnet, testnet_test_cases); + test_block_db_round_trip_with(&Network::new_default_testnet(), testnet_test_cases); // It doesn't matter if these blocks are mainnet or testnet, // because there is no validation at this level of the database. diff --git a/zebra-state/src/service/finalized_state/zebra_db/chain.rs b/zebra-state/src/service/finalized_state/zebra_db/chain.rs index 842fc9453..93c65322d 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/chain.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/chain.rs @@ -18,17 +18,17 @@ use std::{ }; use zebra_chain::{ - amount::NonNegative, - block::Height, - history_tree::{HistoryTree, NonEmptyHistoryTree}, - transparent, + amount::NonNegative, block::Height, history_tree::HistoryTree, transparent, value_balance::ValueBalance, }; use crate::{ request::FinalizedBlock, service::finalized_state::{ - disk_db::DiskWriteBatch, disk_format::RawBytes, zebra_db::ZebraDb, TypedColumnFamily, + disk_db::DiskWriteBatch, + disk_format::{chain::HistoryTreeParts, RawBytes}, + zebra_db::ZebraDb, + TypedColumnFamily, }, BoxError, }; @@ -42,15 +42,15 @@ pub const HISTORY_TREE: &str = "history_tree"; /// /// This constant should be used so the compiler can detect incorrectly typed accesses to the /// column family. -pub type HistoryTreeCf<'cf> = TypedColumnFamily<'cf, (), NonEmptyHistoryTree>; +pub type HistoryTreePartsCf<'cf> = TypedColumnFamily<'cf, (), HistoryTreeParts>; /// The legacy (1.3.0 and earlier) type for reading history trees from the database. /// This type should not be used in new code. -pub type LegacyHistoryTreeCf<'cf> = TypedColumnFamily<'cf, Height, NonEmptyHistoryTree>; +pub type LegacyHistoryTreePartsCf<'cf> = TypedColumnFamily<'cf, Height, HistoryTreeParts>; /// A generic raw key type for reading history trees from the database, regardless of the database version. /// This type should not be used in new code. -pub type RawHistoryTreeCf<'cf> = TypedColumnFamily<'cf, RawBytes, NonEmptyHistoryTree>; +pub type RawHistoryTreePartsCf<'cf> = TypedColumnFamily<'cf, RawBytes, HistoryTreeParts>; /// The name of the chain value pools column family. /// @@ -67,22 +67,22 @@ impl ZebraDb { // Column family convenience methods /// Returns a typed handle to the `history_tree` column family. - pub(crate) fn history_tree_cf(&self) -> HistoryTreeCf { - HistoryTreeCf::new(&self.db, HISTORY_TREE) + pub(crate) fn history_tree_cf(&self) -> HistoryTreePartsCf { + HistoryTreePartsCf::new(&self.db, HISTORY_TREE) .expect("column family was created when database was created") } /// Returns a legacy typed handle to the `history_tree` column family. /// This should not be used in new code. - pub(crate) fn legacy_history_tree_cf(&self) -> LegacyHistoryTreeCf { - LegacyHistoryTreeCf::new(&self.db, HISTORY_TREE) + pub(crate) fn legacy_history_tree_cf(&self) -> LegacyHistoryTreePartsCf { + LegacyHistoryTreePartsCf::new(&self.db, HISTORY_TREE) .expect("column family was created when database was created") } /// Returns a generic raw key typed handle to the `history_tree` column family. /// This should not be used in new code. - pub(crate) fn raw_history_tree_cf(&self) -> RawHistoryTreeCf { - RawHistoryTreeCf::new(&self.db, HISTORY_TREE) + pub(crate) fn raw_history_tree_cf(&self) -> RawHistoryTreePartsCf { + RawHistoryTreePartsCf::new(&self.db, HISTORY_TREE) .expect("column family was created when database was created") } @@ -115,19 +115,24 @@ impl ZebraDb { // // So we use the empty key `()`. Since the key has a constant value, we will always read // the latest tree. - let mut history_tree = history_tree_cf.zs_get(&()); + let mut history_tree_parts = history_tree_cf.zs_get(&()); - if history_tree.is_none() { + if history_tree_parts.is_none() { let legacy_history_tree_cf = self.legacy_history_tree_cf(); // In Zebra 1.4.0 and later, we only update the history tip tree when it has changed (for every block after heartwood). // But we write with a `()` key, not a height key. // So we need to look for the most recent update height if the `()` key has never been written. - history_tree = legacy_history_tree_cf + history_tree_parts = legacy_history_tree_cf .zs_last_key_value() .map(|(_height_key, tree_value)| tree_value); } + let history_tree = history_tree_parts.map(|parts| { + parts.with_network(&self.db.network()).expect( + "deserialization format should match the serialization format used by IntoDisk", + ) + }); Arc::new(HistoryTree::from(history_tree)) } @@ -139,7 +144,12 @@ impl ZebraDb { raw_history_tree_cf .zs_forward_range_iter(..) - .map(|(raw_key, history_tree)| (raw_key, Arc::new(HistoryTree::from(history_tree)))) + .map(|(raw_key, history_tree_parts)| { + let history_tree = history_tree_parts.with_network(&self.db.network()).expect( + "deserialization format should match the serialization format used by IntoDisk", + ); + (raw_key, Arc::new(HistoryTree::from(history_tree))) + }) .collect() } @@ -164,9 +174,9 @@ impl DiskWriteBatch { pub fn update_history_tree(&mut self, db: &ZebraDb, tree: &HistoryTree) { let history_tree_cf = db.history_tree_cf().with_batch_for_writing(self); - if let Some(tree) = tree.as_ref().as_ref() { + if let Some(tree) = tree.as_ref() { // The batch is modified by this method and written by the caller. - let _ = history_tree_cf.zs_insert(&(), tree); + let _ = history_tree_cf.zs_insert(&(), &HistoryTreeParts::from(tree)); } } diff --git a/zebra-state/src/service/non_finalized_state/chain.rs b/zebra-state/src/service/non_finalized_state/chain.rs index 07d287074..45bbb0268 100644 --- a/zebra-state/src/service/non_finalized_state/chain.rs +++ b/zebra-state/src/service/non_finalized_state/chain.rs @@ -636,13 +636,11 @@ impl Chain { .next() .expect("Zebra should never reach the max height in normal operation."); - if self.sprout_trees_by_height.get(&next_height).is_none() { - // TODO: Use `try_insert` once it stabilises. - self.sprout_trees_by_height.insert( - next_height, - highest_removed_tree.expect("There should be a cached removed tree."), - ); - } + self.sprout_trees_by_height + .entry(next_height) + .or_insert_with(|| { + highest_removed_tree.expect("There should be a cached removed tree.") + }); } } @@ -839,13 +837,11 @@ impl Chain { .next() .expect("Zebra should never reach the max height in normal operation."); - if self.sapling_trees_by_height.get(&next_height).is_none() { - // TODO: Use `try_insert` once it stabilises. - self.sapling_trees_by_height.insert( - next_height, - highest_removed_tree.expect("There should be a cached removed tree."), - ); - } + self.sapling_trees_by_height + .entry(next_height) + .or_insert_with(|| { + highest_removed_tree.expect("There should be a cached removed tree.") + }); } } @@ -1048,13 +1044,11 @@ impl Chain { .next() .expect("Zebra should never reach the max height in normal operation."); - if self.orchard_trees_by_height.get(&next_height).is_none() { - // TODO: Use `try_insert` once it stabilises. - self.orchard_trees_by_height.insert( - next_height, - highest_removed_tree.expect("There should be a cached removed tree."), - ); - } + self.orchard_trees_by_height + .entry(next_height) + .or_insert_with(|| { + highest_removed_tree.expect("There should be a cached removed tree.") + }); } } diff --git a/zebra-state/src/service/non_finalized_state/tests/prop.rs b/zebra-state/src/service/non_finalized_state/tests/prop.rs index fab4a127c..d4ef55344 100644 --- a/zebra-state/src/service/non_finalized_state/tests/prop.rs +++ b/zebra-state/src/service/non_finalized_state/tests/prop.rs @@ -10,7 +10,7 @@ use zebra_chain::{ fmt::DisplayToDebug, history_tree::{HistoryTree, NonEmptyHistoryTree}, parameters::NetworkUpgrade::*, - parameters::{Network, *}, + parameters::*, value_balance::ValueBalance, LedgerState, }; @@ -612,15 +612,15 @@ fn different_blocks_different_chains() -> Result<()> { // blocks, heights, hashes chain1.blocks = chain2.blocks.clone(); - chain1.height_by_hash = chain2.height_by_hash.clone(); - chain1.tx_loc_by_hash = chain2.tx_loc_by_hash.clone(); + chain1.height_by_hash.clone_from(&chain2.height_by_hash); + chain1.tx_loc_by_hash.clone_from(&chain2.tx_loc_by_hash); // transparent UTXOs - chain1.created_utxos = chain2.created_utxos.clone(); - chain1.spent_utxos = chain2.spent_utxos.clone(); + chain1.created_utxos.clone_from(&chain2.created_utxos); + chain1.spent_utxos.clone_from(&chain2.spent_utxos); // note commitment trees - chain1.sprout_trees_by_anchor = chain2.sprout_trees_by_anchor.clone(); + chain1.sprout_trees_by_anchor.clone_from(&chain2.sprout_trees_by_anchor); chain1.sprout_trees_by_height = chain2.sprout_trees_by_height.clone(); chain1.sapling_trees_by_height = chain2.sapling_trees_by_height.clone(); chain1.orchard_trees_by_height = chain2.orchard_trees_by_height.clone(); @@ -641,9 +641,9 @@ fn different_blocks_different_chains() -> Result<()> { chain1.orchard_anchors_by_height = chain2.orchard_anchors_by_height.clone(); // nullifiers - chain1.sprout_nullifiers = chain2.sprout_nullifiers.clone(); - chain1.sapling_nullifiers = chain2.sapling_nullifiers.clone(); - chain1.orchard_nullifiers = chain2.orchard_nullifiers.clone(); + chain1.sprout_nullifiers.clone_from(&chain2.sprout_nullifiers); + chain1.sapling_nullifiers.clone_from(&chain2.sapling_nullifiers); + chain1.orchard_nullifiers.clone_from(&chain2.orchard_nullifiers); // proof of work chain1.partial_cumulative_work = chain2.partial_cumulative_work; diff --git a/zebra-state/src/service/non_finalized_state/tests/vectors.rs b/zebra-state/src/service/non_finalized_state/tests/vectors.rs index 00159e4c9..6f908f080 100644 --- a/zebra-state/src/service/non_finalized_state/tests/vectors.rs +++ b/zebra-state/src/service/non_finalized_state/tests/vectors.rs @@ -134,8 +134,9 @@ fn ord_matches_work() -> Result<()> { fn best_chain_wins() -> Result<()> { let _init_guard = zebra_test::init(); - best_chain_wins_for_network(Network::Mainnet)?; - best_chain_wins_for_network(Network::Testnet)?; + for network in Network::iter() { + best_chain_wins_for_network(network)?; + } Ok(()) } @@ -172,8 +173,9 @@ fn best_chain_wins_for_network(network: Network) -> Result<()> { fn finalize_pops_from_best_chain() -> Result<()> { let _init_guard = zebra_test::init(); - finalize_pops_from_best_chain_for_network(Network::Mainnet)?; - finalize_pops_from_best_chain_for_network(Network::Testnet)?; + for network in Network::iter() { + finalize_pops_from_best_chain_for_network(network)?; + } Ok(()) } @@ -219,8 +221,9 @@ fn finalize_pops_from_best_chain_for_network(network: Network) -> Result<()> { fn commit_block_extending_best_chain_doesnt_drop_worst_chains() -> Result<()> { let _init_guard = zebra_test::init(); - commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network(Network::Mainnet)?; - commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network(Network::Testnet)?; + for network in Network::iter() { + commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network(network)?; + } Ok(()) } @@ -264,10 +267,9 @@ fn commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network( #[test] fn shorter_chain_can_be_best_chain() -> Result<()> { let _init_guard = zebra_test::init(); - - shorter_chain_can_be_best_chain_for_network(Network::Mainnet)?; - shorter_chain_can_be_best_chain_for_network(Network::Testnet)?; - + for network in Network::iter() { + shorter_chain_can_be_best_chain_for_network(network)?; + } Ok(()) } @@ -307,9 +309,9 @@ fn shorter_chain_can_be_best_chain_for_network(network: Network) -> Result<()> { #[test] fn longer_chain_with_more_work_wins() -> Result<()> { let _init_guard = zebra_test::init(); - - longer_chain_with_more_work_wins_for_network(Network::Mainnet)?; - longer_chain_with_more_work_wins_for_network(Network::Testnet)?; + for network in Network::iter() { + longer_chain_with_more_work_wins_for_network(network)?; + } Ok(()) } @@ -355,8 +357,9 @@ fn longer_chain_with_more_work_wins_for_network(network: Network) -> Result<()> fn equal_length_goes_to_more_work() -> Result<()> { let _init_guard = zebra_test::init(); - equal_length_goes_to_more_work_for_network(Network::Mainnet)?; - equal_length_goes_to_more_work_for_network(Network::Testnet)?; + for network in Network::iter() { + equal_length_goes_to_more_work_for_network(network)?; + } Ok(()) } @@ -394,8 +397,9 @@ fn equal_length_goes_to_more_work_for_network(network: Network) -> Result<()> { #[test] fn history_tree_is_updated() -> Result<()> { - history_tree_is_updated_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Heartwood)?; - history_tree_is_updated_for_network_upgrade(Network::Testnet, NetworkUpgrade::Heartwood)?; + for network in Network::iter() { + history_tree_is_updated_for_network_upgrade(network, NetworkUpgrade::Heartwood)?; + } // TODO: we can't test other upgrades until we have a method for creating a FinalizedState // with a HistoryTree. Ok(()) @@ -497,8 +501,9 @@ fn history_tree_is_updated_for_network_upgrade( #[test] fn commitment_is_validated() { - commitment_is_validated_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Heartwood); - commitment_is_validated_for_network_upgrade(Network::Testnet, NetworkUpgrade::Heartwood); + for network in Network::iter() { + commitment_is_validated_for_network_upgrade(network, NetworkUpgrade::Heartwood); + } // TODO: we can't test other upgrades until we have a method for creating a FinalizedState // with a HistoryTree. } diff --git a/zebra-state/tests/basic.rs b/zebra-state/tests/basic.rs index 49d3346f0..01b90a11e 100644 --- a/zebra-state/tests/basic.rs +++ b/zebra-state/tests/basic.rs @@ -63,7 +63,7 @@ async fn check_transcripts_mainnet() -> Result<(), Report> { #[tokio::test(flavor = "multi_thread")] async fn check_transcripts_testnet() -> Result<(), Report> { - check_transcripts(Network::Testnet).await + check_transcripts(Network::new_default_testnet()).await } #[spandoc::spandoc] diff --git a/zebra-test/Cargo.toml b/zebra-test/Cargo.toml index 4b563c4b6..16d97cf08 100644 --- a/zebra-test/Cargo.toml +++ b/zebra-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-test" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "Test harnesses and test vectors for Zebra" license = "MIT OR Apache-2.0" @@ -16,16 +16,16 @@ categories = ["command-line-utilities", "cryptography::cryptocurrencies"] [dependencies] hex = "0.4.3" -indexmap = "2.2.5" +indexmap = "2.2.6" lazy_static = "1.4.0" -insta = "1.36.1" +insta = "1.38.0" itertools = "0.12.1" proptest = "1.4.0" once_cell = "1.18.0" rand = "0.8.5" -regex = "1.10.3" +regex = "1.10.4" -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } tower = { version = "0.4.13", features = ["util"] } futures = "0.3.30" diff --git a/zebra-test/src/mock_service.rs b/zebra-test/src/mock_service.rs index 25f379034..7ab0d1f61 100644 --- a/zebra-test/src/mock_service.rs +++ b/zebra-test/src/mock_service.rs @@ -966,6 +966,7 @@ impl ResponseSender { /// /// - [`PanicAssertion`] /// - [`PropTestAssertion`] +#[allow(dead_code)] trait AssertionType {} /// Represents normal Rust assertions that panic, like [`assert_eq`]. diff --git a/zebra-test/src/vectors/block.rs b/zebra-test/src/vectors/block.rs index 1623996af..d25eb5d7c 100644 --- a/zebra-test/src/vectors/block.rs +++ b/zebra-test/src/vectors/block.rs @@ -5,7 +5,7 @@ use hex::FromHex; use lazy_static::lazy_static; -use std::{collections::BTreeMap, convert::TryInto}; +use std::collections::BTreeMap; trait ReverseCollection { /// Return a reversed copy of this collection diff --git a/zebra-test/tests/transcript.rs b/zebra-test/tests/transcript.rs index e51b53ac1..c90fb7c31 100644 --- a/zebra-test/tests/transcript.rs +++ b/zebra-test/tests/transcript.rs @@ -48,10 +48,6 @@ async fn self_check() { assert!(t1.check(t2).await.is_ok()); } -#[derive(Debug, thiserror::Error)] -#[error("Error")] -struct Error; - const TRANSCRIPT_DATA2: [(&str, Result<&str, ExpectedTranscriptError>); 4] = [ ("req1", Ok("rsp1")), ("req2", Ok("rsp2")), diff --git a/zebra-utils/Cargo.toml b/zebra-utils/Cargo.toml index e35f77324..658e6789d 100644 --- a/zebra-utils/Cargo.toml +++ b/zebra-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zebra-utils" -version = "1.0.0-beta.35" +version = "1.0.0-beta.36" authors = ["Zcash Foundation "] description = "Developer tools for Zebra maintenance and testing" license = "MIT OR Apache-2.0" @@ -95,36 +95,36 @@ tinyvec = { version = "1.6.0", features = ["rustc_1_55"] } structopt = "0.3.26" hex = "0.4.3" -serde_json = "1.0.113" +serde_json = "1.0.115" tracing-error = "0.2.0" tracing-subscriber = "0.3.18" thiserror = "1.0.58" -zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.35" } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35" } +zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36" } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36" } zebra-scan = { path = "../zebra-scan", version = "0.1.0-alpha.4", optional = true } # These crates are needed for the block-template-to-proposal binary -zebra-rpc = { path = "../zebra-rpc", version = "1.0.0-beta.35", optional = true } +zebra-rpc = { path = "../zebra-rpc", version = "1.0.0-beta.36", optional = true } # These crates are needed for the zebra-checkpoints binary itertools = { version = "0.12.1", optional = true } # These crates are needed for the search-issue-refs binary -regex = { version = "1.10.3", optional = true } +regex = { version = "1.10.4", optional = true } # Avoid default openssl dependency to reduce the dependency tree and security alerts. reqwest = { version = "0.11.26", default-features = false, features = ["rustls-tls"], optional = true } # These crates are needed for the zebra-checkpoints and search-issue-refs binaries -tokio = { version = "1.36.0", features = ["full"], optional = true } +tokio = { version = "1.37.0", features = ["full"], optional = true } -jsonrpc = { version = "0.17.0", optional = true } +jsonrpc = { version = "0.18.0", 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.53", features = ["full"], optional = true } -quote = { version = "1.0.35", optional = true } -serde_yaml = { version = "0.9.33", optional = true } +syn = { version = "2.0.58", 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 } diff --git a/zebra-utils/src/bin/scanning-results-reader/main.rs b/zebra-utils/src/bin/scanning-results-reader/main.rs index cd31f55cf..1bfa15d36 100644 --- a/zebra-utils/src/bin/scanning-results-reader/main.rs +++ b/zebra-utils/src/bin/scanning-results-reader/main.rs @@ -41,14 +41,13 @@ use zebra_scan::{storage::Storage, Config}; /// - The transaction fetched via RPC cannot be deserialized from raw bytes. #[allow(clippy::print_stdout)] pub fn main() { - let network = zcash_primitives::consensus::Network::MainNetwork; - let zebra_network: zebra_chain::parameters::Network = network.into(); - let storage = Storage::new(&Config::default(), &zebra_network, true); + let network = zebra_chain::parameters::Network::Mainnet; + let storage = Storage::new(&Config::default(), &network, true); // If the first memo is empty, it doesn't get printed. But we never print empty memos anyway. let mut prev_memo = "".to_owned(); for (key, _) in storage.sapling_keys_last_heights().iter() { - let dfvk = sapling_key_to_scan_block_keys(key, &zebra_network) + let dfvk = sapling_key_to_scan_block_keys(key, &network) .expect("Scanning key from the storage should be valid") .0 .into_iter() diff --git a/zebrad/Cargo.toml b/zebrad/Cargo.toml index 33f607527..f9ee5540f 100644 --- a/zebrad/Cargo.toml +++ b/zebrad/Cargo.toml @@ -1,7 +1,7 @@ [package] # Crate metadata name = "zebrad" -version = "1.6.0" +version = "1.6.1" authors = ["Zcash Foundation "] description = "The Zcash Foundation's independent, consensus-compatible implementation of a Zcash node" license = "MIT OR Apache-2.0" @@ -158,33 +158,33 @@ test_sync_past_mandatory_checkpoint_mainnet = [] test_sync_past_mandatory_checkpoint_testnet = [] [dependencies] -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35" } -zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.35" } -zebra-network = { path = "../zebra-network", version = "1.0.0-beta.35" } -zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.35" } -zebra-rpc = { path = "../zebra-rpc", version = "1.0.0-beta.35" } -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35" } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36" } +zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.36" } +zebra-network = { path = "../zebra-network", version = "1.0.0-beta.36" } +zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36" } +zebra-rpc = { path = "../zebra-rpc", version = "1.0.0-beta.36" } +zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36" } # Experimental shielded-scan feature zebra-scan = { path = "../zebra-scan", version = "0.1.0-alpha.4", optional = true } # Required for crates.io publishing, but it's only used in tests -zebra-utils = { path = "../zebra-utils", version = "1.0.0-beta.35", optional = true } +zebra-utils = { path = "../zebra-utils", version = "1.0.0-beta.36", optional = true } abscissa_core = "0.7.0" -clap = { version = "4.5.3", features = ["cargo"] } +clap = { version = "4.5.4", features = ["cargo"] } chrono = { version = "0.4.34", default-features = false, features = ["clock", "std"] } humantime-serde = "1.1.1" -indexmap = "2.2.5" +indexmap = "2.2.6" lazy_static = "1.4.0" semver = "1.0.22" serde = { version = "1.0.196", features = ["serde_derive"] } toml = "0.8.11" futures = "0.3.30" -rayon = "1.9.0" -tokio = { version = "1.36.0", features = ["time", "rt-multi-thread", "macros", "tracing", "signal"] } -tokio-stream = { version = "0.1.14", features = ["time"] } +rayon = "1.10.0" +tokio = { version = "1.37.0", features = ["time", "rt-multi-thread", "macros", "tracing", "signal"] } +tokio-stream = { version = "0.1.15", features = ["time"] } tower = { version = "0.4.13", features = ["hedge", "limit"] } pin-project = "1.1.5" @@ -257,21 +257,21 @@ hex = "0.4.3" hex-literal = "0.4.1" jsonrpc-core = "18.0.0" once_cell = "1.18.0" -regex = "1.10.3" -insta = { version = "1.36.1", features = ["json"] } +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.113", features = ["preserve_order"] } +serde_json = { version = "1.0.115", features = ["preserve_order"] } tempfile = "3.10.1" hyper = { version = "0.14.28", features = ["http1", "http2", "server"]} tracing-test = { version = "0.2.4", features = ["no-env-filter"] } -tokio = { version = "1.36.0", features = ["full", "tracing", "test-util"] } -tokio-stream = "0.1.14" +tokio = { version = "1.37.0", features = ["full", "tracing", "test-util"] } +tokio-stream = "0.1.15" # test feature lightwalletd-grpc-tests -prost = "0.12.2" +prost = "0.12.4" tonic = "0.11.0" proptest = "1.4.0" @@ -280,16 +280,16 @@ proptest-derive = "0.4.0" # enable span traces and track caller in tests color-eyre = { version = "0.6.3" } -zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-network = { path = "../zebra-network", version = "1.0.0-beta.35", features = ["proptest-impl"] } -zebra-scan = { path = "../zebra-scan", version = "0.1.0-alpha.4", features = ["proptest-impl"] } -zebra-state = { path = "../zebra-state", version = "1.0.0-beta.35", features = ["proptest-impl"] } +zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-network = { path = "../zebra-network", version = "1.0.0-beta.36", features = ["proptest-impl"] } +zebra-scan = { path = "../zebra-scan", version = "0.1.0-alpha.5", features = ["proptest-impl"] } +zebra-state = { path = "../zebra-state", version = "1.0.0-beta.36", features = ["proptest-impl"] } -zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.35", features = ["rpc-client"] } +zebra-node-services = { path = "../zebra-node-services", version = "1.0.0-beta.36", features = ["rpc-client"] } -zebra-test = { path = "../zebra-test", version = "1.0.0-beta.35" } -zebra-grpc = { path = "../zebra-grpc", version = "0.1.0-alpha.2" } +zebra-test = { path = "../zebra-test", version = "1.0.0-beta.36" } +zebra-grpc = { path = "../zebra-grpc", version = "0.1.0-alpha.3" } # Used by the checkpoint generation tests via the zebra-checkpoints feature # (the binaries in this crate won't be built unless their features are enabled). @@ -300,4 +300,4 @@ zebra-grpc = { path = "../zebra-grpc", version = "0.1.0-alpha.2" } # When `-Z bindeps` is stabilised, enable this binary dependency instead: # https://github.com/rust-lang/cargo/issues/9096 # zebra-utils { path = "../zebra-utils", artifact = "bin:zebra-checkpoints" } -zebra-utils = { path = "../zebra-utils", version = "1.0.0-beta.35" } +zebra-utils = { path = "../zebra-utils", version = "1.0.0-beta.36" } diff --git a/zebrad/src/commands/copy_state.rs b/zebrad/src/commands/copy_state.rs index 179367ef0..56e7eea62 100644 --- a/zebrad/src/commands/copy_state.rs +++ b/zebrad/src/commands/copy_state.rs @@ -35,7 +35,7 @@ use std::{cmp::min, path::PathBuf}; -use abscissa_core::{config, Command, FrameworkError, Runnable}; +use abscissa_core::{config, Command, FrameworkError}; use color_eyre::eyre::{eyre, Report}; use tokio::time::Instant; use tower::{Service, ServiceExt}; diff --git a/zebrad/src/commands/start.rs b/zebrad/src/commands/start.rs index a6f2ec77f..dbe2368f3 100644 --- a/zebrad/src/commands/start.rs +++ b/zebrad/src/commands/start.rs @@ -78,7 +78,7 @@ //! //! Some of the diagnostic features are optional, and need to be enabled at compile-time. -use abscissa_core::{config, Command, FrameworkError, Runnable}; +use abscissa_core::{config, Command, FrameworkError}; use color_eyre::eyre::{eyre, Report}; use futures::FutureExt; use tokio::{pin, select, sync::oneshot}; diff --git a/zebrad/src/components/inbound/tests/fake_peer_set.rs b/zebrad/src/components/inbound/tests/fake_peer_set.rs index c0dacf897..3ca30c575 100644 --- a/zebrad/src/components/inbound/tests/fake_peer_set.rs +++ b/zebrad/src/components/inbound/tests/fake_peer_set.rs @@ -1,13 +1,6 @@ //! Inbound service tests with a fake peer set. -use std::{ - collections::HashSet, - iter::{self, FromIterator}, - net::SocketAddr, - str::FromStr, - sync::Arc, - time::Duration, -}; +use std::{collections::HashSet, iter, net::SocketAddr, str::FromStr, sync::Arc, time::Duration}; use futures::FutureExt; use tokio::{sync::oneshot, task::JoinHandle, time::timeout}; diff --git a/zebrad/src/components/mempool/storage/tests/vectors.rs b/zebrad/src/components/mempool/storage/tests/vectors.rs index 48bb3cb8e..5b60c133e 100644 --- a/zebrad/src/components/mempool/storage/tests/vectors.rs +++ b/zebrad/src/components/mempool/storage/tests/vectors.rs @@ -8,11 +8,10 @@ use zebra_chain::{ amount::Amount, block::{Block, Height}, parameters::Network, - transaction::{UnminedTxId, VerifiedUnminedTx}, }; use crate::components::mempool::{ - config, storage::tests::unmined_transactions_in_blocks, storage::*, Mempool, + storage::tests::unmined_transactions_in_blocks, storage::*, Mempool, }; /// Eviction memory time used for tests. Most tests won't care about this @@ -60,8 +59,9 @@ fn mempool_storage_basic() -> Result<()> { // Test multiple times to catch intermittent bugs since eviction is randomized for _ in 0..10 { - mempool_storage_basic_for_network(Network::Mainnet)?; - mempool_storage_basic_for_network(Network::Testnet)?; + for network in Network::iter() { + mempool_storage_basic_for_network(network)?; + } } Ok(()) @@ -236,10 +236,9 @@ fn mempool_storage_crud_same_effects_mainnet() { #[test] fn mempool_expired_basic() -> Result<()> { let _init_guard = zebra_test::init(); - - mempool_expired_basic_for_network(Network::Mainnet)?; - mempool_expired_basic_for_network(Network::Testnet)?; - + for network in Network::iter() { + mempool_expired_basic_for_network(network)?; + } Ok(()) } diff --git a/zebrad/src/components/mempool/tests/vector.rs b/zebrad/src/components/mempool/tests/vector.rs index db1915a53..2868fef2e 100644 --- a/zebrad/src/components/mempool/tests/vector.rs +++ b/zebrad/src/components/mempool/tests/vector.rs @@ -1,6 +1,6 @@ //! Fixed test vectors for the mempool. -use std::{collections::HashSet, sync::Arc}; +use std::sync::Arc; use color_eyre::Report; use tokio::time::{self, timeout}; @@ -15,12 +15,10 @@ use zebra_state::{Config as StateConfig, CHAIN_TIP_UPDATE_WAIT_LIMIT}; use zebra_test::mock_service::{MockService, PanicAssertion}; use crate::components::{ - mempool::{self, storage::tests::unmined_transactions_in_blocks, *}, + mempool::{self, *}, sync::RecentSyncLengths, }; -use super::UnboxMempoolError; - /// A [`MockService`] representing the network service. type MockPeerSet = MockService; diff --git a/zebrad/src/components/sync/downloads.rs b/zebrad/src/components/sync/downloads.rs index 67f6ee484..7ee352ae4 100644 --- a/zebrad/src/components/sync/downloads.rs +++ b/zebrad/src/components/sync/downloads.rs @@ -2,7 +2,7 @@ use std::{ collections::HashMap, - convert::{self, TryFrom}, + convert, pin::Pin, sync::Arc, task::{Context, Poll}, diff --git a/zebrad/src/components/sync/end_of_support.rs b/zebrad/src/components/sync/end_of_support.rs index f534f0475..55654bd68 100644 --- a/zebrad/src/components/sync/end_of_support.rs +++ b/zebrad/src/components/sync/end_of_support.rs @@ -13,7 +13,7 @@ use zebra_chain::{ use crate::application::release_version; /// The estimated height that this release will be published. -pub const ESTIMATED_RELEASE_HEIGHT: u32 = 2_413_000; +pub const ESTIMATED_RELEASE_HEIGHT: u32 = 2_471_000; /// The maximum number of days after `ESTIMATED_RELEASE_HEIGHT` where a Zebra server will run /// without halting. diff --git a/zebrad/src/components/tokio.rs b/zebrad/src/components/tokio.rs index 802ebc310..7478022dd 100644 --- a/zebrad/src/components/tokio.rs +++ b/zebrad/src/components/tokio.rs @@ -9,7 +9,7 @@ use std::{future::Future, time::Duration}; -use abscissa_core::{Application, Component, FrameworkError, Shutdown}; +use abscissa_core::{Component, FrameworkError, Shutdown}; use color_eyre::Report; use tokio::runtime::Runtime; diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index 5257b8b72..6c9115d9e 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -155,7 +155,7 @@ use std::{ }; use color_eyre::{ - eyre::{eyre, Result, WrapErr}, + eyre::{eyre, WrapErr}, Help, }; use semver::Version; @@ -480,7 +480,7 @@ fn ephemeral(cache_dir_config: EphemeralConfig, cache_dir_check: EphemeralCheck) let ignored_cache_dir = run_dir.path().join("state"); if cache_dir_config == EphemeralConfig::MisconfiguredCacheDir { // Write a configuration that sets both the cache_dir and ephemeral options - config.state.cache_dir = ignored_cache_dir.clone(); + config.state.cache_dir.clone_from(&ignored_cache_dir); } if cache_dir_check == EphemeralCheck::ExistingDirectory { // We set the cache_dir config to a newly created empty temp directory, @@ -923,6 +923,69 @@ fn invalid_generated_config() -> Result<()> { Ok(()) } +/// Test all versions of `zebrad.toml` we have stored can be parsed by the latest `zebrad`. +#[tracing::instrument] +#[test] +fn stored_configs_parsed_correctly() -> Result<()> { + let old_configs_dir = configs_dir(); + use abscissa_core::Application; + use zebrad::application::ZebradApp; + + tracing::info!(?old_configs_dir, "testing older config parsing"); + + for config_file in old_configs_dir + .read_dir() + .expect("read_dir call failed") + .flatten() + { + let config_file_path = config_file.path(); + let config_file_name = config_file_path + .file_name() + .expect("config files must have a file name") + .to_str() + .expect("config file names are valid unicode"); + + if config_file_name.starts_with('.') || config_file_name.starts_with('#') { + // Skip editor files and other invalid config paths + tracing::info!( + ?config_file_path, + "skipping hidden/temporary config file path" + ); + continue; + } + + // ignore files starting with getblocktemplate prefix + // if we were not built with the getblocktemplate-rpcs feature. + #[cfg(not(feature = "getblocktemplate-rpcs"))] + if config_file_name.starts_with(GET_BLOCK_TEMPLATE_CONFIG_PREFIX) { + tracing::info!( + ?config_file_path, + "skipping getblocktemplate-rpcs config file path" + ); + continue; + } + + // ignore files starting with shieldedscan prefix + // if we were not built with the shielded-scan feature. + #[cfg(not(feature = "shielded-scan"))] + if config_file_name.starts_with(SHIELDED_SCAN_CONFIG_PREFIX) { + tracing::info!(?config_file_path, "skipping shielded-scan config file path"); + continue; + } + + tracing::info!( + ?config_file_path, + "testing old config can be parsed by current zebrad" + ); + + ZebradApp::default() + .load_config(&config_file_path) + .expect("config should parse"); + } + + Ok(()) +} + /// Test all versions of `zebrad.toml` we have stored can be parsed by the latest `zebrad`. #[tracing::instrument] fn stored_configs_work() -> Result<()> { @@ -1052,7 +1115,7 @@ fn sync_one_checkpoint_mainnet() -> Result<()> { fn sync_one_checkpoint_testnet() -> Result<()> { sync_until( TINY_CHECKPOINT_TEST_HEIGHT, - &Testnet, + &Network::new_default_testnet(), STOP_AT_HEIGHT_REGEX, TINY_CHECKPOINT_TIMEOUT, None, @@ -1272,7 +1335,7 @@ fn sync_to_mandatory_checkpoint_mainnet() -> Result<()> { #[cfg_attr(feature = "test_sync_to_mandatory_checkpoint_testnet", test)] fn sync_to_mandatory_checkpoint_testnet() -> Result<()> { let _init_guard = zebra_test::init(); - let network = Testnet; + let network = Network::new_default_testnet(); create_cached_database(network) } @@ -1298,7 +1361,7 @@ fn sync_past_mandatory_checkpoint_mainnet() -> Result<()> { #[cfg_attr(feature = "test_sync_past_mandatory_checkpoint_testnet", test)] fn sync_past_mandatory_checkpoint_testnet() -> Result<()> { let _init_guard = zebra_test::init(); - let network = Testnet; + let network = Network::new_default_testnet(); sync_past_mandatory_checkpoint(network) } @@ -1323,7 +1386,10 @@ fn full_sync_mainnet() -> Result<()> { #[ignore] fn full_sync_testnet() -> Result<()> { // TODO: add "ZEBRA" at the start of this env var, to avoid clashes - full_sync_test(Testnet, "FULL_SYNC_TESTNET_TIMEOUT_MINUTES") + full_sync_test( + Network::new_default_testnet(), + "FULL_SYNC_TESTNET_TIMEOUT_MINUTES", + ) } #[cfg(feature = "prometheus")] @@ -2530,14 +2596,14 @@ async fn generate_checkpoints_mainnet() -> Result<()> { #[ignore] #[cfg(feature = "zebra-checkpoints")] async fn generate_checkpoints_testnet() -> Result<()> { - common::checkpoints::run(Testnet).await + common::checkpoints::run(Network::new_default_testnet()).await } /// Check that new states are created with the current state format version, /// and that restarting `zebrad` doesn't change the format version. #[tokio::test] async fn new_state_format() -> Result<()> { - for network in [Mainnet, Testnet] { + for network in Network::iter() { state_format_test("new_state_format_test", &network, 2, None).await?; } @@ -2555,7 +2621,7 @@ async fn update_state_format() -> Result<()> { fake_version.minor = 0; fake_version.patch = 0; - for network in [Mainnet, Testnet] { + for network in Network::iter() { state_format_test("update_state_format_test", &network, 3, Some(&fake_version)).await?; } @@ -2572,7 +2638,7 @@ async fn downgrade_state_format() -> Result<()> { fake_version.minor = u16::MAX.into(); fake_version.patch = 0; - for network in [Mainnet, Testnet] { + for network in Network::iter() { state_format_test( "downgrade_state_format_test", &network, @@ -2951,11 +3017,15 @@ fn scan_start_where_left() -> Result<()> { config.shielded_scan.sapling_keys_to_scan = keys; // Add the cache dir to shielded scan, make it the same as the zebrad cache state. - config.shielded_scan.db_config_mut().cache_dir = cache_dir.clone(); + config + .shielded_scan + .db_config_mut() + .cache_dir + .clone_from(&cache_dir); config.shielded_scan.db_config_mut().ephemeral = false; // Add the cache dir to state. - config.state.cache_dir = cache_dir.clone(); + config.state.cache_dir.clone_from(&cache_dir); config.state.ephemeral = false; // Remove the scan directory before starting. diff --git a/zebrad/tests/common/checkpoints.rs b/zebrad/tests/common/checkpoints.rs index f59dd8fb2..602525fd9 100644 --- a/zebrad/tests/common/checkpoints.rs +++ b/zebrad/tests/common/checkpoints.rs @@ -15,7 +15,7 @@ use tempfile::TempDir; use zebra_chain::{ block::{Height, HeightDiff, TryIntoHeight}, - parameters::Network::{self, *}, + parameters::Network, transparent::MIN_TRANSPARENT_COINBASE_MATURITY, }; use zebra_consensus::MAX_CHECKPOINT_HEIGHT_GAP; @@ -82,7 +82,7 @@ pub async fn run(network: Network) -> Result<()> { // Wait for the upgrade if needed. // Currently we only write an image for testnet, which is quick. // (Mainnet would need to wait at the end of this function, if the upgrade is long.) - if network == Testnet { + if network.is_a_test_network() { let state_version_message = wait_for_state_version_message(&mut zebrad)?; // Before we write a cached state image, wait for a database upgrade. diff --git a/zebrad/tests/common/configs/v1.7.0.toml b/zebrad/tests/common/configs/v1.7.0.toml new file mode 100644 index 000000000..58aed232f --- /dev/null +++ b/zebrad/tests/common/configs/v1.7.0.toml @@ -0,0 +1,91 @@ +# Default configuration for zebrad. +# +# This file can be used as a skeleton for custom configs. +# +# Unspecified fields use default values. Optional fields are Some(field) if the +# field is present and None if it is absent. +# +# This file is generated as an example using zebrad's current defaults. +# You should set only the config options you want to keep, and delete the rest. +# Only a subset of fields are present in the skeleton, since optional values +# whose default is None are omitted. +# +# The config format (including a complete list of sections and fields) is +# documented here: +# https://docs.rs/zebrad/latest/zebrad/config/struct.ZebradConfig.html +# +# zebrad attempts to load configs in the following order: +# +# 1. The -c flag on the command line, e.g., `zebrad -c myconfig.toml start`; +# 2. The file `zebrad.toml` in the users's preference directory (platform-dependent); +# 3. The default config. +# +# The user's preference directory and the default path to the `zebrad` config are platform dependent, +# based on `dirs::preference_dir`, see https://docs.rs/dirs/latest/dirs/fn.preference_dir.html : +# +# | Platform | Value | Example | +# | -------- | ------------------------------------- | ---------------------------------------------- | +# | Linux | `$XDG_CONFIG_HOME` or `$HOME/.config` | `/home/alice/.config/zebrad.toml` | +# | macOS | `$HOME/Library/Preferences` | `/Users/Alice/Library/Preferences/zebrad.toml` | +# | Windows | `{FOLDERID_RoamingAppData}` | `C:\Users\Alice\AppData\Local\zebrad.toml` | + +[consensus] +checkpoint_sync = true + +[mempool] +eviction_memory_time = "1h" +tx_cost_limit = 80000000 + +[metrics] + +[mining] +debug_like_zcashd = true + +[network] +cache_dir = true +crawl_new_peer_interval = "1m 1s" +initial_mainnet_peers = [ + "dnsseed.z.cash:8233", + "dnsseed.str4d.xyz:8233", + "mainnet.seeder.zfnd.org:8233", + "mainnet.is.yolo.money:8233", +] +initial_testnet_peers = [ + "dnsseed.testnet.z.cash:18233", + "testnet.seeder.zfnd.org:18233", + "testnet.is.yolo.money:18233", +] +listen_addr = "0.0.0.0:8233" +max_connections_per_ip = 1 +network = "Testnet" +peerset_initial_target_size = 25 + +[network.testnet_parameters.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 + +[state] +cache_dir = "cache_dir" +delete_old_database = true +ephemeral = false + +[sync] +checkpoint_verify_concurrency_limit = 1000 +download_concurrency_limit = 50 +full_verify_concurrency_limit = 20 +parallel_cpu_threads = 0 + +[tracing] +buffer_limit = 128000 +force_use_color = false +use_color = true +use_journald = false diff --git a/zebrad/tests/common/launch.rs b/zebrad/tests/common/launch.rs index 82e4f451e..0cbb52e7c 100644 --- a/zebrad/tests/common/launch.rs +++ b/zebrad/tests/common/launch.rs @@ -13,7 +13,6 @@ use std::{ time::Duration, }; -use color_eyre::eyre::Result; use tempfile::TempDir; use zebra_chain::parameters::Network::{self, *}; diff --git a/zebrad/tests/common/lightwalletd.rs b/zebrad/tests/common/lightwalletd.rs index 62282ed52..fc10242d8 100644 --- a/zebrad/tests/common/lightwalletd.rs +++ b/zebrad/tests/common/lightwalletd.rs @@ -16,7 +16,7 @@ use tempfile::TempDir; use zebra_chain::parameters::Network::{self, *}; use zebra_test::{ args, - command::{Arguments, TestChild, TestDirExt}, + command::{Arguments, TestDirExt}, net::random_known_port, prelude::*, }; diff --git a/zebrad/tests/common/shielded_scan/scan_task_commands.rs b/zebrad/tests/common/shielded_scan/scan_task_commands.rs index 1961c8f68..f626c0485 100644 --- a/zebrad/tests/common/shielded_scan/scan_task_commands.rs +++ b/zebrad/tests/common/shielded_scan/scan_task_commands.rs @@ -69,7 +69,10 @@ pub(crate) async fn run() -> Result<()> { .expect("already checked that there is a cached state path"); let mut scan_config = zebra_scan::Config::default(); - scan_config.db_config_mut().cache_dir = zebrad_state_path.clone(); + scan_config + .db_config_mut() + .cache_dir + .clone_from(&zebrad_state_path); // Logs the network as zebrad would as part of the metadata when starting up. // This is currently needed for the 'Check startup logs' step in CI to pass. diff --git a/zebrad/tests/common/sync.rs b/zebrad/tests/common/sync.rs index 5543640dd..ff5234c2b 100644 --- a/zebrad/tests/common/sync.rs +++ b/zebrad/tests/common/sync.rs @@ -7,7 +7,6 @@ use std::{path::PathBuf, time::Duration}; -use color_eyre::eyre::Result; use tempfile::TempDir; use zebra_chain::{block::Height, parameters::Network};