Skip to content
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

Add config option for sharding strategy #2352

Merged
merged 1 commit into from
Aug 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions fog/types/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2018-2022 The MobileCoin Foundation

use alloc::{format, string::String, vec::Vec};
use core::str::FromStr;
use prost::Message;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -45,9 +47,31 @@ impl core::fmt::Display for BlockRange {
}
}

impl FromStr for BlockRange {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let block_indices: Vec<u64> = s
.split(',')
.map(|index_str| index_str.trim().parse())
.collect::<Result<Vec<_>, _>>()
.map_err(|_| "BlockRange index is not a number.")?;
if block_indices.len() != 2 {
return Err(format!(
"Block range is composed of two indices, found {} indices",
block_indices.len()
));
}
let result = BlockRange::new(block_indices[0], block_indices[1]);

Ok(result)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_contains() {
let range = BlockRange::new(10, 13);
Expand Down Expand Up @@ -87,4 +111,55 @@ mod tests {
assert!(!range.overlaps(&BlockRange::new(0, 10)));
assert!(!range.overlaps(&BlockRange::new(13, 100)));
}

#[test]
fn from_string_well_formatted_creates_block_range() {
let start_block = 0;
let end_block = 10;
let block_range_str = format!("{},{}", start_block, end_block);

let result = BlockRange::from_str(&block_range_str);

assert!(result.is_ok());
let block_range = result.unwrap();
assert_eq!(block_range.start_block, start_block);
assert_eq!(block_range.end_block, end_block);
}

#[test]
fn from_string_well_formatted_with_whitespace_creates_block_range() {
let start_block = 0;
let end_block = 10;
let block_range_str = format!(" {} , {} ", start_block, end_block);

let result = BlockRange::from_str(&block_range_str);

assert!(result.is_ok());
let block_range = result.unwrap();
assert_eq!(block_range.start_block, start_block);
assert_eq!(block_range.end_block, end_block);
}

#[test]
fn from_string_multiple_indices_errors() {
let start_block = 0;
let end_block = 10;
let third_block = 10;
let block_range_str = format!("{},{},{}", start_block, end_block, third_block);

let result = BlockRange::from_str(&block_range_str);

assert!(result.is_err());
}

#[test]
fn from_string_non_numbers_errors() {
let start_block = 'a';
let end_block = 'b';
let block_range_str = format!("{},{}", start_block, end_block);

let result = BlockRange::from_str(&block_range_str);

assert!(result.is_err());
}
}
10 changes: 4 additions & 6 deletions fog/view/server/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ use mc_attest_net::{Client, RaClient};
use mc_common::{logger::log, time::SystemTimeProvider};
use mc_fog_sql_recovery_db::SqlRecoveryDb;
use mc_fog_view_enclave::{SgxViewEnclave, ENCLAVE_FILE};
use mc_fog_view_server::{
config::MobileAcctViewConfig, server::ViewServer, sharding_strategy::EpochShardingStrategy,
};
use mc_fog_view_server::{config, config::MobileAcctViewConfig, server::ViewServer};
use mc_util_cli::ParserWithBuildInfo;
use mc_util_grpc::AdminServer;
use std::{env, sync::Arc};
Expand Down Expand Up @@ -60,15 +58,15 @@ fn main() {

let ias_client = Client::new(&config.ias_api_key).expect("Could not create IAS client");

let config::ShardingStrategy::Epoch(sharding_strategy) = config.sharding_strategy.clone();

let mut server = ViewServer::new(
config.clone(),
sgx_enclave,
recovery_db,
ias_client,
SystemTimeProvider::default(),
// TODO: Change the EpochShardingStrategy to incorporate config values that specify
// start and end block indices. See PR #2352
EpochShardingStrategy::default(),
sharding_strategy,
logger.clone(),
);
server.start();
Expand Down
29 changes: 28 additions & 1 deletion fog/view/server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

//! Configuration parameters for the MobileCoin Fog View Node
#![deny(missing_docs)]

use crate::sharding_strategy::EpochShardingStrategy;
use clap::Parser;
use mc_attest_core::ProviderId;
use mc_common::ResponderId;
Expand Down Expand Up @@ -67,6 +67,33 @@ pub struct MobileAcctViewConfig {
/// Postgres config
#[clap(flatten)]
pub postgres_config: SqlRecoveryDbConnectionConfig,

/// Determines which group of TxOuts the Fog View Store instance will
/// process.
#[clap(long, default_value = "default")]
pub sharding_strategy: ShardingStrategy,
}

/// Determines which group of TxOuts the Fog View Store instance will process.
#[derive(Clone, Serialize)]
pub enum ShardingStrategy {
/// URI used by the FogViewServer when fulfilling direct client requests.
Epoch(EpochShardingStrategy),
}

impl FromStr for ShardingStrategy {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.eq("default") {
return Ok(ShardingStrategy::Epoch(EpochShardingStrategy::default()));
}
if let Ok(epoch_sharding_strategy) = EpochShardingStrategy::from_str(s) {
return Ok(ShardingStrategy::Epoch(epoch_sharding_strategy));
}

Err("Invalid sharding strategy config.".to_string())
}
}

/// A FogViewServer can either fulfill client requests directly or fulfill Fog
Expand Down
16 changes: 15 additions & 1 deletion fog/view/server/src/sharding_strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

use mc_blockchain_types::BlockIndex;
use mc_fog_types::common::BlockRange;
use serde::Serialize;
use std::str::FromStr;

/// Tells a Fog View Store for which blocks it should process TxOuts.
pub trait ShardingStrategy {
Expand All @@ -20,7 +22,7 @@ pub trait ShardingStrategy {
///
/// In practice, the set of Fog View Shards will contain overlapping
/// [epoch_block_ranges] in order to obfuscate which shard processed the TxOuts.
#[derive(Clone)]
#[derive(Clone, Serialize)]
pub struct EpochShardingStrategy {
/// If a block falls within this range, then the Fog View Store should
/// process its TxOuts.
Expand Down Expand Up @@ -48,6 +50,18 @@ impl EpochShardingStrategy {
}
}

impl FromStr for EpochShardingStrategy {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(block_range) = BlockRange::from_str(s) {
return Ok(Self::new(block_range));
}

Err("Invalid epoch sharding strategy.".to_string())
}
}

#[cfg(test)]
mod epoch_sharding_strategy_tests {
use super::*;
Expand Down
3 changes: 2 additions & 1 deletion fog/view/server/tests/smoke_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use mc_fog_view_connection::FogViewGrpcClient;
use mc_fog_view_enclave::SgxViewEnclave;
use mc_fog_view_protocol::FogViewConnection;
use mc_fog_view_server::{
config::{ClientListenUri::ClientFacing, MobileAcctViewConfig as ViewConfig},
config::{ClientListenUri::ClientFacing, MobileAcctViewConfig as ViewConfig, ShardingStrategy},
server::ViewServer,
sharding_strategy::EpochShardingStrategy,
};
Expand Down Expand Up @@ -72,6 +72,7 @@ fn get_test_environment(
ias_api_key: Default::default(),
admin_listen_uri: Default::default(),
client_auth_token_max_lifetime: Default::default(),
sharding_strategy: ShardingStrategy::Epoch(EpochShardingStrategy::default()),
postgres_config: Default::default(),
};

Expand Down