Skip to content

Commit

Permalink
Implement non-KeyImage Functionality for Fog Ledger Router (#3084)
Browse files Browse the repository at this point in the history
* Ledger enclave support for router and store (#2896)

* Pulling changes in from milliec/ledger-router-dev

* Run cargo fmt

* Making requested changes and clarifications to Fog ledger router comments.

* Additional comment fixes

* Fix CI lint

* PR feedback nits

Co-authored-by: Andrew Wygle <andrew@mobilecoin.com>

* Fog Ledger Router Admin service

* Sort itertools properly in Cargo.toml

* Key Image Router Server + Binary

* Update router config for parameterized retries

* Changes due to rebase

* normalize naming - ledger router, key image store

* Linting fixes

* Accept code review suggestions

* Updates for GRPCIO 0.12

* Pulling changes in from milliec/ledger-router-dev

* Making requested changes and clarifications to Fog ledger router comments.

* PR feedback nits

* Key Image Router Service

* Update fog/ledger/server/src/key_image_router_service.rs

Co-authored-by: Nick Santana <nick@mobilecoin.com>

* Address PR feedback around logging and comments.

* Parameterize allowed number of retries for query loop

* Fog Ledger Router Admin service

* Sort itertools properly in Cargo.toml

* Key Image Router Server + Binary

* Key image store changes pulled in from milliec/ledger-router-dev

* Cargo fmt

* Run clippy

* Sort itertools properly in Cargo.toml

* Rebase and update to match current fog ledger router branch

* Implement ShardingStrategy into DbFetcher

* Add a DbFetcher to the ledger store server.

* Run cargo fmt

* Other clippy and fmt changes

* Sort dependencies

* Remove unimplemented! that snuck in from other branch

* Update and sync with latest Fog ledger router

* Refactor router dispatch into match statement

Uses ugly names from rust-protobuf. rust-protobuf version 3.* will do
the Rusty thing and put the generated enums into modules, but we're on
version 2.* and they do the C thing of really_long_snake_case_names.

* Add merkle proof service to router server

* Add untrusted tx out service to router server

* Add block service to router server

* Fixups from rebase

---------

Co-authored-by: Emily C <gyrocoder@gmail.com>
Co-authored-by: Nick Santana <nick@mobilecoin.com>
  • Loading branch information
3 people committed Mar 28, 2023
1 parent dfa338f commit 49d0990
Show file tree
Hide file tree
Showing 9 changed files with 656 additions and 30 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions fog/ledger/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ mc-blockchain-test-utils = { path = "../../../blockchain/test-utils" }
mc-common = { path = "../../../common", features = ["loggers"] }
mc-crypto-keys = { path = "../../../crypto/keys" }
mc-crypto-rand = { path = "../../../crypto/rand" }
mc-crypto-x509-test-vectors = { path = "../../../crypto/x509/test-vectors" }
mc-util-keyfile = { path = "../../../util/keyfile" }
mc-util-test-helper = { path = "../../../util/test-helper" }
mc-util-uri = { path = "../../../util/uri" }

Expand All @@ -93,5 +95,8 @@ mc-fog-test-infra = { path = "../../test_infra" }
# third-party
tempfile = "3.4"
aes-gcm = "0.10.1"
pem = "1.1"
portpicker = "0.1.1"
sha2 = "0.10"
tempdir = "0.3"
x509-signature = "0.5"
17 changes: 14 additions & 3 deletions fog/ledger/server/src/bin/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ use mc_fog_api::ledger_grpc::KeyImageStoreApiClient;
use mc_fog_ledger_enclave::{LedgerSgxEnclave, ENCLAVE_FILE};
use mc_fog_ledger_server::{LedgerRouterConfig, LedgerRouterServer};
use mc_fog_uri::{KeyImageStoreScheme, KeyImageStoreUri};

use mc_ledger_db::LedgerDB;
use mc_util_grpc::ConnectionUriGrpcioChannel;
use mc_util_uri::UriScheme;
use mc_watcher::watcher_db::WatcherDB;

fn main() {
let (logger, _global_logger_guard) =
Expand Down Expand Up @@ -78,8 +79,18 @@ fn main() {
}
let ledger_store_grpc_clients = Arc::new(RwLock::new(ledger_store_grpc_clients));

let mut router_server =
LedgerRouterServer::new(config, enclave, ledger_store_grpc_clients, logger);
let ledger_db = LedgerDB::open(&config.ledger_db).expect("Could not read ledger DB");
let watcher_db =
WatcherDB::open_ro(&config.watcher_db, logger.clone()).expect("Could not open watcher DB");

let mut router_server = LedgerRouterServer::new(
config,
enclave,
ledger_store_grpc_clients,
ledger_db,
watcher_db,
logger,
);
router_server.start();

loop {
Expand Down
23 changes: 23 additions & 0 deletions fog/ledger/server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ pub struct LedgerServerConfig {
#[derive(Clone, Parser, Serialize)]
#[clap(version)]
pub struct LedgerRouterConfig {
/// The chain id of the network we are a part of
#[clap(long, env = "MC_CHAIN_ID")]
pub chain_id: String,

/// The ID with which to respond to client attestation requests.
///
/// This ID needs to match the host:port clients use in their URI when
Expand All @@ -102,6 +106,25 @@ pub struct LedgerRouterConfig {
#[clap(long, default_value = "3")]
pub query_retries: usize,

/// Enables authenticating client requests using Authorization tokens using
/// the provided hex-encoded 32 bytes shared secret.
#[clap(long, value_parser = mc_util_parse::parse_hex::<[u8; 32]>, env = "MC_CLIENT_AUTH_TOKEN_SECRET")]
pub client_auth_token_secret: Option<[u8; 32]>,

/// Maximal client authentication token lifetime, in seconds (only relevant
/// when --client-auth-token-secret is used. Defaults to 86400 - 24
/// hours).
#[clap(long, default_value = "86400", value_parser = parse_duration_in_seconds, env = "MC_CLIENT_AUTH_TOKEN_MAX_LIFETIME")]
pub client_auth_token_max_lifetime: Duration,

/// Path to ledger db (lmdb)
#[clap(long, env = "MC_LEDGER_DB")]
pub ledger_db: PathBuf,

/// Path to watcher db (lmdb) - includes block timestamps
#[clap(long, env = "MC_WATCHER_DB")]
pub watcher_db: PathBuf,

// TODO: Add store instance uris which are of type Vec<FogLedgerStoreUri>.
/// The capacity to build the OMAP (ORAM hash table) with.
/// About 75% of this capacity can be used.
Expand Down
117 changes: 117 additions & 0 deletions fog/ledger/server/src/key_image_router_server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) 2018-2022 The MobileCoin Foundation

use std::{
collections::HashMap,
sync::{Arc, RwLock},
};

use futures::executor::block_on;
use mc_common::logger::{log, Logger};
use mc_fog_api::ledger_grpc;
use mc_fog_ledger_enclave::LedgerEnclaveProxy;
use mc_fog_uri::{ConnectionUri, KeyImageStoreUri};
use mc_util_grpc::{ConnectionUriGrpcioServer, ReadinessIndicator};

use crate::{
config::LedgerRouterConfig, key_image_router_service::KeyImageRouterService,
router_admin_service::LedgerRouterAdminService,
};

pub struct KeyImageRouterServer {
router_server: grpcio::Server,
admin_server: grpcio::Server,
logger: Logger,
}

impl KeyImageRouterServer {
pub fn new<E>(
config: LedgerRouterConfig,
enclave: E,
shards: Arc<RwLock<HashMap<KeyImageStoreUri, Arc<ledger_grpc::KeyImageStoreApiClient>>>>,
logger: Logger,
) -> KeyImageRouterServer
where
E: LedgerEnclaveProxy,
{
let readiness_indicator = ReadinessIndicator::default();

let env = Arc::new(
grpcio::EnvBuilder::new()
.name_prefix("key-image-router-server".to_string())
.build(),
);

// Health check service - will be used in both cases
let health_service =
mc_util_grpc::HealthService::new(Some(readiness_indicator.into()), logger.clone())
.into_service();

// Build our router server.
// Init ledger router service.
let ledger_router_service = ledger_grpc::create_ledger_api(KeyImageRouterService::new(
enclave,
shards.clone(),
logger.clone(),
));
log::debug!(logger, "Constructed Key Image Router GRPC Service");

// Init ledger router admin service.
let ledger_router_admin_service = ledger_grpc::create_ledger_router_admin_api(
LedgerRouterAdminService::new(shards, logger.clone()),
);
log::debug!(logger, "Constructed Key Image Router Admin GRPC Service");

// Package service into grpc server
log::info!(
logger,
"Starting Key Image Router server on {}",
config.client_listen_uri.addr(),
);

let router_server_builder = grpcio::ServerBuilder::new(env.clone())
.register_service(ledger_router_service)
.register_service(health_service)
.bind_using_uri(&config.client_listen_uri, logger.clone());
let admin_server_builder = grpcio::ServerBuilder::new(env)
.register_service(ledger_router_admin_service)
.bind_using_uri(&config.admin_listen_uri, logger.clone());

let router_server = router_server_builder.build().unwrap();
let admin_server = admin_server_builder.build().unwrap();

Self {
router_server,
admin_server,
logger,
}
}

/// Starts the server
pub fn start(&mut self) {
self.router_server.start();
for (host, port) in self.router_server.bind_addrs() {
log::info!(self.logger, "Router API listening on {}:{}", host, port);
}
self.admin_server.start();
for (host, port) in self.admin_server.bind_addrs() {
log::info!(
self.logger,
"Router Admin API listening on {}:{}",
host,
port
);
}
}

/// Stops the server
pub fn stop(&mut self) {
block_on(self.router_server.shutdown()).expect("Could not stop router grpc server");
block_on(self.admin_server.shutdown()).expect("Could not stop router admin grpc server");
}
}

impl Drop for KeyImageRouterServer {
fn drop(&mut self) {
self.stop();
}
}
86 changes: 86 additions & 0 deletions fog/ledger/server/src/key_image_router_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) 2018-2022 The MobileCoin Foundation

use std::{
collections::HashMap,
sync::{Arc, RwLock},
};

use futures::{FutureExt, TryFutureExt};
use grpcio::{DuplexSink, RequestStream, RpcContext};
use mc_common::logger::{log, Logger};
use mc_fog_api::{
ledger::{LedgerRequest, LedgerResponse},
ledger_grpc::{self, LedgerApi},
};
use mc_fog_ledger_enclave::LedgerEnclaveProxy;
use mc_fog_uri::KeyImageStoreUri;
use mc_util_grpc::rpc_logger;
use mc_util_metrics::SVC_COUNTERS;

use crate::router_handlers;

#[derive(Clone)]
pub struct KeyImageRouterService<E>
where
E: LedgerEnclaveProxy,
{
enclave: E,
shards: Arc<RwLock<HashMap<KeyImageStoreUri, Arc<ledger_grpc::KeyImageStoreApiClient>>>>,
query_retries: usize,
logger: Logger,
}

impl<E: LedgerEnclaveProxy> KeyImageRouterService<E> {
/// Creates a new LedgerRouterService that can be used by a gRPC server to
/// fulfill gRPC requests.
#[allow(dead_code)] // FIXME
pub fn new(
enclave: E,
shards: Arc<RwLock<HashMap<KeyImageStoreUri, Arc<ledger_grpc::KeyImageStoreApiClient>>>>,
query_retries: usize,
logger: Logger,
) -> Self {
Self {
enclave,
shards,
query_retries,
logger,
}
}
}

impl<E> LedgerApi for KeyImageRouterService<E>
where
E: LedgerEnclaveProxy,
{
fn request(
&mut self,
ctx: RpcContext,
requests: RequestStream<LedgerRequest>,
responses: DuplexSink<LedgerResponse>,
) {
let _timer = SVC_COUNTERS.req(&ctx);
mc_common::logger::scoped_global_logger(&rpc_logger(&ctx, &self.logger), |logger| {
log::warn!(
self.logger,
"Streaming GRPC Ledger API only partially implemented."
);
let logger = logger.clone();

let shards = self.shards.read().expect("RwLock poisoned");
let future = router_handlers::handle_requests(
shards.values().cloned().collect(),
self.enclave.clone(),
requests,
responses,
self.query_retries,
logger.clone(),
)
.map_err(move |err| log::error!(&logger, "failed to reply: {}", err))
// TODO: Do more with the error than just push it to the log.
.map(|_| ());

ctx.spawn(future)
});
}
}
41 changes: 18 additions & 23 deletions fog/ledger/server/src/router_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use mc_common::{
};
use mc_fog_api::{
ledger::{
LedgerRequest, LedgerResponse, MultiKeyImageStoreRequest, MultiKeyImageStoreResponse,
MultiKeyImageStoreResponseStatus,
LedgerRequest, LedgerRequest_oneof_request_data, LedgerResponse, MultiKeyImageStoreRequest,
MultiKeyImageStoreResponse, MultiKeyImageStoreResponseStatus,
},
ledger_grpc::KeyImageStoreApiClient,
};
Expand Down Expand Up @@ -55,7 +55,7 @@ where
/// Handles a client's request by performing either an authentication or a
/// query.
pub async fn handle_request<E>(
mut request: LedgerRequest,
request: LedgerRequest,
shard_clients: Vec<Arc<KeyImageStoreApiClient>>,
enclave: E,
query_retries: usize,
Expand All @@ -64,26 +64,21 @@ pub async fn handle_request<E>(
where
E: LedgerEnclaveProxy,
{
if request.has_auth() {
handle_auth_request(enclave, request.take_auth(), logger)
} else if request.has_check_key_images() {
handle_query_request(
request.take_check_key_images(),
enclave,
shard_clients,
query_retries,
logger,
)
.await
// TODO: Handle other cases here as they are added, such as the merkele
// proof service.
} else {
let rpc_status = rpc_invalid_arg_error(
"Inavlid LedgerRequest request",
"Neither the check_key_images nor auth fields were set".to_string(),
&logger,
);
Err(rpc_status)
match request.request_data {
Some(LedgerRequest_oneof_request_data::auth(request)) => {
handle_auth_request(enclave, request, logger)
}
Some(LedgerRequest_oneof_request_data::check_key_images(request)) => {
handle_query_request(request, enclave, shard_clients, query_retries, logger).await
}
None => {
let rpc_status = rpc_invalid_arg_error(
"Inavlid LedgerRequest request",
"Neither the check_key_images nor auth fields were set".to_string(),
&logger,
);
Err(rpc_status)
}
}
}

Expand Down
Loading

0 comments on commit 49d0990

Please sign in to comment.