mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-22 12:01:08 +03:00
1ded3f3972
* config file can now be generated by executable * rustfmt * remove now-unnecessary config defaults test * set up paths and config file creation in user's home directory * rustfmt * remove default grin.toml * add grin configuration command to spit out config file * Split configuration into wallet and server * rustfmt * Restore logging to wallet configurations * rustfmt
150 lines
4.5 KiB
Rust
150 lines
4.5 KiB
Rust
// Copyright 2018 The Grin Developers
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Temporary utility to migrate wallet data from file to a database
|
|
|
|
use keychain::{ExtKeychain, Identifier, Keychain};
|
|
use std::fs::File;
|
|
use std::io::Read;
|
|
use std::path::{Path, MAIN_SEPARATOR};
|
|
/// Migrate wallet data. Assumes current directory contains a set of wallet
|
|
/// files
|
|
use std::sync::Arc;
|
|
|
|
use error::{Error, ErrorKind};
|
|
use failure::ResultExt;
|
|
|
|
use serde_json;
|
|
|
|
use libwallet::types::WalletDetails;
|
|
use types::WalletSeed;
|
|
|
|
use libwallet::types::OutputData;
|
|
use store::{self, to_key};
|
|
|
|
const DETAIL_FILE: &'static str = "wallet.det";
|
|
const DAT_FILE: &'static str = "wallet.dat";
|
|
const SEED_FILE: &'static str = "wallet.seed";
|
|
const DB_DIR: &'static str = "db";
|
|
const OUTPUT_PREFIX: u8 = 'o' as u8;
|
|
const DERIV_PREFIX: u8 = 'd' as u8;
|
|
const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
|
|
|
|
// determine whether we have wallet files but no file wallet
|
|
pub fn needs_migrate(data_dir: &str) -> bool {
|
|
let db_path = Path::new(data_dir).join(DB_DIR);
|
|
let data_path = Path::new(data_dir).join(DAT_FILE);
|
|
if !db_path.exists() && data_path.exists() {
|
|
return true;
|
|
}
|
|
false
|
|
}
|
|
|
|
pub fn migrate(data_dir: &str, pwd: &str) -> Result<(), Error> {
|
|
let data_file_path = format!("{}{}{}", data_dir, MAIN_SEPARATOR, DAT_FILE);
|
|
let details_file_path = format!("{}{}{}", data_dir, MAIN_SEPARATOR, DETAIL_FILE);
|
|
let seed_file_path = format!("{}{}{}", data_dir, MAIN_SEPARATOR, SEED_FILE);
|
|
let outputs = read_outputs(&data_file_path)?;
|
|
let details = read_details(&details_file_path)?;
|
|
|
|
let mut file = File::open(seed_file_path).context(ErrorKind::IO)?;
|
|
let mut buffer = String::new();
|
|
file.read_to_string(&mut buffer).context(ErrorKind::IO)?;
|
|
let wallet_seed = WalletSeed::from_hex(&buffer)?;
|
|
let keychain: ExtKeychain = wallet_seed.derive_keychain(pwd)?;
|
|
let root_key_id = keychain.root_key_id();
|
|
|
|
//open db
|
|
let db_path = Path::new(data_dir).join(DB_DIR);
|
|
let lmdb_env = Arc::new(store::new_env(db_path.to_str().unwrap().to_string()));
|
|
|
|
// open store
|
|
let store = store::Store::open(lmdb_env, DB_DIR);
|
|
let batch = store.batch().unwrap();
|
|
|
|
// write
|
|
for out in outputs {
|
|
save_output(&batch, out.clone())?;
|
|
}
|
|
save_details(&batch, root_key_id, details)?;
|
|
|
|
let res = batch.commit();
|
|
if let Err(e) = res {
|
|
panic!("Unable to commit db: {:?}", e);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// save output in db
|
|
fn save_output(batch: &store::Batch, out: OutputData) -> Result<(), Error> {
|
|
let key = to_key(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec());
|
|
if let Err(e) = batch.put_ser(&key, &out) {
|
|
Err(ErrorKind::GenericError(format!(
|
|
"Error inserting output: {:?}",
|
|
e
|
|
)))?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// save details in db
|
|
fn save_details(
|
|
batch: &store::Batch,
|
|
root_key_id: Identifier,
|
|
d: WalletDetails,
|
|
) -> Result<(), Error> {
|
|
let deriv_key = to_key(DERIV_PREFIX, &mut root_key_id.to_bytes().to_vec());
|
|
let height_key = to_key(
|
|
CONFIRMED_HEIGHT_PREFIX,
|
|
&mut root_key_id.to_bytes().to_vec(),
|
|
);
|
|
if let Err(e) = batch.put_ser(&deriv_key, &d.last_child_index) {
|
|
Err(ErrorKind::GenericError(format!(
|
|
"Error saving last_child_index: {:?}",
|
|
e
|
|
)))?;
|
|
}
|
|
if let Err(e) = batch.put_ser(&height_key, &d.last_confirmed_height) {
|
|
Err(ErrorKind::GenericError(format!(
|
|
"Error saving last_confirmed_height: {:?}",
|
|
e
|
|
)))?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Read output_data vec from disk.
|
|
fn read_outputs(data_file_path: &str) -> Result<Vec<OutputData>, Error> {
|
|
let data_file = File::open(data_file_path.clone())
|
|
.context(ErrorKind::FileWallet(&"Could not open wallet file"))?;
|
|
serde_json::from_reader(data_file)
|
|
.context(ErrorKind::Format)
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
/// Read details file from disk
|
|
fn read_details(details_file_path: &str) -> Result<WalletDetails, Error> {
|
|
let details_file = File::open(details_file_path.clone())
|
|
.context(ErrorKind::FileWallet(&"Could not open wallet details file"))?;
|
|
serde_json::from_reader(details_file)
|
|
.context(ErrorKind::Format)
|
|
.map_err(|e| e.into())
|
|
}
|
|
|
|
#[ignore]
|
|
#[test]
|
|
fn migrate_db() {
|
|
let _ = migrate("test_wallet", "");
|
|
}
|