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

LedgerDb syncing #223

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion full-service/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ fn main() {
.expect("Failed creating ReqwestTransactionsFetcher");

// Create the ledger_db.
let ledger_db = config.create_or_open_ledger_db(&logger, &transactions_fetcher);
let ledger_db = config.ledger_db_config.create_or_open_ledger_db(
&transactions_fetcher,
config.offline,
&logger,
);

// Start ledger sync thread unless running in offline mode.
let _ledger_sync_service_thread = if config.offline {
Expand Down
224 changes: 117 additions & 107 deletions full-service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,8 @@ pub struct APIConfig {
#[structopt(long, parse(from_os_str))]
pub wallet_db: PathBuf,

/// Path to LedgerDB
#[structopt(long, parse(from_os_str))]
pub ledger_db: PathBuf,

/// Path to existing ledger db that contains the origin block, used when
/// initializing new ledger dbs.
#[structopt(long)]
pub ledger_db_bootstrap: Option<String>,
#[structopt(flatten)]
pub ledger_db_config: LedgerDbConfig,

#[structopt(flatten)]
pub peers_config: PeersConfig,
Expand Down Expand Up @@ -184,105 +178,6 @@ impl APIConfig {
})
}

pub fn create_or_open_ledger_db(
&self,
logger: &Logger,
transactions_fetcher: &ReqwestTransactionsFetcher,
) -> LedgerDB {
// Attempt to open the ledger and see if it has anything in it.
if let Ok(ledger_db) = LedgerDB::open(&self.ledger_db) {
if let Ok(num_blocks) = ledger_db.num_blocks() {
if num_blocks > 0 {
// Successfully opened a ledger that has blocks in it.
log::info!(
logger,
"Ledger DB {:?} opened: num_blocks={} num_txos={}",
self.ledger_db,
num_blocks,
ledger_db.num_txos().expect("Failed getting number of txos")
);
return ledger_db;
}
}
}

// Ledger doesn't exist, or is empty. Copy a bootstrapped ledger or try and get
// it from the network.
let ledger_db_file = Path::new(&self.ledger_db).join("data.mdb");
match &self.ledger_db_bootstrap {
Some(ledger_db_bootstrap) => {
log::debug!(
logger,
"Ledger DB {:?} does not exist, copying from {}",
self.ledger_db,
ledger_db_bootstrap
);

// Try and create directory in case it doesn't exist. We need it to exist before
// we can copy the data.mdb file.
if !Path::new(&self.ledger_db).exists() {
std::fs::create_dir_all(self.ledger_db.clone()).unwrap_or_else(|_| {
panic!("Failed creating directory {:?}", self.ledger_db)
});
}

let src = format!("{}/data.mdb", ledger_db_bootstrap);
std::fs::copy(src.clone(), ledger_db_file.clone()).unwrap_or_else(|_| {
panic!(
"Failed copying ledger from {} into directory {}",
src,
ledger_db_file.display()
)
});
}
None => {
std::fs::create_dir_all(self.ledger_db.clone())
.expect("Could not create ledger dir");
LedgerDB::create(&self.ledger_db).expect("Could not create ledger_db");
if !self.offline {
log::info!(
logger,
"Ledger DB {:?} does not exist, bootstrapping from peer, this may take a few minutes",
self.ledger_db
);
let block_data = transactions_fetcher
.get_origin_block_and_transactions()
.expect("Failed to download initial transactions");
let mut db = LedgerDB::open(&self.ledger_db).expect("Could not open ledger_db");
db.append_block(
block_data.block(),
block_data.contents(),
block_data.signature().clone(),
)
.expect("Failed to appened initial transactions");
log::info!(logger, "Bootstrapping completed!");
}
}
}

// Open ledger and verify it has (at least) the origin block.
log::debug!(logger, "Opening Ledger DB {:?}", self.ledger_db);
let ledger_db = LedgerDB::open(&self.ledger_db)
.unwrap_or_else(|_| panic!("Could not open ledger db inside {:?}", self.ledger_db));

let num_blocks = ledger_db
.num_blocks()
.expect("Failed getting number of blocks");
if num_blocks == 0 {
log::info!(logger, "Ledger DB is empty. You can still perform some wallet actions, such as creating addresses, but you will not be able to sync Txos.");
}

log::info!(
logger,
"Ledger DB {:?} opened: num_blocks={} num_txos={}",
self.ledger_db,
num_blocks,
ledger_db.num_txos().expect("Failed getting number of txos")
);

ledger_db
}

/// Ensure local IP address is valid.
///
/// Uses ipinfo.io for getting details about IP address.
Expand Down Expand Up @@ -428,3 +323,118 @@ impl PeersConfig {
ConnectionManager::new(peers, logger.clone())
}
}

#[derive(Clone, Debug, StructOpt)]
#[structopt()]
pub struct LedgerDbConfig {
/// Path to LedgerDB
#[structopt(long, parse(from_os_str))]
pub ledger_db: PathBuf,

/// Path to existing ledger db that contains the origin block, used when
/// initializing new ledger dbs.
#[structopt(long)]
pub ledger_db_bootstrap: Option<String>,
}

impl LedgerDbConfig {
pub fn create_or_open_ledger_db(
&self,
transactions_fetcher: &ReqwestTransactionsFetcher,
offline: bool,
logger: &Logger,
) -> LedgerDB {
// Attempt to open the ledger and see if it has anything in it.
if let Ok(ledger_db) = LedgerDB::open(&self.ledger_db) {
if let Ok(num_blocks) = ledger_db.num_blocks() {
if num_blocks > 0 {
// Successfully opened a ledger that has blocks in it.
log::info!(
logger,
"Ledger DB {:?} opened: num_blocks={} num_txos={}",
self.ledger_db,
num_blocks,
ledger_db.num_txos().expect("Failed getting number of txos")
);
return ledger_db;
}
}
}

// Ledger doesn't exist, or is empty. Copy a bootstrapped ledger or try and get
// it from the network.
let ledger_db_file = Path::new(&self.ledger_db).join("data.mdb");
match &self.ledger_db_bootstrap {
Some(ledger_db_bootstrap) => {
log::debug!(
logger,
"Ledger DB {:?} does not exist, copying from {}",
self.ledger_db,
ledger_db_bootstrap
);

// Try and create directory in case it doesn't exist. We need it to exist before
// we can copy the data.mdb file.
if !Path::new(&self.ledger_db).exists() {
std::fs::create_dir_all(self.ledger_db.clone()).unwrap_or_else(|_| {
panic!("Failed creating directory {:?}", self.ledger_db)
});
}

let src = format!("{}/data.mdb", ledger_db_bootstrap);
std::fs::copy(src.clone(), ledger_db_file.clone()).unwrap_or_else(|_| {
panic!(
"Failed copying ledger from {} into directory {}",
src,
ledger_db_file.display()
)
});
}
None => {
std::fs::create_dir_all(self.ledger_db.clone())
.expect("Could not create ledger dir");
LedgerDB::create(&self.ledger_db).expect("Could not create ledger_db");
if !offline {
log::info!(
logger,
"Ledger DB {:?} does not exist, bootstrapping from peer, this may take a few minutes",
self.ledger_db
);
let block_data = transactions_fetcher
.get_origin_block_and_transactions()
.expect("Failed to download initial transactions");
let mut db = LedgerDB::open(&self.ledger_db).expect("Could not open ledger_db");
db.append_block(
block_data.block(),
block_data.contents(),
block_data.signature().clone(),
)
.expect("Failed to appened initial transactions");
log::info!(logger, "Bootstrapping completed!");
}
}
}

// Open ledger and verify it has (at least) the origin block.
log::debug!(logger, "Opening Ledger DB {:?}", self.ledger_db);
let ledger_db = LedgerDB::open(&self.ledger_db)
.unwrap_or_else(|_| panic!("Could not open ledger db inside {:?}", self.ledger_db));

let num_blocks = ledger_db
.num_blocks()
.expect("Failed getting number of blocks");
if num_blocks == 0 {
log::info!(logger, "Ledger DB is empty. You can still perform some wallet actions, such as creating addresses, but you will not be able to sync Txos.");
}

log::info!(
logger,
"Ledger DB {:?} opened: num_blocks={} num_txos={}",
self.ledger_db,
num_blocks,
ledger_db.num_txos().expect("Failed getting number of txos")
);

ledger_db
}
}
3 changes: 3 additions & 0 deletions validator/service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ path = "src/bin/main.rs"
mc-full-service = { path = "../../full-service"}
mc-validator-api = { path = "../api" }

mc-attest-verifier = { path = "../../mobilecoin/attest/verifier" }
mc-common = { path = "../../mobilecoin/common", default-features = false, features = ["loggers"] }
mc-consensus-enclave-measurement = { path = "../../mobilecoin/consensus/enclave/measurement" }
mc-ledger-sync = { path = "../../mobilecoin/ledger/sync" }
mc-util-grpc = { path = "../../mobilecoin/util/grpc" }
mc-util-parse = { path = "../../mobilecoin/util/parse" }
mc-util-uri = { path = "../../mobilecoin/util/uri" }
Expand Down
46 changes: 46 additions & 0 deletions validator/service/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

//! The entrypoint for the Ledger Validator Service.

use mc_attest_verifier::{MrSignerVerifier, Verifier, DEBUG_ENCLAVE};
use mc_common::logger::{create_app_logger, log, o};
use mc_ledger_sync::{LedgerSyncServiceThread, PollingNetworkState, ReqwestTransactionsFetcher};
use mc_validator_service::{Config, Service};
use std::sync::{Arc, RwLock};
use structopt::StructOpt;

fn main() {
Expand All @@ -16,6 +19,49 @@ fn main() {

log::info!(logger, "Read Configs: {:?}", config);

// Create enclave verifier.
let mut mr_signer_verifier =
MrSignerVerifier::from(mc_consensus_enclave_measurement::sigstruct());
mr_signer_verifier.allow_hardening_advisory("INTEL-SA-00334");

let mut verifier = Verifier::default();
verifier.mr_signer(mr_signer_verifier).debug(DEBUG_ENCLAVE);

log::debug!(logger, "Verifier: {:?}", verifier);

// Create peer manager.
let peer_manager = config.peers_config.create_peer_manager(verifier, &logger);

// Create network state, transactions fetcher and ledger sync.
let network_state = Arc::new(RwLock::new(PollingNetworkState::new(
config.peers_config.quorum_set(),
peer_manager.clone(),
logger.clone(),
)));

let transactions_fetcher = ReqwestTransactionsFetcher::new(
config
.peers_config
.tx_source_urls
.clone()
.unwrap_or_default(),
logger.clone(),
)
.expect("Failed creating ReqwestTransactionsFetcher");

// Create the ledger_db.
let ledger_db = config.ledger_db_config.create_or_open_ledger_db(&transactions_fetcher, false, &logger);

// Start ledger sync thread.
let _ledger_sync_service_thread = LedgerSyncServiceThread::new(
ledger_db.clone(),
peer_manager.clone(),
network_state.clone(),
transactions_fetcher,
config.poll_interval,
logger.clone(),
);

// Start GRPC service.
let _service = Service::new(&config.listen_uri, logger);

Expand Down
17 changes: 5 additions & 12 deletions validator/service/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use mc_full_service::config::PeersConfig;
use mc_full_service::config::{LedgerDbConfig, PeersConfig};
use mc_util_parse::parse_duration_in_seconds;
use mc_validator_api::ValidatorUri;
use std::{path::PathBuf, time::Duration};
use std::time::Duration;
use structopt::StructOpt;

/// Configuration options for the validator service
Expand All @@ -12,19 +12,12 @@ use structopt::StructOpt;
)]
pub struct Config {
/// Listening URI.
// #[structopt(long)]
#[structopt(long, default_value = "insecure-validator://127.0.0.1/")]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to note that insecure in this context means plaintext, as opposed to using TLS.
Can't have the default be TLS because of the need for a key and certificate.

pub listen_uri: ValidatorUri,

/// Path to LedgerDB.
#[structopt(long, parse(from_os_str))]
pub ledger_db: PathBuf,

/// Path to existing ledger db that contains the origin block, used when
/// initializing new ledger dbs.
#[structopt(long)]
pub ledger_db_bootstrap: Option<String>,
#[structopt(flatten)]
pub ledger_db_config: LedgerDbConfig,

/// The location for the network.toml/json configuration file.
#[structopt(flatten)]
pub peers_config: PeersConfig,

Expand Down