-
Notifications
You must be signed in to change notification settings - Fork 155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mc-watcher keeps log of attestation verification reports #694
Changes from 11 commits
6a584ea
ca5cce0
5c0dfa4
e8606a0
b504a11
56a0674
1f9dfdb
072ec0b
0581423
21ff645
4a3bf0d
0a1fc26
9d8f3ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,21 +7,26 @@ | |
//! blocks are synced. | ||
|
||
use mc_watcher::{ | ||
config::WatcherConfig, watcher::Watcher, watcher_db::create_or_open_rw_watcher_db, | ||
config::WatcherConfig, verification_reports_collector::VerificationReportsCollector, | ||
watcher::Watcher, watcher_db::create_or_open_rw_watcher_db, | ||
}; | ||
|
||
use mc_common::logger::{create_app_logger, o}; | ||
use mc_common::logger::{create_app_logger, log, o}; | ||
use mc_ledger_sync::ReqwestTransactionsFetcher; | ||
use std::{thread::sleep, time::Duration}; | ||
use structopt::StructOpt; | ||
|
||
const SYNC_RETRY_INTERVAL: Duration = Duration::from_secs(1); | ||
|
||
fn main() { | ||
mc_common::setup_panic_handler(); | ||
let (logger, _global_logger_guard) = create_app_logger(o!()); | ||
|
||
let config = WatcherConfig::from_args(); | ||
let sources_config = config.sources_config(); | ||
|
||
let transactions_fetcher = | ||
ReqwestTransactionsFetcher::new(config.tx_source_urls.clone(), logger.clone()) | ||
ReqwestTransactionsFetcher::new(sources_config.tx_source_urls(), logger.clone()) | ||
.expect("Failed creating ReqwestTransactionsFetcher"); | ||
|
||
let watcher_db = create_or_open_rw_watcher_db( | ||
|
@@ -30,9 +35,25 @@ fn main() { | |
logger.clone(), | ||
) | ||
.expect("Could not create or open watcher db"); | ||
let watcher = Watcher::new(watcher_db, transactions_fetcher, logger); | ||
// For now, ignore origin block, as it does not have a signature. | ||
watcher | ||
.sync_signatures(1, config.max_block_height) | ||
.expect("Could not sync signatures"); | ||
let watcher = Watcher::new(watcher_db.clone(), transactions_fetcher, logger.clone()); | ||
|
||
let _verification_reports_collector = VerificationReportsCollector::new( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now we only collect verification reports inside the |
||
watcher_db, | ||
sources_config.tx_source_urls_to_consensus_client_urls(), | ||
SYNC_RETRY_INTERVAL, | ||
logger.clone(), | ||
); | ||
|
||
loop { | ||
// For now, ignore origin block, as it does not have a signature. | ||
let syncing_done = watcher | ||
.sync_signatures(1, config.max_block_height) | ||
.expect("Could not sync signatures"); | ||
if syncing_done { | ||
log::info!(logger, "sync_signatures indicates we're done"); | ||
break; | ||
} | ||
|
||
sleep(SYNC_RETRY_INTERVAL); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,10 @@ | |
|
||
//! Configuration parameters for the watcher test utility. | ||
|
||
use std::path::PathBuf; | ||
use mc_common::HashMap; | ||
use mc_util_uri::ConsensusClientUri; | ||
use serde::{Deserialize, Serialize}; | ||
use std::{fs, iter::FromIterator, path::PathBuf}; | ||
use structopt::StructOpt; | ||
|
||
#[derive(Debug, StructOpt)] | ||
|
@@ -16,13 +19,115 @@ pub struct WatcherConfig { | |
#[structopt(long, default_value = "/tmp/watcher-db", parse(from_os_str))] | ||
pub watcher_db: PathBuf, | ||
|
||
/// URLs to use to pull blocks. | ||
/// | ||
/// For example: https://s3-us-west-1.amazonaws.com/mobilecoin.chain/node1.master.mobilecoin.com/ | ||
#[structopt(long = "tx-source-url", required = true, min_values = 1)] | ||
pub tx_source_urls: Vec<String>, | ||
/// The location of the sources.toml file. This file configures the list of block sources and | ||
/// consensus nodes that are being watched. | ||
#[structopt(long)] | ||
pub sources_path: PathBuf, | ||
|
||
/// (Optional) Number of blocks to sync | ||
#[structopt(long)] | ||
pub max_block_height: Option<u64>, | ||
} | ||
|
||
impl WatcherConfig { | ||
/// Load the sources configuration file. | ||
pub fn sources_config(&self) -> SourcesConfig { | ||
// Read configuration file. | ||
let data = fs::read_to_string(&self.sources_path) | ||
.unwrap_or_else(|err| panic!("failed reading {:?}: {:?}", self.sources_path, err)); | ||
|
||
// Parse configuration file. | ||
toml::from_str(&data) | ||
.unwrap_or_else(|err| panic!("failed TOML parsing {:?}: {:?}", self.sources_path, err)) | ||
} | ||
} | ||
|
||
/// A single watched source configuration. | ||
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)] | ||
struct SourceConfig { | ||
/// URL to use for pulling blocks. | ||
/// | ||
/// For example: https://s3-us-west-1.amazonaws.com/mobilecoin.chain/node1.master.mobilecoin.com/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would maybe put testnet URL as example |
||
tx_source_url: String, | ||
|
||
/// (Optional) Consensus node client URL to use for fetching the remote attestation report | ||
/// whenever a block signer change is detected. | ||
consensus_client_url: Option<ConsensusClientUri>, | ||
} | ||
|
||
impl SourceConfig { | ||
// Get the tx_source_url and ensure it has a trailing slash. | ||
// This is compatible with the behavior inside ReqwestTransactionsFetcher and ensures | ||
// everywhere we use URLs we always have "slash-terminated" URLs | ||
pub fn tx_source_url(&self) -> String { | ||
let mut url = self.tx_source_url.clone(); | ||
if !url.ends_with('/') { | ||
url.push_str("/"); | ||
} | ||
url | ||
} | ||
} | ||
|
||
/// Sources configuration - this configures which sources are being watched. | ||
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)] | ||
pub struct SourcesConfig { | ||
/// List of sources being watched. | ||
sources: Vec<SourceConfig>, | ||
} | ||
|
||
impl SourcesConfig { | ||
/// Returns a list of URLs that can be used to fetch block contents from. | ||
pub fn tx_source_urls(&self) -> Vec<String> { | ||
self.sources | ||
.iter() | ||
.map(|source_config| source_config.tx_source_url()) | ||
.collect() | ||
} | ||
|
||
/// Returns a map of tx source url -> consensus client url. This is used when we want to try | ||
/// and connect to the consensus block that provided some block from a given URL. | ||
pub fn tx_source_urls_to_consensus_client_urls(&self) -> HashMap<String, ConsensusClientUri> { | ||
HashMap::from_iter(self.sources.iter().filter_map(|source_config| { | ||
source_config | ||
.consensus_client_url | ||
.clone() | ||
.map(|client_url| (source_config.tx_source_url(), client_url)) | ||
})) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use std::str::FromStr; | ||
|
||
#[test] | ||
fn sources_config_toml() { | ||
let expected_config = SourcesConfig { | ||
sources: vec![ | ||
SourceConfig { | ||
tx_source_url: "https://www.source.com/".to_owned(), | ||
consensus_client_url: None, | ||
}, | ||
SourceConfig { | ||
tx_source_url: "https://www.2nd-source.com/".to_owned(), | ||
consensus_client_url: Some( | ||
ConsensusClientUri::from_str("mc://www.x.com:443/").unwrap(), | ||
), | ||
}, | ||
], | ||
}; | ||
|
||
let input_toml: &str = r#" | ||
[[sources]] | ||
tx_source_url = "https://www.source.com/" | ||
|
||
[[sources]] | ||
tx_source_url = "https://www.2nd-source.com/" | ||
consensus_client_url = "mc://www.x.com:443/" | ||
"#; | ||
let config: SourcesConfig = toml::from_str(input_toml).expect("failed parsing toml"); | ||
|
||
assert_eq!(config, expected_config); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this set here as opposed to either from config, or via using something like the retry crate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its there because realistically no-one will ever choose a different value.
retry
is inappropriate since this is actually a polling interval so the name is misleading. I'll add it to the command line config.