diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e4ecb7f..28a92c77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,10 @@ jobs: test: name: Test (+${{ matrix.rust }}) on ${{ matrix.os }} - # The large timeout is to accommodate Windows builds - timeout-minutes: 75 + # The large timeout is to accommodate: + # - Windows builds (75 minutes, typically 30-50 minutes) + # - parameter downloads (40 minutes, but only when the cache expires) + timeout-minutes: 115 runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -87,7 +89,7 @@ jobs: uses: actions/cache@v2 with: path: ${{ env.ZCASH_PARAMS }} - key: ${{ runner.os }}-params + key: ${{ runner.os }}-sprout-and-sapling-params - name: Fetch Zcash parameters if: steps.cache-params.outputs.cache-hit != 'true' working-directory: ./zebra-consensus diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d713e02e..f1341778 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -13,8 +13,10 @@ jobs: coverage: name: Coverage (+nightly) - # The large timeout is to accommodate nightly builds - timeout-minutes: 60 + # The large timeout is to accommodate: + # - nightly builds (75 minutes, typically 30-50 minutes) + # - parameter downloads (40 minutes, but only when the cache expires) + timeout-minutes: 115 runs-on: ubuntu-latest env: CARGO_INCREMENTAL: 0 @@ -62,7 +64,7 @@ jobs: uses: actions/cache@v2 with: path: ${{ env.ZCASH_PARAMS }} - key: ${{ runner.os }}-params + key: ${{ runner.os }}-sprout-and-sapling-params - name: Fetch Zcash parameters if: steps.cache-params.outputs.cache-hit != 'true' working-directory: ./zebra-consensus diff --git a/Cargo.lock b/Cargo.lock index db8068b8..2d9df883 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1086,7 +1086,7 @@ dependencies = [ [[package]] name = "equihash" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=53d0a51d33a421cb76d3e3124d1e4c1c9036068e#53d0a51d33a421cb76d3e3124d1e4c1c9036068e" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?rev=dea8d97d5ed09bdb6673cb64d0a63706f71c2f61#dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" dependencies = [ "blake2b_simd", "byteorder", @@ -4181,7 +4181,7 @@ dependencies = [ [[package]] name = "zcash_encoding" version = "0.0.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=53d0a51d33a421cb76d3e3124d1e4c1c9036068e#53d0a51d33a421cb76d3e3124d1e4c1c9036068e" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?rev=dea8d97d5ed09bdb6673cb64d0a63706f71c2f61#dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" dependencies = [ "byteorder", "nonempty", @@ -4190,7 +4190,7 @@ dependencies = [ [[package]] name = "zcash_history" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=53d0a51d33a421cb76d3e3124d1e4c1c9036068e#53d0a51d33a421cb76d3e3124d1e4c1c9036068e" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?rev=dea8d97d5ed09bdb6673cb64d0a63706f71c2f61#dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" dependencies = [ "bigint", "blake2b_simd", @@ -4200,7 +4200,7 @@ dependencies = [ [[package]] name = "zcash_note_encryption" version = "0.0.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=53d0a51d33a421cb76d3e3124d1e4c1c9036068e#53d0a51d33a421cb76d3e3124d1e4c1c9036068e" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?rev=dea8d97d5ed09bdb6673cb64d0a63706f71c2f61#dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" dependencies = [ "blake2b_simd", "byteorder", @@ -4215,7 +4215,7 @@ dependencies = [ [[package]] name = "zcash_primitives" version = "0.5.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=53d0a51d33a421cb76d3e3124d1e4c1c9036068e#53d0a51d33a421cb76d3e3124d1e4c1c9036068e" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?rev=dea8d97d5ed09bdb6673cb64d0a63706f71c2f61#dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" dependencies = [ "aes", "bip0039", @@ -4249,7 +4249,7 @@ dependencies = [ [[package]] name = "zcash_proofs" version = "0.5.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=53d0a51d33a421cb76d3e3124d1e4c1c9036068e#53d0a51d33a421cb76d3e3124d1e4c1c9036068e" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?rev=dea8d97d5ed09bdb6673cb64d0a63706f71c2f61#dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" dependencies = [ "bellman", "blake2b_simd", diff --git a/Cargo.toml b/Cargo.toml index b621cd73..7732a6b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,11 +22,21 @@ panic = "abort" [patch.crates-io] -# TODO: replace with upstream orchard when these changes are merged -# https://github.com/ZcashFoundation/zebra/issues/3056 +# TODO: replace with upstream orchard (#3056) orchard = { git = "https://github.com/ZcashFoundation/orchard.git", rev = "568e24cd5f129158375d7ac7d98c89ebff4f982f" } -# TODO: remove these after a new librustzcash release. +# TODO: replace with upstream librustzcash when these changes are merged (#3037) +# +# This zcash_proofs patch doesn't work, maybe because of features? +#zcash_proofs = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } + +# Use the ZcashFoundation fork where possible, to avoid duplicate dependencies +equihash = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } +zcash_note_encryption = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } +zcash_primitives = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } +zcash_history = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } + +# TODO: remove these after a new librustzcash release (#2982) # These are librustzcash git requirements specified in its workspace Cargo.toml, # that we must replicate here @@ -34,13 +44,15 @@ incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree. # Replaced by the ZcashFoundation fork above #orchard = { git = "https://github.com/zcash/orchard.git", rev = "2c8241f25b943aa05203eacf9905db117c69bd29" } +# Replaced by the ZcashFoundation fork above + # These are librustzcash file requirements specified in its workspace Cargo.toml, # that we must replace with git requirements -zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } +#zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } # These patches are not strictly required, # but they help avoid duplicate dependencies -equihash = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } -zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } -zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } -zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } +#equihash = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } +#zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } +#zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } +#zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index b30c65a0..70f31bba 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -33,7 +33,6 @@ hex = "0.4" incrementalmerkletree = "0.1.0" jubjub = "0.8.0" lazy_static = "1.4.0" -orchard = "0.0" rand_core = "0.6" ripemd160 = "0.9" secp256k1 = { version = "0.20.3", features = ["serde"] } @@ -45,9 +44,15 @@ subtle = "2.4" thiserror = "1" uint = "0.9.1" x25519-dalek = { version = "1.2.0", features = ["serde"] } -zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } -zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } -zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e" } + +# TODO: replace with upstream orchard (#3056) +orchard = { git = "https://github.com/ZcashFoundation/orchard.git", rev = "568e24cd5f129158375d7ac7d98c89ebff4f982f" } + +# TODO: replace with upstream librustzcash when these changes are merged (#3037) +equihash = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } +zcash_note_encryption = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } +zcash_primitives = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } +zcash_history = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61" } proptest = { version = "0.10", optional = true } proptest-derive = { version = "0.3.0", optional = true } @@ -57,7 +62,6 @@ rand_chacha = { version = "0.3", optional = true } # ZF deps ed25519-zebra = "3.0.0" -equihash = "0.1" # TODO: Update to 0.5 release when published redjubjub = { git = "https://github.com/ZcashFoundation/redjubjub.git", rev = "f772176560b0b7daf25eff2460e08dc127ac8407" } diff --git a/zebra-consensus/Cargo.toml b/zebra-consensus/Cargo.toml index 1fb4f266..c61b00a3 100644 --- a/zebra-consensus/Cargo.toml +++ b/zebra-consensus/Cargo.toml @@ -17,9 +17,6 @@ jubjub = "0.8.0" rand = "0.8" halo2 = "=0.1.0-beta.1" -# TODO: replace with upstream orchard when these changes are merged -# https://github.com/ZcashFoundation/zebra/issues/3056 -orchard = "0.0.0" chrono = "0.4.19" dirs = "4.0.0" @@ -37,7 +34,11 @@ tower = { version = "0.4.11", features = ["timeout", "util", "buffer"] } tracing = "0.1.29" tracing-futures = "0.2.5" -zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "53d0a51d33a421cb76d3e3124d1e4c1c9036068e", features = ["local-prover", "multicore", "download-params"] } +# TODO: replace with upstream orchard (#3056) +orchard = { git = "https://github.com/ZcashFoundation/orchard.git", rev = "568e24cd5f129158375d7ac7d98c89ebff4f982f" } + +# TODO: replace with upstream librustzcash when these changes are merged (#3037) +zcash_proofs = { git = "https://github.com/ZcashFoundation/librustzcash.git", rev = "dea8d97d5ed09bdb6673cb64d0a63706f71c2f61", features = ["local-prover", "multicore", "download-params"] } tower-fallback = { path = "../tower-fallback/" } tower-batch = { path = "../tower-batch/" } diff --git a/zebra-consensus/src/chain.rs b/zebra-consensus/src/chain.rs index 4e29f25a..58fe99b8 100644 --- a/zebra-consensus/src/chain.rs +++ b/zebra-consensus/src/chain.rs @@ -198,11 +198,13 @@ where S::Future: Send + 'static, { // Pre-download Groth16 parameters in a separate thread. - // This thread must be launched first, so the download doesn't happen on the startup thread. + // Give other tasks priority, before spawning the download task. + tokio::task::yield_now().await; + + // The parameter download thread must be launched before initializing any verifiers. + // Otherwise, the download might happen on the startup thread. let groth16_download_handle = spawn_blocking(|| { - tracing::info!("checking if Zcash Sapling and Sprout parameters have been downloaded"); - // The lazy static initializer does the download, if needed, // and the file hash checks. lazy_static::initialize(&crate::groth16::GROTH16_PARAMETERS); diff --git a/zebra-consensus/src/primitives/groth16/params.rs b/zebra-consensus/src/primitives/groth16/params.rs index e3bb8bd6..a3cd8680 100644 --- a/zebra-consensus/src/primitives/groth16/params.rs +++ b/zebra-consensus/src/primitives/groth16/params.rs @@ -5,6 +5,13 @@ use std::path::PathBuf; use bellman::groth16; use bls12_381::Bls12; +/// The timeout for each parameter file download, in seconds. +/// +/// Zebra assumes that it's running on at least a 10 Mbps connection. +/// So the parameter files should download in about 15 minutes using `zebrad download`. +/// But `zebrad start` downloads blocks at the same time, so we allow some extra time. +pub const PARAMETER_DOWNLOAD_TIMEOUT: u64 = 60 * 60; + lazy_static::lazy_static! { /// Groth16 Zero-Knowledge Proof parameters for the Sapling and Sprout circuits. /// @@ -20,10 +27,28 @@ lazy_static::lazy_static! { } /// Groth16 Zero-Knowledge Proof parameters for the Sapling and Sprout circuits. -#[non_exhaustive] pub struct Groth16Parameters { /// The Sapling circuit Groth16 parameters. pub sapling: SaplingParameters, + + /// The Sprout circuit Groth16 spend parameter. + pub sprout: SproutParameters, +} + +/// Groth16 Zero-Knowledge Proof spend and output parameters for the Sapling circuit. +pub struct SaplingParameters { + pub spend: groth16::Parameters, + pub spend_prepared_verifying_key: groth16::PreparedVerifyingKey, + + pub output: groth16::Parameters, + pub output_prepared_verifying_key: groth16::PreparedVerifyingKey, +} + +/// Groth16 Zero-Knowledge Proof spend parameters for the Sprout circuit. +/// +/// New Sprout outputs were disabled by the Canopy network upgrade. +pub struct SproutParameters { + pub spend_prepared_verifying_key: groth16::PreparedVerifyingKey, } impl Groth16Parameters { @@ -33,9 +58,64 @@ impl Groth16Parameters { /// /// If the downloaded or pre-existing parameter files are invalid. fn new() -> Groth16Parameters { - Groth16Parameters { - sapling: SaplingParameters::new(), + let params_directory = Groth16Parameters::directory(); + let sapling_spend_path = params_directory.join(zcash_proofs::SAPLING_SPEND_NAME); + let sapling_output_path = params_directory.join(zcash_proofs::SAPLING_OUTPUT_NAME); + let sprout_path = params_directory.join(zcash_proofs::SPROUT_NAME); + + // TODO: instead of the path check, add a zcash_proofs argument to skip hashing existing files + // (we check them on load anyway) + if !sapling_spend_path.exists() || !sapling_output_path.exists() { + tracing::info!("downloading Zcash Sapling parameters"); + let new_sapling_paths = + zcash_proofs::download_sapling_parameters(Some(PARAMETER_DOWNLOAD_TIMEOUT)) + .unwrap_or_else(|error| { + panic!( + "error downloading Sapling parameter files: {:?}. {}", + error, + Groth16Parameters::failure_hint() + ) + }); + assert_eq!(sapling_spend_path, new_sapling_paths.spend); + assert_eq!(sapling_output_path, new_sapling_paths.output); } + + if !sprout_path.exists() { + tracing::info!("downloading Zcash Sprout parameters"); + let new_sprout_path = + zcash_proofs::download_sprout_parameters(Some(PARAMETER_DOWNLOAD_TIMEOUT)) + .unwrap_or_else(|error| { + panic!( + "error downloading Sprout parameter files: {:?}. {}", + error, + Groth16Parameters::failure_hint() + ) + }); + assert_eq!(sprout_path, new_sprout_path); + } + + // TODO: if loading fails, log a message including `failure_hint` + tracing::info!("checking and loading Zcash Sapling and Sprout parameters"); + let parameters = zcash_proofs::load_parameters( + &sapling_spend_path, + &sapling_output_path, + Some(&sprout_path), + ); + + let sapling = SaplingParameters { + spend: parameters.spend_params, + spend_prepared_verifying_key: parameters.spend_vk, + output: parameters.output_params, + output_prepared_verifying_key: parameters.output_vk, + }; + + let sprout = SproutParameters { + spend_prepared_verifying_key: parameters + .sprout_vk + .expect("unreachable code: sprout loader panics on failure"), + }; + + Groth16Parameters { sapling, sprout } } /// Returns the path to the Groth16 parameters directory. @@ -51,52 +131,3 @@ impl Groth16Parameters { ) } } - -/// Groth16 Zero-Knowledge Proof spend and output parameters for the Sapling circuit. -#[non_exhaustive] -pub struct SaplingParameters { - pub spend: groth16::Parameters, - pub spend_prepared_verifying_key: groth16::PreparedVerifyingKey, - - pub output: groth16::Parameters, - pub output_prepared_verifying_key: groth16::PreparedVerifyingKey, -} - -impl SaplingParameters { - /// Download if needed, cache, check, and load the Sapling Groth16 parameters. - /// - /// # Panics - /// - /// If the downloaded or pre-existing parameter files are invalid. - fn new() -> SaplingParameters { - // TODO: Sprout - - let params_directory = Groth16Parameters::directory(); - let spend_path = params_directory.join("sapling-spend.params"); - let output_path = params_directory.join("sapling-output.params"); - - // Download parameters if needed. - // - // TODO: use try_exists when it stabilises, to exit early on permissions errors (#83186) - if !spend_path.exists() || !output_path.exists() { - tracing::info!("downloading Zcash Sapling parameters"); - zcash_proofs::download_parameters().unwrap_or_else(|_| { - panic!( - "error downloading parameter files. {}", - Groth16Parameters::failure_hint() - ) - }); - } - - // TODO: if loading fails, log a message including `failure_hint` - tracing::info!("checking and loading Zcash Sapling parameters"); - let parameters = zcash_proofs::load_parameters(&spend_path, &output_path, None); - - SaplingParameters { - spend: parameters.spend_params, - spend_prepared_verifying_key: parameters.spend_vk, - output: parameters.output_params, - output_prepared_verifying_key: parameters.output_vk, - } - } -} diff --git a/zebrad/src/commands/start.rs b/zebrad/src/commands/start.rs index 338ff803..36b7d53e 100644 --- a/zebrad/src/commands/start.rs +++ b/zebrad/src/commands/start.rs @@ -19,6 +19,9 @@ //! * verifies blocks using zebra-chain, then stores verified blocks in zebra-state //! * verifies mempool and block transactions using zebra-chain and zebra-script, //! and returns verified mempool transactions for mempool storage +//! * Groth16 Parameters Download Task +//! * downloads the Sprout and Sapling Groth16 circuit parameter files +//! * finishes when the download is complete and the download file hashes have been checked //! * Inbound Service //! * handles requests from peers for network data, chain data, and mempool transactions //! * spawns download and verify tasks for each gossiped block