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")]
|
#![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_state")]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![allow(clippy::try_err)]
|
#![allow(clippy::try_err)]
|
||||||
|
|
||||||
use color_eyre::eyre::{eyre, Report};
|
use color_eyre::eyre::{eyre, Report};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
@ -23,34 +24,44 @@ use tower::{Service, ServiceExt};
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
block::{Block, BlockHeaderHash},
|
block::{Block, BlockHeaderHash},
|
||||||
types::BlockHeight,
|
types::BlockHeight,
|
||||||
|
Network,
|
||||||
|
Network::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod in_memory;
|
pub mod in_memory;
|
||||||
pub mod on_disk;
|
pub mod on_disk;
|
||||||
|
|
||||||
/// Configuration for networking code.
|
/// Configuration for the state service.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Config {
|
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>,
|
pub cache_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Generate the appropriate `sled::Config` based on the provided
|
/// Generate the appropriate `sled::Config` for `network`, based on the
|
||||||
/// `zebra_state::Config`.
|
/// provided `zebra_state::Config`.
|
||||||
///
|
///
|
||||||
/// # Details
|
/// # Details
|
||||||
///
|
///
|
||||||
/// This function should panic if the user of `zebra-state` doesn't configure
|
/// This function should panic if the user of `zebra-state` doesn't configure
|
||||||
/// a directory to store the state.
|
/// 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
|
let path = self
|
||||||
.cache_dir
|
.cache_dir
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or_else(|| {
|
.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");
|
.join("state");
|
||||||
|
|
||||||
sled::Config::default().path(path)
|
sled::Config::default().path(path)
|
||||||
|
|
@ -185,12 +196,45 @@ where
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_no_path() {
|
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 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::{
|
use zebra_chain::{
|
||||||
block::{Block, BlockHeaderHash},
|
block::{Block, BlockHeaderHash},
|
||||||
types::BlockHeight,
|
types::BlockHeight,
|
||||||
|
Network,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -22,8 +23,8 @@ struct SledState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SledState {
|
impl SledState {
|
||||||
pub(crate) fn new(config: &Config) -> Self {
|
pub(crate) fn new(config: &Config, network: Network) -> Self {
|
||||||
let config = config.sled_config();
|
let config = config.sled_config(network);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
storage: config.open().unwrap(),
|
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 {
|
impl Service<Request> for SledState {
|
||||||
type Response = Response;
|
type Response = Response;
|
||||||
type Error = Error;
|
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(
|
pub fn init(
|
||||||
config: Config,
|
config: Config,
|
||||||
|
network: Network,
|
||||||
) -> impl Service<
|
) -> impl Service<
|
||||||
Request,
|
Request,
|
||||||
Response = Response,
|
Response = Response,
|
||||||
|
|
@ -243,7 +240,7 @@ pub fn init(
|
||||||
> + Send
|
> + Send
|
||||||
+ Clone
|
+ Clone
|
||||||
+ 'static {
|
+ 'static {
|
||||||
Buffer::new(SledState::new(&config), 1)
|
Buffer::new(SledState::new(&config, network), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Error = Box<dyn error::Error + Send + Sync + 'static>;
|
type Error = Box<dyn error::Error + Send + Sync + 'static>;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ use color_eyre::eyre::Report;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tempdir::TempDir;
|
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_test::transcript::Transcript;
|
||||||
|
|
||||||
use zebra_state::*;
|
use zebra_state::*;
|
||||||
|
|
@ -49,12 +50,17 @@ static GET_TIP_TRANSCRIPT: Lazy<Vec<(Request, Response)>> = Lazy::new(|| {
|
||||||
});
|
});
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn check_transcripts_test() -> Result<(), Report> {
|
async fn check_transcripts_mainnet() -> Result<(), Report> {
|
||||||
check_transcripts().await
|
check_transcripts(Mainnet).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn check_transcripts_testnet() -> Result<(), Report> {
|
||||||
|
check_transcripts(Testnet).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[spandoc::spandoc]
|
#[spandoc::spandoc]
|
||||||
async fn check_transcripts() -> Result<(), Report> {
|
async fn check_transcripts(network: Network) -> Result<(), Report> {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
|
||||||
for transcript_data in &[&ADD_BLOCK_TRANSCRIPT, &GET_TIP_TRANSCRIPT] {
|
for transcript_data in &[&ADD_BLOCK_TRANSCRIPT, &GET_TIP_TRANSCRIPT] {
|
||||||
|
|
@ -64,9 +70,12 @@ async fn check_transcripts() -> Result<(), Report> {
|
||||||
transcript.check(service).await?;
|
transcript.check(service).await?;
|
||||||
|
|
||||||
let storage_guard = TempDir::new("")?;
|
let storage_guard = TempDir::new("")?;
|
||||||
let service = on_disk::init(Config {
|
let service = on_disk::init(
|
||||||
cache_dir: Some(storage_guard.path().to_owned()),
|
Config {
|
||||||
});
|
cache_dir: Some(storage_guard.path().to_owned()),
|
||||||
|
},
|
||||||
|
network,
|
||||||
|
);
|
||||||
let transcript = Transcript::from(transcript_data.iter().cloned());
|
let transcript = Transcript::from(transcript_data.iter().cloned());
|
||||||
/// SPANDOC: check the on disk service against the transcript
|
/// SPANDOC: check the on disk service against the transcript
|
||||||
transcript.check(service).await?;
|
transcript.check(service).await?;
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ impl StartCmd {
|
||||||
info!(?self, "starting to connect to the network");
|
info!(?self, "starting to connect to the network");
|
||||||
|
|
||||||
let config = app_config();
|
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;
|
let verifier = zebra_consensus::chain::init(config.network.network, state.clone()).await;
|
||||||
|
|
||||||
// The service that our node uses to respond to requests by peers
|
// The service that our node uses to respond to requests by peers
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue