From 7403897fdac22910c5ca726d29fd4835b3a275fe Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 13 Nov 2020 10:19:47 -0800 Subject: [PATCH 001/148] Add transcript tests as described in the state service tracking issue (#1281) * Add transcript test for requests while state is empty * Add happy path test for each query once the state is populated * let populate logic handle out of order blocks --- zebra-state/src/service.rs | 2 + zebra-state/src/service/tests.rs | 182 +++++++++++++++++++++++++++++++ zebra-test/src/transcript.rs | 9 +- 3 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 zebra-state/src/service/tests.rs diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 2a6430e30b4..1deefb1bc75 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -27,6 +27,8 @@ use crate::{ mod check; mod memory_state; +#[cfg(test)] +mod tests; mod utxo; // todo: put this somewhere diff --git a/zebra-state/src/service/tests.rs b/zebra-state/src/service/tests.rs new file mode 100644 index 00000000000..1acf159075e --- /dev/null +++ b/zebra-state/src/service/tests.rs @@ -0,0 +1,182 @@ +use std::sync::Arc; + +use futures::stream::FuturesUnordered; +use tower::{util::BoxService, Service, ServiceExt}; +use zebra_chain::{ + block::Block, parameters::Network, serialization::ZcashDeserializeInto, transaction, + transparent, +}; +use zebra_test::{prelude::*, transcript::Transcript}; + +use crate::{init, BoxError, Config, Request, Response}; + +const LAST_BLOCK_HEIGHT: u32 = 10; + +async fn populated_state( + blocks: impl IntoIterator>, +) -> BoxService { + let requests = blocks + .into_iter() + .map(|block| Request::CommitFinalizedBlock { block }); + + let config = Config::ephemeral(); + let network = Network::Mainnet; + let mut state = init(config, network); + + let mut responses = FuturesUnordered::new(); + + for request in requests { + let rsp = state.ready_and().await.unwrap().call(request); + responses.push(rsp); + } + + use futures::StreamExt; + while let Some(rsp) = responses.next().await { + rsp.expect("blocks should commit just fine"); + } + + state +} + +async fn test_populated_state_responds_correctly( + mut state: BoxService, +) -> Result<()> { + let blocks = zebra_test::vectors::MAINNET_BLOCKS + .range(0..=LAST_BLOCK_HEIGHT) + .map(|(_, block_bytes)| block_bytes.zcash_deserialize_into::>().unwrap()); + + for (ind, block) in blocks.into_iter().enumerate() { + let mut transcript = vec![]; + let height = block.coinbase_height().unwrap(); + let hash = block.hash(); + + transcript.push(( + Request::Block(hash.into()), + Ok(Response::Block(Some(block.clone()))), + )); + + transcript.push(( + Request::Block(height.into()), + Ok(Response::Block(Some(block.clone()))), + )); + + transcript.push(( + Request::Depth(block.hash()), + Ok(Response::Depth(Some(LAST_BLOCK_HEIGHT - height.0))), + )); + + if ind == LAST_BLOCK_HEIGHT as usize { + transcript.push((Request::Tip, Ok(Response::Tip(Some((height, hash)))))); + } + + // Consensus-critical bug in zcashd: transactions in the genesis block + // are ignored. + if height.0 != 0 { + for transaction in &block.transactions { + let transaction_hash = transaction.hash(); + + transcript.push(( + Request::Transaction(transaction_hash), + Ok(Response::Transaction(Some(transaction.clone()))), + )); + + for (index, output) in transaction.outputs().iter().enumerate() { + let outpoint = transparent::OutPoint { + hash: transaction_hash, + index: index as _, + }; + + transcript.push(( + Request::AwaitUtxo(outpoint), + Ok(Response::Utxo(output.clone())), + )); + } + } + } + + let transcript = Transcript::from(transcript); + transcript.check(&mut state).await?; + } + + Ok(()) +} + +#[tokio::main] +async fn populate_and_check(blocks: Vec>) -> Result<()> { + let state = populated_state(blocks).await; + test_populated_state_responds_correctly(state).await?; + Ok(()) +} + +fn out_of_order_committing_strategy() -> BoxedStrategy>> { + let blocks = zebra_test::vectors::MAINNET_BLOCKS + .range(0..=LAST_BLOCK_HEIGHT) + .map(|(_, block_bytes)| block_bytes.zcash_deserialize_into::>().unwrap()) + .collect::>(); + + Just(blocks).prop_shuffle().boxed() +} + +#[tokio::test] +async fn empty_state_still_responds_to_requests() -> Result<()> { + zebra_test::init(); + + let block = + zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into::>()?; + + let iter = vec![ + // No checks for CommitBlock or CommitFinalizedBlock because empty state + // precondition doesn't matter to them + (Request::Depth(block.hash()), Ok(Response::Depth(None))), + (Request::Tip, Ok(Response::Tip(None))), + (Request::BlockLocator, Ok(Response::BlockLocator(vec![]))), + ( + Request::Transaction(transaction::Hash([0; 32])), + Ok(Response::Transaction(None)), + ), + ( + Request::Block(block.hash().into()), + Ok(Response::Block(None)), + ), + ( + Request::Block(block.coinbase_height().unwrap().into()), + Ok(Response::Block(None)), + ), + // No check for AwaitUTXO because it will wait if the UTXO isn't present + ] + .into_iter(); + let transcript = Transcript::from(iter); + + let config = Config::ephemeral(); + let network = Network::Mainnet; + let state = init(config, network); + + transcript.check(state).await?; + + Ok(()) +} + +#[test] +fn state_behaves_when_blocks_are_committed_in_order() -> Result<()> { + zebra_test::init(); + + let blocks = zebra_test::vectors::MAINNET_BLOCKS + .range(0..=LAST_BLOCK_HEIGHT) + .map(|(_, block_bytes)| block_bytes.zcash_deserialize_into::>().unwrap()) + .collect(); + + populate_and_check(blocks)?; + + Ok(()) +} + +#[test] +fn state_behaves_when_blocks_are_committed_out_of_order() -> Result<()> { + zebra_test::init(); + + proptest!(|(blocks in out_of_order_committing_strategy())| { + populate_and_check(blocks).unwrap(); + }); + + Ok(()) +} diff --git a/zebra-test/src/transcript.rs b/zebra-test/src/transcript.rs index 8c9a2d44751..feea1b0c861 100644 --- a/zebra-test/src/transcript.rs +++ b/zebra-test/src/transcript.rs @@ -51,6 +51,7 @@ impl TransError { #[error("ErrorChecker Error: {0}")] struct ErrorCheckerError(Error); +#[must_use] pub struct Transcript where I: Iterator)>, @@ -58,12 +59,14 @@ where messages: I, } -impl From for Transcript +impl From for Transcript where - I: Iterator)>, + I: IntoIterator)>, { fn from(messages: I) -> Self { - Self { messages } + Self { + messages: messages.into_iter(), + } } } From 8c5f6d01778004e266e3ba02fc6d2788df084425 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Nov 2020 10:01:37 +0000 Subject: [PATCH 002/148] build(deps): bump once_cell from 1.5.1 to 1.5.2 Bumps [once_cell](https://github.com/matklad/once_cell) from 1.5.1 to 1.5.2. - [Release notes](https://github.com/matklad/once_cell/releases) - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.5.1...v1.5.2) Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- zebra-consensus/Cargo.toml | 2 +- zebra-state/Cargo.toml | 2 +- zebrad/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5c9d970617..2c2362ca36f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1820,9 +1820,9 @@ checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" [[package]] name = "once_cell" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f53cef67919d7d247eb9a2f128ca9e522789967ef1eb4ccd8c71a95a8aedf596" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" [[package]] name = "opaque-debug" diff --git a/zebra-consensus/Cargo.toml b/zebra-consensus/Cargo.toml index eb84e8b45fb..eeae83d0c9c 100644 --- a/zebra-consensus/Cargo.toml +++ b/zebra-consensus/Cargo.toml @@ -10,7 +10,7 @@ chrono = "0.4.19" color-eyre = "0.5" displaydoc = "0.1.7" jubjub = "0.5.1" -once_cell = "1.4" +once_cell = "1.5" rand = "0.7" redjubjub = "0.2" serde = { version = "1", features = ["serde_derive"] } diff --git a/zebra-state/Cargo.toml b/zebra-state/Cargo.toml index 5bd87e93ed8..06a21f298bf 100644 --- a/zebra-state/Cargo.toml +++ b/zebra-state/Cargo.toml @@ -30,7 +30,7 @@ displaydoc = "0.1.7" zebra-chain = { path = "../zebra-chain", features = ["proptest-impl"] } zebra-test = { path = "../zebra-test/" } -once_cell = "1.4" +once_cell = "1.5" spandoc = "0.2" tempdir = "0.3.7" tokio = { version = "0.2.22", features = ["full"] } diff --git a/zebrad/Cargo.toml b/zebrad/Cargo.toml index cb5431780f4..d88d7d29afa 100644 --- a/zebrad/Cargo.toml +++ b/zebrad/Cargo.toml @@ -41,6 +41,6 @@ inferno = { version = "0.10.1", default-features = false } [dev-dependencies] abscissa_core = { version = "0.5", features = ["testing"] } -once_cell = "1.4" +once_cell = "1.5" tempdir = "0.3.7" zebra-test = { path = "../zebra-test" } From 18eb4d1c317c98fc0c2a2c820e99de27cbc2bc8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Nov 2020 10:01:34 +0000 Subject: [PATCH 003/148] build(deps): bump primitive-types from 0.7.2 to 0.7.3 Bumps [primitive-types](https://github.com/paritytech/parity-common) from 0.7.2 to 0.7.3. - [Release notes](https://github.com/paritytech/parity-common/releases) - [Commits](https://github.com/paritytech/parity-common/compare/primitive-types-v0.7.2...primitive-types-v0.7.3) Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- zebra-chain/Cargo.toml | 2 +- zebra-state/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c2362ca36f..268023d6476 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2006,9 +2006,9 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55c21c64d0eaa4d7ed885d959ef2d62d9e488c27c0e02d9aa5ce6c877b7d5f8" +checksum = "7dd39dcacf71411ba488570da7bbc89b717225e46478b30ba99b92db6b149809" dependencies = [ "fixed-hash", "impl-codec", diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index 93efc7bc91e..54953858336 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -24,7 +24,7 @@ futures = "0.3" hex = "0.4" jubjub = "0.5.1" lazy_static = "1.4.0" -primitive-types = "0.7.2" +primitive-types = "0.7.3" rand_core = "0.5.1" ripemd160 = "0.8.0" secp256k1 = { version = "0.19.0", features = ["serde"] } diff --git a/zebra-state/Cargo.toml b/zebra-state/Cargo.toml index 06a21f298bf..ab5bf229521 100644 --- a/zebra-state/Cargo.toml +++ b/zebra-state/Cargo.toml @@ -35,4 +35,4 @@ spandoc = "0.2" tempdir = "0.3.7" tokio = { version = "0.2.22", features = ["full"] } proptest = "0.10.1" -primitive-types = "0.7.2" +primitive-types = "0.7.3" From 472163f8176c429ed889678d088955bd92f775ed Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 13 Nov 2020 16:58:25 -0500 Subject: [PATCH 004/148] Add a manual zebrad node deploy workflow --- .github/workflows/manual-deploy.yml | 64 +++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/manual-deploy.yml diff --git a/.github/workflows/manual-deploy.yml b/.github/workflows/manual-deploy.yml new file mode 100644 index 00000000000..414dabb3dd3 --- /dev/null +++ b/.github/workflows/manual-deploy.yml @@ -0,0 +1,64 @@ +name: Deploy a zebrad node + +on: + workflow_dispatch: + inputs: + network: + default: 'mainnet' + checkpoint_sync: + default: true + +env: + PROJECT_ID: zealous-zebra + +jobs: + + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set project and image names + run: | + BRANCH_NAME=$(expr $GITHUB_REF : '.*/\(.*\)') && \ + BRANCH_NAME=${BRANCH_NAME,,} && \ + REPOSITORY=${GITHUB_REPOSITORY,,} && \ + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV && \ + echo "SHORT_SHA=$(git rev-parse --short=7 $GITHUB_SHA)" >> $GITHUB_ENV && \ + echo "REPOSITORY=$REPOSITORY" >> $GITHUB_ENV + + - name: Set up gcloud + uses: GoogleCloudPlatform/github-actions/setup-gcloud@master + with: + version: '295.0.0' + project_id: ${{ env.PROJECT_ID }} + service_account_key: ${{ secrets.GCLOUD_AUTH }} + + # Build and push image to Google Container Registry + - name: Build + # Tagging w/ the commit SHA blocks the :latest tag on GCR + run: | + gcloud builds submit \ + --config cloudbuild.yaml \ + --substitutions SHORT_SHA="$SHORT_SHA",BRANCH_NAME="$BRANCH_NAME" + + # Run once: create firewall rule to allow incoming traffic to the node + # - name: Create Zcash incoming traffic firewall rule + # run: | + # gcloud compute firewall-rules create "allow-zcash" \ + # --target-tags zebrad \ + # --allow tcp:8233,tcp:18233 \ + # --source-ranges 0.0.0.0/0 \ + # --description="Allow incoming Zcash traffic from anywhere" \ + + # Creates Compute Engine virtual machine instance w/ zebrad container and disks + - name: Create instance running zebrad container image + run: | + gcloud compute instances create-with-container "zebra-$BRANCH_NAME-$SHORT_SHA" \ + --container-image "gcr.io/$PROJECT_ID/$REPOSITORY/$BRANCH_NAME:$SHORT_SHA" \ + --container-mount-disk mount-path='/zebrad-cache',name=zebrad-cache-$SHORT_SHA \ + --create-disk name=zebrad-cache-$SHORT_SHA,size=100GB,type=pd-balanced,auto-delete=no \ + --machine-type n2-standard-4 \ + --service-account cos-vm@zealous-zebra.iam.gserviceaccount.com \ + --tags zebrad \ + --zone us-central1-a From 1a1240a94351b97781d9723f9132ad63cfa048e8 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 13 Nov 2020 16:58:41 -0500 Subject: [PATCH 005/148] Rearrange some deploy flags --- .github/workflows/cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 4b9d5d598a8..e37bd81401d 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -144,9 +144,9 @@ jobs: run: | gcloud compute instance-templates create-with-container "zebrad-$BRANCH_NAME-$SHORT_SHA" \ --container-image "gcr.io/$PROJECT_ID/$REPOSITORY/$BRANCH_NAME:$SHORT_SHA" \ - --machine-type n2-standard-4 \ --create-disk name=zebrad-cache-$SHORT_SHA,size=100GB,type=pd-balanced,auto-delete=no \ --container-mount-disk mount-path="/zebrad-cache",name=zebrad-cache-$SHORT_SHA \ + --machine-type n2-standard-4 \ --service-account cos-vm@zealous-zebra.iam.gserviceaccount.com \ --scopes cloud-platform \ --tags zebrad \ From 7023465d91023ba388742e670000fd1f88a5a93c Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 13 Nov 2020 22:06:48 -0500 Subject: [PATCH 006/148] Pass in workflow inputs for network and checkpoint_sync (with defaults) all the way down --- .github/workflows/manual-deploy.yml | 5 ++++- Dockerfile | 7 ++++++- cloudbuild.yaml | 19 +++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/.github/workflows/manual-deploy.yml b/.github/workflows/manual-deploy.yml index 414dabb3dd3..e0db3962d49 100644 --- a/.github/workflows/manual-deploy.yml +++ b/.github/workflows/manual-deploy.yml @@ -40,7 +40,10 @@ jobs: run: | gcloud builds submit \ --config cloudbuild.yaml \ - --substitutions SHORT_SHA="$SHORT_SHA",BRANCH_NAME="$BRANCH_NAME" + --substitutions SHORT_SHA="$SHORT_SHA",\ + BRANCH_NAME="$BRANCH_NAME",\ + _CHECKPOINT_SYNC="${{ github.event.inputs.checkpoint_sync }}",\ + _NETWORK="${{ github.event.inputs.network }}" # Run once: create firewall rule to allow incoming traffic to the node # - name: Create Zcash incoming traffic firewall rule diff --git a/Dockerfile b/Dockerfile index 6bc8f4ad968..d10dc0c7a18 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,8 +35,13 @@ FROM debian:buster-slim AS zebrad-release COPY --from=builder /zebra/target/release/zebrad / +ARG checkpoint_sync=true +ARG network=Mainnet + RUN printf "[consensus]\n" >> /zebrad.toml -RUN printf "checkpoint_sync = true\n" >> /zebrad.toml +RUN printf "checkpoint_sync = $checkpoint_sync\n" >> /zebrad.toml +RUN printf "[network]\n" >> /zebrad.toml +RUN printf "network = $network\n" >> /zebrad.toml RUN printf "[state]\n" >> /zebrad.toml RUN printf "cache_dir = '/zebrad-cache'\n" >> /zebrad.toml RUN printf "memory_cache_bytes = 52428800\n" >> /zebrad.toml diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 7cd64677f36..b96b0c95ed0 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,8 +1,22 @@ steps: - name: 'gcr.io/cloud-builders/docker' - args: ['build', '--target', 'zebra-tests', '-t', 'gcr.io/$PROJECT_ID/zcashfoundation/zebra/tests/$BRANCH_NAME:$SHORT_SHA', '.'] + args: ['build', + '--target', + 'zebra-tests', + '-t', + 'gcr.io/$PROJECT_ID/zcashfoundation/zebra/tests/$BRANCH_NAME:$SHORT_SHA', + '.'] - name: 'gcr.io/cloud-builders/docker' - args: ['build', '--target', 'zebrad-release', '-t', 'gcr.io/$PROJECT_ID/zcashfoundation/zebra/$BRANCH_NAME:$SHORT_SHA', '.'] + args: ['build', + '--build-arg', + 'checkpoint_sync=${_CHECKPOINT_SYNC}', + '--build-arg', + 'network=${_NETWORK}', + '--target', + 'zebrad-release', + '-t', + 'gcr.io/$PROJECT_ID/zcashfoundation/zebra/$BRANCH_NAME:$SHORT_SHA', + '.'] images: - 'gcr.io/$PROJECT_ID/zcashfoundation/zebra/tests/$BRANCH_NAME:$SHORT_SHA' @@ -10,5 +24,6 @@ images: options: machineType: 'N1_HIGHCPU_32' + substitution_option: 'ALLOW_LOOSE' timeout: 1800s # 30 mins From 477eac7f19721d1bc18eac099708e32ad125b259 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 13 Nov 2020 23:53:26 -0500 Subject: [PATCH 007/148] Properly use Dockerfile ARG values --- .github/workflows/manual-deploy.yml | 2 +- Dockerfile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/manual-deploy.yml b/.github/workflows/manual-deploy.yml index e0db3962d49..914ae0d1b4d 100644 --- a/.github/workflows/manual-deploy.yml +++ b/.github/workflows/manual-deploy.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: network: - default: 'mainnet' + default: 'Mainnet' checkpoint_sync: default: true diff --git a/Dockerfile b/Dockerfile index d10dc0c7a18..8a7c279e577 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,9 +39,9 @@ ARG checkpoint_sync=true ARG network=Mainnet RUN printf "[consensus]\n" >> /zebrad.toml -RUN printf "checkpoint_sync = $checkpoint_sync\n" >> /zebrad.toml +RUN printf "checkpoint_sync = ${checkpoint_sync}\n" >> /zebrad.toml RUN printf "[network]\n" >> /zebrad.toml -RUN printf "network = $network\n" >> /zebrad.toml +RUN printf "network = '${network}'\n" >> /zebrad.toml RUN printf "[state]\n" >> /zebrad.toml RUN printf "cache_dir = '/zebrad-cache'\n" >> /zebrad.toml RUN printf "memory_cache_bytes = 52428800\n" >> /zebrad.toml From 87d749ee4fc69f7db839876f63d15c6b1f7ce12d Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Sat, 14 Nov 2020 21:36:41 -0500 Subject: [PATCH 008/148] I love it when capitalization matters, contrary to the docs --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8a7c279e577..12946c086cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,13 +35,13 @@ FROM debian:buster-slim AS zebrad-release COPY --from=builder /zebra/target/release/zebrad / -ARG checkpoint_sync=true -ARG network=Mainnet +ARG CHECKPOINT_SYNC=true +ARG NETWORK=Mainnet RUN printf "[consensus]\n" >> /zebrad.toml -RUN printf "checkpoint_sync = ${checkpoint_sync}\n" >> /zebrad.toml +RUN printf "checkpoint_sync = ${CHECKPOINT_SYNC}\n" >> /zebrad.toml RUN printf "[network]\n" >> /zebrad.toml -RUN printf "network = '${network}'\n" >> /zebrad.toml +RUN printf "network = '${NETWORK}'\n" >> /zebrad.toml RUN printf "[state]\n" >> /zebrad.toml RUN printf "cache_dir = '/zebrad-cache'\n" >> /zebrad.toml RUN printf "memory_cache_bytes = 52428800\n" >> /zebrad.toml From bb99a5aa2ad2b74a33a985cccdc0a62c4d361b52 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Sat, 14 Nov 2020 22:49:05 -0500 Subject: [PATCH 009/148] Linewrap --- .github/workflows/manual-deploy.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/manual-deploy.yml b/.github/workflows/manual-deploy.yml index 914ae0d1b4d..5382bf6337e 100644 --- a/.github/workflows/manual-deploy.yml +++ b/.github/workflows/manual-deploy.yml @@ -40,10 +40,7 @@ jobs: run: | gcloud builds submit \ --config cloudbuild.yaml \ - --substitutions SHORT_SHA="$SHORT_SHA",\ - BRANCH_NAME="$BRANCH_NAME",\ - _CHECKPOINT_SYNC="${{ github.event.inputs.checkpoint_sync }}",\ - _NETWORK="${{ github.event.inputs.network }}" + --substitutions SHORT_SHA="$SHORT_SHA",BRANCH_NAME="$BRANCH_NAME",_CHECKPOINT_SYNC="${{ github.event.inputs.checkpoint_sync }}",_NETWORK="${{ github.event.inputs.network }}" # Run once: create firewall rule to allow incoming traffic to the node # - name: Create Zcash incoming traffic firewall rule From 2b8d69622162dcbf9bc21b636b19a68834499826 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Sun, 15 Nov 2020 01:17:46 -0500 Subject: [PATCH 010/148] Better naming workflows (#1301) * Better workflow names * We run zebrad --- .github/workflows/manual-deploy.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/manual-deploy.yml b/.github/workflows/manual-deploy.yml index 5382bf6337e..fa33d64de7b 100644 --- a/.github/workflows/manual-deploy.yml +++ b/.github/workflows/manual-deploy.yml @@ -1,4 +1,4 @@ -name: Deploy a zebrad node +name: Manual Deploy on: workflow_dispatch: @@ -14,6 +14,7 @@ env: jobs: deploy: + name: Deploy one zebrad node runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -54,7 +55,7 @@ jobs: # Creates Compute Engine virtual machine instance w/ zebrad container and disks - name: Create instance running zebrad container image run: | - gcloud compute instances create-with-container "zebra-$BRANCH_NAME-$SHORT_SHA" \ + gcloud compute instances create-with-container "zebrad-$BRANCH_NAME-$SHORT_SHA" \ --container-image "gcr.io/$PROJECT_ID/$REPOSITORY/$BRANCH_NAME:$SHORT_SHA" \ --container-mount-disk mount-path='/zebrad-cache',name=zebrad-cache-$SHORT_SHA \ --create-disk name=zebrad-cache-$SHORT_SHA,size=100GB,type=pd-balanced,auto-delete=no \ From 57637560b9c93fab0bfc1632bef4d8a637e36813 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Sun, 15 Nov 2020 18:22:53 -0800 Subject: [PATCH 011/148] Add internal iterator API for accessing relevant chain blocks (#1271) * Add internal iterator API for accessing relevant chain blocks * get blocks from all chains in non_finalized state * Impl FusedIterator for service::Iter * impl ExactSizedIterator for service::Iter * let size_hint find heights in side chains Co-authored-by: teor --- zebra-state/src/service.rs | 112 ++++++++++++++++++ .../memory_state/non_finalized_state.rs | 26 ++++ 2 files changed, 138 insertions(+) diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 1deefb1bc75..6b446d990fe 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -252,10 +252,122 @@ impl StateService { self.mem.hash(height).or_else(|| self.sled.hash(height)) } + /// Return the height for the block at `hash` in any chain. + pub fn height_by_hash(&self, hash: block::Hash) -> Option { + self.mem + .height_by_hash(hash) + .or_else(|| self.sled.height(hash)) + } + /// Return the utxo pointed to by `outpoint` if it exists in any chain. pub fn utxo(&self, outpoint: &transparent::OutPoint) -> Option { self.mem.utxo(outpoint).or_else(|| self.sled.utxo(outpoint)) } + + /// Return an iterator over the relevant chain of the block identified by + /// `hash`. + /// + /// The block identified by `hash` is included in the chain of blocks yielded + /// by the iterator. + #[allow(dead_code)] + pub fn chain(&self, hash: block::Hash) -> Iter<'_> { + Iter { + service: self, + state: IterState::NonFinalized(hash), + } + } +} + +struct Iter<'a> { + service: &'a StateService, + state: IterState, +} + +enum IterState { + NonFinalized(block::Hash), + Finalized(block::Height), + Finished, +} + +impl Iter<'_> { + fn next_non_finalized_block(&mut self) -> Option> { + let Iter { service, state } = self; + + let hash = match state { + IterState::NonFinalized(hash) => *hash, + IterState::Finalized(_) | IterState::Finished => unreachable!(), + }; + + if let Some(block) = service.mem.block_by_hash(hash) { + let hash = block.header.previous_block_hash; + self.state = IterState::NonFinalized(hash); + Some(block) + } else { + None + } + } + + fn next_finalized_block(&mut self) -> Option> { + let Iter { service, state } = self; + + let hash_or_height: HashOrHeight = match *state { + IterState::Finalized(height) => height.into(), + IterState::NonFinalized(hash) => hash.into(), + IterState::Finished => unreachable!(), + }; + + if let Some(block) = service.sled.block(hash_or_height) { + let height = block + .coinbase_height() + .expect("valid blocks have a coinbase height"); + + if let Some(next_height) = height - 1 { + self.state = IterState::Finalized(next_height); + } else { + self.state = IterState::Finished; + } + + Some(block) + } else { + self.state = IterState::Finished; + None + } + } +} + +impl Iterator for Iter<'_> { + type Item = Arc; + + fn next(&mut self) -> Option { + match self.state { + IterState::NonFinalized(_) => self + .next_non_finalized_block() + .or_else(|| self.next_finalized_block()), + IterState::Finalized(_) => self.next_finalized_block(), + IterState::Finished => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl std::iter::FusedIterator for Iter<'_> {} + +impl ExactSizeIterator for Iter<'_> { + fn len(&self) -> usize { + match self.state { + IterState::NonFinalized(hash) => self + .service + .height_by_hash(hash) + .map(|height| (height.0 + 1) as _) + .unwrap_or(0), + IterState::Finalized(height) => (height.0 + 1) as _, + IterState::Finished => 0, + } + } } impl Service for StateService { diff --git a/zebra-state/src/service/memory_state/non_finalized_state.rs b/zebra-state/src/service/memory_state/non_finalized_state.rs index 2384bf07073..f4bcbe1e54d 100644 --- a/zebra-state/src/service/memory_state/non_finalized_state.rs +++ b/zebra-state/src/service/memory_state/non_finalized_state.rs @@ -143,6 +143,21 @@ impl NonFinalizedState { None } + /// Returns the `block` with the given hash in the any chain. + pub fn block_by_hash(&self, hash: block::Hash) -> Option> { + for chain in self.chain_set.iter().rev() { + if let Some(block) = chain + .height_by_hash + .get(&hash) + .and_then(|height| chain.blocks.get(height)) + { + return Some(block.clone()); + } + } + + None + } + /// Returns the `block` at a given height or hash in the best chain. pub fn block(&self, hash_or_height: HashOrHeight) -> Option> { let best_chain = self.best_chain()?; @@ -173,6 +188,17 @@ impl NonFinalizedState { Some(height) } + /// Returns the height of `hash` in any chain. + pub fn height_by_hash(&self, hash: block::Hash) -> Option { + for chain in self.chain_set.iter().rev() { + if let Some(height) = chain.height_by_hash.get(&hash) { + return Some(*height); + } + } + + None + } + /// Returns the given transaction if it exists in the best chain. pub fn transaction(&self, hash: transaction::Hash) -> Option> { let best_chain = self.best_chain()?; From ca4e792f472b1e94f4fcf3d21dbf14861bc9614b Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 17 Nov 2020 05:57:57 +1000 Subject: [PATCH 012/148] Put messages in request/response order And fix a comment typo --- .../src/protocol/external/message.rs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/zebra-network/src/protocol/external/message.rs b/zebra-network/src/protocol/external/message.rs index 1bf051a4b45..e0e035460b2 100644 --- a/zebra-network/src/protocol/external/message.rs +++ b/zebra-network/src/protocol/external/message.rs @@ -121,20 +121,15 @@ pub enum Message { data: Option<[u8; 32]>, }, - /// An `addr` message. - /// - /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#addr) - Addr(Vec), - /// A `getaddr` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#getaddr) GetAddr, - /// A `block` message. + /// An `addr` message. /// - /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#block) - Block(Arc), + /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#addr) + Addr(Vec), /// A `getblocks` message. /// @@ -155,16 +150,14 @@ pub enum Message { stop: Option, }, - /// A `headers` message. + /// An `inv` message. /// - /// Returns block headers in response to a getheaders packet. + /// Allows a node to advertise its knowledge of one or more + /// objects. It can be received unsolicited, or in reply to + /// `getblocks`. /// - /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#headers) - // Note that the block headers in this packet include a - // transaction count (a var_int, so there can be more than 81 - // bytes per header) as opposed to the block headers that are - // hashed by miners. - Headers(Vec), + /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#inv) + Inv(Vec), /// A `getheaders` message. /// @@ -173,7 +166,7 @@ pub enum Message { /// of its best chain and determine the blocks following the intersection /// point. /// - /// The peer responds with an `headers` packet with the hashes of subsequent blocks. + /// The peer responds with an `headers` packet with the headers of subsequent blocks. /// If supplied, the `stop` parameter specifies the last header to request. /// Otherwise, the maximum number of block headers (160) are sent. /// @@ -185,14 +178,16 @@ pub enum Message { stop: Option, }, - /// An `inv` message. + /// A `headers` message. /// - /// Allows a node to advertise its knowledge of one or more - /// objects. It can be received unsolicited, or in reply to - /// `getblocks`. + /// Returns block headers in response to a getheaders packet. /// - /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#inv) - Inv(Vec), + /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#headers) + // Note that the block headers in this packet include a + // transaction count (a var_int, so there can be more than 81 + // bytes per header) as opposed to the block headers that are + // hashed by miners. + Headers(Vec), /// A `getdata` message. /// @@ -203,17 +198,22 @@ pub enum Message { /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#getdata) GetData(Vec), - /// A `notfound` message. + /// A `block` message. /// - /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#notfound) - // See note above on `Inventory`. - NotFound(Vec), + /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#block) + Block(Arc), /// A `tx` message. /// /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#tx) Tx(Arc), + /// A `notfound` message. + /// + /// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#notfound) + // See note above on `Inventory`. + NotFound(Vec), + /// A `mempool` message. /// /// This was defined in [BIP35], which is included in Zcash. From 2253ab3c00ec8845f1dbea0914c20643d23477e6 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 17 Nov 2020 06:50:57 +1000 Subject: [PATCH 013/148] Improve state request docs Document best and any chain requests Explain that the block locator is sparse --- zebra-state/src/request.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/zebra-state/src/request.rs b/zebra-state/src/request.rs index 974210617bd..6a0da75c818 100644 --- a/zebra-state/src/request.rs +++ b/zebra-state/src/request.rs @@ -83,45 +83,49 @@ pub enum Request { // sapling_anchor: sapling::tree::Root, }, - /// Computes the depth in the best chain of the block identified by the given hash. + /// Computes the depth in the current best chain of the block identified by the given hash. /// /// Returns /// - /// * [`Response::Depth(Some(depth))`](Response::Depth) if the block is in the main chain; + /// * [`Response::Depth(Some(depth))`](Response::Depth) if the block is in the best chain; /// * [`Response::Depth(None)`](Response::Depth) otherwise. Depth(block::Hash), /// Returns [`Response::Tip`] with the current best chain tip. Tip, - /// Computes a block locator object based on the current chain state. + /// Computes a block locator object based on the current best chain. /// /// Returns [`Response::BlockLocator`] with hashes starting - /// from the current chain tip and reaching backwards towards the genesis - /// block. The first hash is the current chain tip. The last hash is the tip - /// of the finalized portion of the state. If the state is empty, the block - /// locator is also empty. + /// from the best chain tip, and following the chain of previous + /// hashes. The first hash is the best chain tip. The last hash is + /// the tip of the finalized portion of the state. Block locators + /// are not continuous - some intermediate hashes might be skipped. + /// + /// If the state is empty, the block locator is also empty. BlockLocator, - /// Looks up a transaction by hash. + /// Looks up a transaction by hash in the current best chain. /// /// Returns /// - /// * [`Response::Transaction(Some(Arc))`](Response::Transaction) if the transaction is known; + /// * [`Response::Transaction(Some(Arc))`](Response::Transaction) if the transaction is in the best chain; /// * [`Response::Transaction(None)`](Response::Transaction) otherwise. Transaction(transaction::Hash), - /// Looks up a block by hash or height. + /// Looks up a block by hash or height in the current best chain. /// /// Returns /// - /// * [`Response::Block(Some(Arc))`](Response::Block) if the block is known; - /// * [`Response::Block(None)`](Response::Transaction) otherwise. + /// * [`Response::Block(Some(Arc))`](Response::Block) if the block is in the best chain; + /// * [`Response::Block(None)`](Response::Block) otherwise. /// /// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or /// [`block::Height`] using `.into()`. Block(HashOrHeight), - /// Request a UTXO identified by the given Outpoint + /// Request a UTXO identified by the given Outpoint in any chain. + /// + /// Returns UTXOs fron any chain, including side-chains. AwaitUtxo(transparent::OutPoint), } From 4c2b44be9372938a4010c8c7073bd5dcf131410c Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Mon, 16 Nov 2020 15:31:22 -0800 Subject: [PATCH 014/148] Add tests for QueuedBlocks (#1268) * Add unit test for QueuedBlocks * Add test for pruned blocks --- .../src/service/memory_state/queued_blocks.rs | 156 +++++++++++++++++- 1 file changed, 153 insertions(+), 3 deletions(-) diff --git a/zebra-state/src/service/memory_state/queued_blocks.rs b/zebra-state/src/service/memory_state/queued_blocks.rs index dc7721857fc..ec16d807c50 100644 --- a/zebra-state/src/service/memory_state/queued_blocks.rs +++ b/zebra-state/src/service/memory_state/queued_blocks.rs @@ -96,10 +96,27 @@ impl QueuedBlocks { for hash in by_height.into_iter().flat_map(|(_, hashes)| hashes) { let expired = self.blocks.remove(&hash).expect("block is present"); let parent_hash = &expired.block.header.previous_block_hash; - self.by_parent + + let parent_list = self + .by_parent .get_mut(parent_hash) - .expect("parent is present") - .remove(&hash); + .expect("parent is present"); + + if parent_list.len() == 1 { + let removed = self + .by_parent + .remove(parent_hash) + .expect("parent is present"); + assert!( + removed.contains(&hash), + "hash must be present in parent hash list" + ); + } else { + assert!( + parent_list.remove(&hash), + "hash must be present in parent hash list" + ); + } } tracing::trace!(num_blocks = %self.blocks.len(), "Finished pruning blocks at or beneath the finalized tip height",); @@ -122,3 +139,136 @@ impl QueuedBlocks { metrics::gauge!("state.memory.queued.block.count", self.blocks.len() as _); } } + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use tokio::sync::oneshot; + use zebra_chain::{block::Block, serialization::ZcashDeserializeInto}; + use zebra_test::prelude::*; + + use crate::tests::FakeChainHelper; + + use self::assert_eq; + use super::*; + + // Quick helper trait for making queued blocks with throw away channels + trait IntoQueued { + fn into_queued(self) -> QueuedBlock; + } + + impl IntoQueued for Arc { + fn into_queued(self) -> QueuedBlock { + let (rsp_tx, _) = oneshot::channel(); + + QueuedBlock { + block: self, + rsp_tx, + } + } + } + + #[test] + fn dequeue_gives_right_children() -> Result<()> { + zebra_test::init(); + + let block1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + let child1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419201_BYTES.zcash_deserialize_into()?; + let child2 = block1.make_fake_child(); + + let parent = block1.header.previous_block_hash; + + let mut queue = QueuedBlocks::default(); + // Empty to start + assert_eq!(0, queue.blocks.len()); + assert_eq!(0, queue.by_parent.len()); + assert_eq!(0, queue.by_height.len()); + + // Inserting the first block gives us 1 in each table + queue.queue(block1.clone().into_queued()); + assert_eq!(1, queue.blocks.len()); + assert_eq!(1, queue.by_parent.len()); + assert_eq!(1, queue.by_height.len()); + + // The second gives us one in each table because its a child of the first + queue.queue(child1.clone().into_queued()); + assert_eq!(2, queue.blocks.len()); + assert_eq!(2, queue.by_parent.len()); + assert_eq!(2, queue.by_height.len()); + + // The 3rd only increments blocks, because it is also a child of the + // first block, so for the second and third tables it gets added to the + // existing HashSet value + queue.queue(child2.clone().into_queued()); + assert_eq!(3, queue.blocks.len()); + assert_eq!(2, queue.by_parent.len()); + assert_eq!(2, queue.by_height.len()); + + // Dequeueing the first block removes 1 block from each list + let children = queue.dequeue_children(parent); + assert_eq!(1, children.len()); + assert_eq!(block1, children[0].block); + assert_eq!(2, queue.blocks.len()); + assert_eq!(1, queue.by_parent.len()); + assert_eq!(1, queue.by_height.len()); + + // Dequeueing the children of the first block removes both of the other + // blocks, and empties all lists + let parent = children[0].block.hash(); + let children = queue.dequeue_children(parent); + assert_eq!(2, children.len()); + assert!(children + .iter() + .any(|QueuedBlock { block, .. }| block == &child1)); + assert!(children + .iter() + .any(|QueuedBlock { block, .. }| block == &child2)); + assert_eq!(0, queue.blocks.len()); + assert_eq!(0, queue.by_parent.len()); + assert_eq!(0, queue.by_height.len()); + + Ok(()) + } + + #[test] + fn prune_removes_right_children() -> Result<()> { + zebra_test::init(); + + let block1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + let child1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419201_BYTES.zcash_deserialize_into()?; + let child2 = block1.make_fake_child(); + + let mut queue = QueuedBlocks::default(); + queue.queue(block1.clone().into_queued()); + queue.queue(child1.clone().into_queued()); + queue.queue(child2.clone().into_queued()); + assert_eq!(3, queue.blocks.len()); + assert_eq!(2, queue.by_parent.len()); + assert_eq!(2, queue.by_height.len()); + + // Pruning the first height removes only block1 + queue.prune_by_height(block1.coinbase_height().unwrap()); + assert_eq!(2, queue.blocks.len()); + assert_eq!(1, queue.by_parent.len()); + assert_eq!(1, queue.by_height.len()); + assert!(queue.get_mut(&block1.hash()).is_none()); + assert!(queue.get_mut(&child1.hash()).is_some()); + assert!(queue.get_mut(&child2.hash()).is_some()); + + // Dequeueing the children of the first block removes both of the other + // blocks, and empties all lists + queue.prune_by_height(child1.coinbase_height().unwrap()); + assert_eq!(0, queue.blocks.len()); + assert_eq!(0, queue.by_parent.len()); + assert_eq!(0, queue.by_height.len()); + assert!(queue.get_mut(&child1.hash()).is_none()); + assert!(queue.get_mut(&child2.hash()).is_none()); + + Ok(()) + } +} From a6bd77e98a3625e8953ec0bda5bed59bea0ef84e Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Mon, 16 Nov 2020 15:53:33 -0800 Subject: [PATCH 015/148] Add check to ensure heights in state service are sequential (#1290) * Add check to ensure heights in state service are sequential Co-authored-by: teor --- zebra-state/src/service.rs | 3 +++ zebra-state/src/sled_state.rs | 38 ++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 6b446d990fe..90769ed9d2a 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -196,7 +196,10 @@ impl StateService { let parent_height = parent_block .coinbase_height() .expect("valid blocks have a coinbase height"); + let parent_hash = parent_block.hash(); check::height_one_more_than_parent_height(parent_height, block)?; + // should be impossible by design, so no handleable error is thrown + assert_eq!(parent_hash, block.header.previous_block_hash); // TODO: contextual validation design and implementation Ok(()) diff --git a/zebra-state/src/sled_state.rs b/zebra-state/src/sled_state.rs index 002f2b80e91..62a3a2b0aff 100644 --- a/zebra-state/src/sled_state.rs +++ b/zebra-state/src/sled_state.rs @@ -148,11 +148,45 @@ impl FinalizedState { let height = queued_block.block.coinbase_height().unwrap(); self.queued_by_prev_hash.insert(prev_hash, queued_block); - while let Some(queued_block) = self.queued_by_prev_hash.remove(&self.finalized_tip_hash()) { + loop { + let finalized_tip_hash = self.finalized_tip_hash(); + let queued_block = + if let Some(queued_block) = self.queued_by_prev_hash.remove(&finalized_tip_hash) { + queued_block + } else { + break; + }; + let height = queued_block .block .coinbase_height() .expect("valid blocks must have a height"); + + if self.block_by_height.is_empty() { + assert_eq!( + block::Hash([0; 32]), + prev_hash, + "the first block added to an empty state must be a genesis block" + ); + assert_eq!( + block::Height(0), + height, + "cannot commit genesis: invalid height" + ); + } else { + assert_eq!( + self.finalized_tip_height() + .expect("state must have a genesis block committed") + + 1, + Some(height) + ); + + assert_eq!( + finalized_tip_hash, + queued_block.block.header.previous_block_hash + ); + } + self.commit_finalized(queued_block); metrics::counter!("state.finalized.committed.block.count", 1); metrics::gauge!("state.finalized.committed.block.height", height.0 as _); @@ -216,8 +250,6 @@ impl FinalizedState { sprout_nullifiers, sapling_nullifiers, )| { - // TODO: check highest entry of hash_by_height as in RFC - // Index the block hash_by_height.zs_insert(height, hash)?; height_by_hash.zs_insert(hash, height)?; From 54cb9277ef94630197a1ca8be75ebe1f58512d52 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 16 Nov 2020 13:00:08 +1000 Subject: [PATCH 016/148] Allow some new clippy nightly lints --- zebra-chain/src/lib.rs | 2 ++ zebra-state/src/lib.rs | 2 ++ zebra-test/src/lib.rs | 2 ++ zebrad/tests/acceptance.rs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index 3c504a26fde..c35a8afde9b 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -8,6 +8,8 @@ #![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_chain")] // #![deny(missing_docs)] #![allow(clippy::try_err)] +#![allow(clippy::unknown_clippy_lints)] +#![allow(clippy::from_iter_instead_of_collect)] #[macro_use] extern crate serde; diff --git a/zebra-state/src/lib.rs b/zebra-state/src/lib.rs index 5e716772efb..42fd4cea2aa 100644 --- a/zebra-state/src/lib.rs +++ b/zebra-state/src/lib.rs @@ -5,6 +5,8 @@ #![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_state")] #![warn(missing_docs)] #![allow(clippy::try_err)] +#![allow(clippy::unknown_clippy_lints)] +#![allow(clippy::field_reassign_with_default)] mod config; mod constants; diff --git a/zebra-test/src/lib.rs b/zebra-test/src/lib.rs index 46919611acb..e45eb4a81e2 100644 --- a/zebra-test/src/lib.rs +++ b/zebra-test/src/lib.rs @@ -1,5 +1,7 @@ //! Miscellaneous test code for Zebra. +#![allow(clippy::unknown_clippy_lints)] +#![allow(clippy::from_iter_instead_of_collect)] // Each lazy_static variable uses additional recursion #![recursion_limit = "256"] diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index 227d9435431..742fb1ebd0f 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -14,6 +14,8 @@ #![warn(warnings, missing_docs, trivial_casts, unused_qualifications)] #![forbid(unsafe_code)] #![allow(clippy::try_err)] +#![allow(clippy::unknown_clippy_lints)] +#![allow(clippy::field_reassign_with_default)] use color_eyre::eyre::Result; use eyre::WrapErr; From d80a0c74026f6285aada7828220edab9b3f39104 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 16 Nov 2020 13:06:40 +1000 Subject: [PATCH 017/148] Stop panicking during contextual validation `check_contextual_validity` mistakenly used the new block's hash to try to get the parent block from the state. This caused a panic, because the new block isn't in the state yet. Use `StateService::chain` to get the parent block, because we'll be using `chain` for difficulty adjustment contextual verification anyway. --- zebra-state/src/service.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 90769ed9d2a..d502b3fae31 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -190,9 +190,10 @@ impl StateService { ); check::block_is_not_orphaned(finalized_tip_height, block)?; - let parent_block = self - .block(block.hash().into()) - .expect("the parent's presence has already been checked"); + let mut relevant_chain = self.chain(block.header.previous_block_hash); + let parent_block = relevant_chain + .next() + .expect("state must contain parent block to do contextual validation"); let parent_height = parent_block .coinbase_height() .expect("valid blocks have a coinbase height"); @@ -201,7 +202,8 @@ impl StateService { // should be impossible by design, so no handleable error is thrown assert_eq!(parent_hash, block.header.previous_block_hash); - // TODO: contextual validation design and implementation + // TODO: validate difficulty adjustment + // TODO: other contextual validation design and implelentation Ok(()) } @@ -272,7 +274,6 @@ impl StateService { /// /// The block identified by `hash` is included in the chain of blocks yielded /// by the iterator. - #[allow(dead_code)] pub fn chain(&self, hash: block::Hash) -> Iter<'_> { Iter { service: self, From cfe779db69f468408b221cc7a9cafd14948f97fb Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 16 Nov 2020 15:46:16 +1000 Subject: [PATCH 018/148] Add an info-level span to check_contextual_validity --- zebra-state/src/service.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index d502b3fae31..fd0faa2d855 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -50,6 +50,8 @@ struct StateService { queued_blocks: QueuedBlocks, /// The set of outpoints with pending requests for their associated transparent::Output pending_utxos: utxo::PendingUtxos, + /// The configured Zcash network + network: Network, /// Instant tracking the last time `pending_utxos` was pruned last_prune: Instant, } @@ -68,6 +70,7 @@ impl StateService { mem, queued_blocks, pending_utxos, + network, last_prune: Instant::now(), } } @@ -185,6 +188,15 @@ impl StateService { /// Check that `block` is contextually valid based on the committed finalized /// and non-finalized state. fn check_contextual_validity(&mut self, block: &Block) -> Result<(), ValidateContextError> { + let height = block + .coinbase_height() + .expect("semantically valid blocks have a coinbase height"); + let hash = block.hash(); + + let span = tracing::info_span!("StateService::check_contextual_validity", + ?height, network = ?self.network, ?hash); + let _entered = span.enter(); + let finalized_tip_height = self.sled.finalized_tip_height().expect( "finalized state must contain at least one block to use the non-finalized state", ); From c8e6f5843f58bc1125deaa0614007495de3c15d7 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Mon, 16 Nov 2020 22:10:21 -0300 Subject: [PATCH 019/148] Update RFC template (#1278) * update rfc template * change pull to issues --- .github/PULL_REQUEST_TEMPLATE/rfc.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/rfc.md b/.github/PULL_REQUEST_TEMPLATE/rfc.md index bdb39cf8501..e8a363a1eb1 100644 --- a/.github/PULL_REQUEST_TEMPLATE/rfc.md +++ b/.github/PULL_REQUEST_TEMPLATE/rfc.md @@ -15,10 +15,22 @@ The RFC process is documented in CONTRIBUTING.md. Please see the checklist there: https://zebra.zfnd.org/CONTRIBUTING.html --> + +### Summary + +Please copy the RFC summary over here. + +### More information + Feature Name: `my_feature` + Start Date: YYYY-MM-DD + Design PR: [ZcashFoundation/zebra#0000](https://github.com/ZcashFoundation/zebra/pull/0000) -Zebra Issue: [ZcashFoundation/zebra#0000](https://github.com/ZcashFoundation/zebra/pull/0000) + +Zebra Issue: [ZcashFoundation/zebra#0000](https://github.com/ZcashFoundation/zebra/issues/0000) + +### Document