feature: Separate Mainnet and Testnet state
This commit is contained in:
parent
be054906ef
commit
11090dbf91
|
@ -14,6 +14,7 @@
|
|||
#![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_state")]
|
||||
#![warn(missing_docs)]
|
||||
#![allow(clippy::try_err)]
|
||||
|
||||
use color_eyre::eyre::{eyre, Report};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
@ -23,34 +24,44 @@ use tower::{Service, ServiceExt};
|
|||
use zebra_chain::{
|
||||
block::{Block, BlockHeaderHash},
|
||||
types::BlockHeight,
|
||||
Network,
|
||||
Network::*,
|
||||
};
|
||||
|
||||
pub mod in_memory;
|
||||
pub mod on_disk;
|
||||
|
||||
/// Configuration for networking code.
|
||||
/// Configuration for the state service.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
/// The root directory for the state storage
|
||||
/// The root directory for storing cached data.
|
||||
///
|
||||
/// Each network has a separate state, which is stored in "mainnet/state"
|
||||
/// and "testnet/state" subdirectories.
|
||||
pub cache_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Generate the appropriate `sled::Config` based on the provided
|
||||
/// `zebra_state::Config`.
|
||||
/// Generate the appropriate `sled::Config` for `network`, based on the
|
||||
/// provided `zebra_state::Config`.
|
||||
///
|
||||
/// # Details
|
||||
///
|
||||
/// This function should panic if the user of `zebra-state` doesn't configure
|
||||
/// a directory to store the state.
|
||||
pub(crate) fn sled_config(&self) -> sled::Config {
|
||||
pub(crate) fn sled_config(&self, network: Network) -> sled::Config {
|
||||
let net_dir = match network {
|
||||
Mainnet => "mainnet",
|
||||
Testnet => "testnet",
|
||||
};
|
||||
let path = self
|
||||
.cache_dir
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| {
|
||||
todo!("create a nice user facing error explaining how to set the cache directory")
|
||||
todo!("create a nice user facing error explaining how to set the cache directory in zebrad.toml:\n[state]\ncache_dir = '/path/to/cache-or-tmp'")
|
||||
})
|
||||
.join(net_dir)
|
||||
.join("state");
|
||||
|
||||
sled::Config::default().path(path)
|
||||
|
@ -185,12 +196,45 @@ where
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::ffi::OsStr;
|
||||
|
||||
#[test]
|
||||
fn test_path_mainnet() {
|
||||
test_path(Mainnet);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_testnet() {
|
||||
test_path(Testnet);
|
||||
}
|
||||
|
||||
/// Check the sled path for `network`.
|
||||
fn test_path(network: Network) {
|
||||
zebra_test::init();
|
||||
|
||||
let config = Config::default();
|
||||
// we can't do many useful tests on this value, because it depends on the
|
||||
// local environment and OS.
|
||||
let sled_config = config.sled_config(network);
|
||||
let mut path = sled_config.get_path();
|
||||
assert_eq!(path.file_name(), Some(OsStr::new("state")));
|
||||
assert!(path.pop());
|
||||
match network {
|
||||
Mainnet => assert_eq!(path.file_name(), Some(OsStr::new("mainnet"))),
|
||||
Testnet => assert_eq!(path.file_name(), Some(OsStr::new("testnet"))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check what happens when the config is invalid.
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_no_path() {
|
||||
zebra_test::init();
|
||||
|
||||
// We don't call `zebra_test::init` here, to silence the expected panic log
|
||||
// TODO:
|
||||
// - implement test log levels in #760
|
||||
// - call `zebra_test::init`
|
||||
// - disable all log output from this test
|
||||
let bad_config = Config { cache_dir: None };
|
||||
let _unreachable = bad_config.sled_config();
|
||||
let _unreachable = bad_config.sled_config(Mainnet);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use zebra_chain::serialization::{ZcashDeserialize, ZcashSerialize};
|
|||
use zebra_chain::{
|
||||
block::{Block, BlockHeaderHash},
|
||||
types::BlockHeight,
|
||||
Network,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -22,8 +23,8 @@ struct SledState {
|
|||
}
|
||||
|
||||
impl SledState {
|
||||
pub(crate) fn new(config: &Config) -> Self {
|
||||
let config = config.sled_config();
|
||||
pub(crate) fn new(config: &Config, network: Network) -> Self {
|
||||
let config = config.sled_config(network);
|
||||
|
||||
Self {
|
||||
storage: config.open().unwrap(),
|
||||
|
@ -94,13 +95,6 @@ impl SledState {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for SledState {
|
||||
fn default() -> Self {
|
||||
let config = crate::Config::default();
|
||||
Self::new(&config)
|
||||
}
|
||||
}
|
||||
|
||||
impl Service<Request> for SledState {
|
||||
type Response = Response;
|
||||
type Error = Error;
|
||||
|
@ -232,9 +226,12 @@ impl From<BlockHeight> for BlockQuery {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return's a type that implement's the `zebra_state::Service` using `sled`
|
||||
/// Returns a type that implements the `zebra_state::Service` using `sled`.
|
||||
///
|
||||
/// Each `network` has its own separate sled database.
|
||||
pub fn init(
|
||||
config: Config,
|
||||
network: Network,
|
||||
) -> impl Service<
|
||||
Request,
|
||||
Response = Response,
|
||||
|
@ -243,7 +240,7 @@ pub fn init(
|
|||
> + Send
|
||||
+ Clone
|
||||
+ 'static {
|
||||
Buffer::new(SledState::new(&config), 1)
|
||||
Buffer::new(SledState::new(&config, network), 1)
|
||||
}
|
||||
|
||||
type Error = Box<dyn error::Error + Send + Sync + 'static>;
|
||||
|
|
|
@ -2,7 +2,8 @@ use color_eyre::eyre::Report;
|
|||
use once_cell::sync::Lazy;
|
||||
use std::sync::Arc;
|
||||
use tempdir::TempDir;
|
||||
use zebra_chain::{block::Block, serialization::ZcashDeserialize};
|
||||
|
||||
use zebra_chain::{block::Block, serialization::ZcashDeserialize, Network, Network::*};
|
||||
use zebra_test::transcript::Transcript;
|
||||
|
||||
use zebra_state::*;
|
||||
|
@ -49,12 +50,17 @@ static GET_TIP_TRANSCRIPT: Lazy<Vec<(Request, Response)>> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_transcripts_test() -> Result<(), Report> {
|
||||
check_transcripts().await
|
||||
async fn check_transcripts_mainnet() -> Result<(), Report> {
|
||||
check_transcripts(Mainnet).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_transcripts_testnet() -> Result<(), Report> {
|
||||
check_transcripts(Testnet).await
|
||||
}
|
||||
|
||||
#[spandoc::spandoc]
|
||||
async fn check_transcripts() -> Result<(), Report> {
|
||||
async fn check_transcripts(network: Network) -> Result<(), Report> {
|
||||
zebra_test::init();
|
||||
|
||||
for transcript_data in &[&ADD_BLOCK_TRANSCRIPT, &GET_TIP_TRANSCRIPT] {
|
||||
|
@ -64,9 +70,12 @@ async fn check_transcripts() -> Result<(), Report> {
|
|||
transcript.check(service).await?;
|
||||
|
||||
let storage_guard = TempDir::new("")?;
|
||||
let service = on_disk::init(Config {
|
||||
cache_dir: Some(storage_guard.path().to_owned()),
|
||||
});
|
||||
let service = on_disk::init(
|
||||
Config {
|
||||
cache_dir: Some(storage_guard.path().to_owned()),
|
||||
},
|
||||
network,
|
||||
);
|
||||
let transcript = Transcript::from(transcript_data.iter().cloned());
|
||||
/// SPANDOC: check the on disk service against the transcript
|
||||
transcript.check(service).await?;
|
||||
|
|
|
@ -41,7 +41,7 @@ impl StartCmd {
|
|||
info!(?self, "starting to connect to the network");
|
||||
|
||||
let config = app_config();
|
||||
let state = zebra_state::on_disk::init(config.state.clone());
|
||||
let state = zebra_state::on_disk::init(config.state.clone(), config.network.network);
|
||||
let verifier = zebra_consensus::chain::init(config.network.network, state.clone()).await;
|
||||
|
||||
// The service that our node uses to respond to requests by peers
|
||||
|
|
Loading…
Reference in New Issue