2020-06-22 21:31:44 -07:00
|
|
|
use color_eyre::eyre::Report;
|
|
|
|
use once_cell::sync::Lazy;
|
2020-06-24 11:30:20 -07:00
|
|
|
use std::sync::Arc;
|
2020-06-22 21:31:44 -07:00
|
|
|
use tempdir::TempDir;
|
2020-08-15 15:45:37 -07:00
|
|
|
use zebra_chain::{block::Block, parameters::Network, serialization::ZcashDeserialize};
|
2020-07-31 11:54:18 -07:00
|
|
|
use zebra_test::transcript::{TransError, Transcript};
|
2020-06-22 21:31:44 -07:00
|
|
|
|
|
|
|
use zebra_state::*;
|
|
|
|
|
2020-09-09 17:59:58 -07:00
|
|
|
static COMMIT_FINALIZED_BLOCK_MAINNET: Lazy<Vec<(Request, Result<Response, TransError>)>> =
|
2020-08-04 13:39:32 -07:00
|
|
|
Lazy::new(|| {
|
|
|
|
let block: Arc<_> =
|
2020-09-04 02:34:40 -07:00
|
|
|
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
|
2020-08-04 13:39:32 -07:00
|
|
|
.unwrap()
|
|
|
|
.into();
|
2020-09-09 17:59:58 -07:00
|
|
|
let block2 = block.clone();
|
|
|
|
let hash = block.hash();
|
2020-08-04 13:39:32 -07:00
|
|
|
vec![
|
|
|
|
(
|
state: introduce PreparedBlock, FinalizedBlock
This change introduces two new types:
- `PreparedBlock`, representing a block which has undergone semantic
validation and has been prepared for contextual validation;
- `FinalizedBlock`, representing a block which is ready to be finalized
immediately;
and changes the `Request::CommitBlock`,`Request::CommitFinalizedBlock`
variants to use these types instead of their previous fields.
This change solves the problem of passing data between semantic
validation and contextual validation, and cleans up the state code by
allowing it to pass around a bundle of data. Previously, the state code
just passed around an `Arc<Block>`, which forced it to needlessly
recompute block hashes and other data, and was incompatible with the
already-known but not-yet-implemented data transfer requirements, namely
passing in the Sprout and Sapling anchors computed during contextual
validation.
This commit propagates the `PreparedBlock` and `FinalizedBlock` types
through the state code but only uses their data opportunistically, e.g.,
changing .hash() computations to use the precomputed hash. In the
future, these structures can be extended to pass data through the
verification pipeline for reuse as appropriate. For instance, these
changes allow the sprout and sapling anchors to be propagated through
the state.
2020-11-21 01:16:14 -08:00
|
|
|
Request::CommitFinalizedBlock(block.into()),
|
2020-09-09 17:59:58 -07:00
|
|
|
Ok(Response::Committed(hash)),
|
2020-09-04 02:50:25 -07:00
|
|
|
),
|
|
|
|
(
|
2020-09-09 17:59:58 -07:00
|
|
|
Request::Block(hash.into()),
|
|
|
|
Ok(Response::Block(Some(block2))),
|
2020-09-04 02:50:25 -07:00
|
|
|
),
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
2020-09-09 17:59:58 -07:00
|
|
|
static COMMIT_FINALIZED_BLOCK_TESTNET: Lazy<Vec<(Request, Result<Response, TransError>)>> =
|
2020-09-04 02:50:25 -07:00
|
|
|
Lazy::new(|| {
|
2020-09-09 17:59:58 -07:00
|
|
|
let block: Arc<_> =
|
2020-08-04 13:39:32 -07:00
|
|
|
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_TESTNET_GENESIS_BYTES[..])
|
|
|
|
.unwrap()
|
|
|
|
.into();
|
2020-09-09 17:59:58 -07:00
|
|
|
let block2 = block.clone();
|
|
|
|
let hash = block.hash();
|
2020-08-04 13:39:32 -07:00
|
|
|
vec![
|
|
|
|
(
|
state: introduce PreparedBlock, FinalizedBlock
This change introduces two new types:
- `PreparedBlock`, representing a block which has undergone semantic
validation and has been prepared for contextual validation;
- `FinalizedBlock`, representing a block which is ready to be finalized
immediately;
and changes the `Request::CommitBlock`,`Request::CommitFinalizedBlock`
variants to use these types instead of their previous fields.
This change solves the problem of passing data between semantic
validation and contextual validation, and cleans up the state code by
allowing it to pass around a bundle of data. Previously, the state code
just passed around an `Arc<Block>`, which forced it to needlessly
recompute block hashes and other data, and was incompatible with the
already-known but not-yet-implemented data transfer requirements, namely
passing in the Sprout and Sapling anchors computed during contextual
validation.
This commit propagates the `PreparedBlock` and `FinalizedBlock` types
through the state code but only uses their data opportunistically, e.g.,
changing .hash() computations to use the precomputed hash. In the
future, these structures can be extended to pass data through the
verification pipeline for reuse as appropriate. For instance, these
changes allow the sprout and sapling anchors to be propagated through
the state.
2020-11-21 01:16:14 -08:00
|
|
|
Request::CommitFinalizedBlock(block.into()),
|
2020-09-09 17:59:58 -07:00
|
|
|
Ok(Response::Committed(hash)),
|
2020-08-04 13:39:32 -07:00
|
|
|
),
|
|
|
|
(
|
2020-09-09 17:59:58 -07:00
|
|
|
Request::Block(hash.into()),
|
|
|
|
Ok(Response::Block(Some(block2))),
|
2020-08-04 13:39:32 -07:00
|
|
|
),
|
|
|
|
]
|
|
|
|
});
|
2020-06-22 21:31:44 -07:00
|
|
|
|
|
|
|
#[tokio::test]
|
2020-07-26 16:57:18 -07:00
|
|
|
async fn check_transcripts_mainnet() -> Result<(), Report> {
|
2020-08-15 15:45:37 -07:00
|
|
|
check_transcripts(Network::Mainnet).await
|
2020-07-26 16:57:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn check_transcripts_testnet() -> Result<(), Report> {
|
2020-08-15 15:45:37 -07:00
|
|
|
check_transcripts(Network::Testnet).await
|
2020-07-23 04:12:20 -07:00
|
|
|
}
|
|
|
|
|
2020-07-17 15:19:00 -07:00
|
|
|
#[spandoc::spandoc]
|
2020-07-26 16:57:18 -07:00
|
|
|
async fn check_transcripts(network: Network) -> Result<(), Report> {
|
2020-06-24 11:30:20 -07:00
|
|
|
zebra_test::init();
|
2020-06-22 21:31:44 -07:00
|
|
|
|
2020-09-09 17:59:58 -07:00
|
|
|
let mainnet_transcript = &[&COMMIT_FINALIZED_BLOCK_MAINNET];
|
|
|
|
let testnet_transcript = &[&COMMIT_FINALIZED_BLOCK_TESTNET];
|
2020-08-04 13:39:32 -07:00
|
|
|
|
|
|
|
for transcript_data in match network {
|
2020-09-04 02:50:25 -07:00
|
|
|
Network::Mainnet => mainnet_transcript,
|
2020-08-04 13:39:32 -07:00
|
|
|
Network::Testnet => testnet_transcript,
|
|
|
|
} {
|
2020-06-22 21:31:44 -07:00
|
|
|
let storage_guard = TempDir::new("")?;
|
2020-08-05 11:48:08 -07:00
|
|
|
let cache_dir = storage_guard.path().to_owned();
|
2020-09-01 12:39:04 -07:00
|
|
|
let service = zebra_state::init(
|
Fix sync algorithm. (#887)
* checkpoint: reject older of duplicate verification requests.
If we get a duplicate block verification request, we should drop the older one
in favor of the newer one, because the older request is likely to have been
canceled. Previously, this code would accept up to four duplicate verification
requests, then fail all subsequent ones.
* sync: add a timeout layer to block requests.
Note that if this timeout is too short, we'll bring down the peer set in a
retry storm.
* sync: restart syncing on error
Restart the syncing process when an error occurs, rather than ignoring it.
Restarting means we discard all tips and start over with a new block locator,
so we can have another chance to "unstuck" ourselves.
* sync: additional debug info
* sync: handle lookahead limit correctly.
Instead of extracting all the completed task results, the previous code pulled
results out until there were fewer tasks than the lookahead limit, then
stopped. This meant that completed tasks could be left until the limit was
exceeded again. Instead, extract all completed results, and use the number of
pending tasks to decide whether to extend the tip or wait for blocks to finish.
* network: add debug instrumentation to retry policy
* sync: instrument the spawned task
* sync: streamline ObtainTips/ExtendTips logic & tracing
This change does three things:
1. It aligns the implementation of ObtainTips and ExtendTips so that they use
the same deduplication method. This means that when debugging we only have one
deduplication algorithm to focus on.
2. It streamlines the tracing output to not include information already
included in spans. Both obtain_tips and extend_tips have their own spans
attached to the events, so it's not necessary to add Scope: prefixes in
messages.
3. It changes the messages to be focused on reporting the actual
events rather than the interpretation of the events (e.g., "got genesis hash in
response" rather than "peer could not extend tip"). The motivation for this
change is that when debugging, the interpretation of events is already known to
be incorrect, in the sense that the mental model of the code (no bug) does not
match its behavior (has bug), so presenting minimally-interpreted events forces
interpretation relative to the actual code.
* sync: hack to work around zcashd behavior
* sync: localize debug statement in extend_tips
* sync: change algorithm to define tips as pairs of hashes.
This is different enough from the existing description that its comments no
longer apply, so I removed them. A further chunk of work is to change the sync
RFC to document this algorithm.
* sync: reduce block timeout
* state: add resource limits for sled
Closes #888
* sync: add a restart timeout constant
* sync: de-pub constants
2020-08-12 16:48:01 -07:00
|
|
|
Config {
|
|
|
|
cache_dir,
|
|
|
|
..Config::default()
|
|
|
|
},
|
|
|
|
network,
|
|
|
|
);
|
2020-06-22 21:31:44 -07:00
|
|
|
let transcript = Transcript::from(transcript_data.iter().cloned());
|
2020-07-17 15:19:00 -07:00
|
|
|
/// SPANDOC: check the on disk service against the transcript
|
2020-06-22 21:31:44 -07:00
|
|
|
transcript.check(service).await?;
|
|
|
|
// Delete the contents of the temp directory before going to the next case.
|
|
|
|
std::mem::drop(storage_guard);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|