diff --git a/ethcore/src/migrations/extras/mod.rs b/ethcore/src/migrations/extras/mod.rs index c4d4790dc..28bbb2856 100644 --- a/ethcore/src/migrations/extras/mod.rs +++ b/ethcore/src/migrations/extras/mod.rs @@ -2,4 +2,4 @@ mod v6; -pub use self::v6::ToV6; +pub use self::v6::ToV6; \ No newline at end of file diff --git a/ethcore/src/migrations/mod.rs b/ethcore/src/migrations/mod.rs index 1473ced9c..6d86a122f 100644 --- a/ethcore/src/migrations/mod.rs +++ b/ethcore/src/migrations/mod.rs @@ -1,3 +1,4 @@ //! Database migrations. pub mod extras; +pub mod state; diff --git a/ethcore/src/migrations/state/mod.rs b/ethcore/src/migrations/state/mod.rs new file mode 100644 index 000000000..88d4369a2 --- /dev/null +++ b/ethcore/src/migrations/state/mod.rs @@ -0,0 +1,5 @@ +//! State database migrations. + +mod v7; + +pub use self::v7::ToV7; \ No newline at end of file diff --git a/ethcore/src/migrations/state/v7.rs b/ethcore/src/migrations/state/v7.rs new file mode 100644 index 000000000..aadf9ac62 --- /dev/null +++ b/ethcore/src/migrations/state/v7.rs @@ -0,0 +1,31 @@ +use util::hash::{FixedHash, H256}; +use util::migration::Migration; +use util::sha3::Hashable; + +/// This migration migrates the state db to use an accountdb which ensures uniqueness +/// using an address' hash as opposed to the address itself. +pub struct ToV7; + +impl Migration for ToV7 { + fn version(&self) -> u32 { + 7 + } + + fn simple_migrate(&self, mut key: Vec, value: Vec) -> Option<(Vec, Vec)> { + let val_hash = value.sha3(); + assert!(key.len() == 32); // all keys in the state db are hashes. + let key_h = H256::from_slice(&key[..]); + if key_h != val_hash { + // this is a key which has been xor'd with an address. + // recover the address + let address = key_h ^ val_hash; + let address_hash = address.sha3(); + + let new_key = address_hash ^ val_hash; + key.copy_from_slice(&new_key[..]); + } + // nothing to do here + Some((key, value)) + } +} + diff --git a/parity/migration.rs b/parity/migration.rs index df2c2116f..af09709a9 100644 --- a/parity/migration.rs +++ b/parity/migration.rs @@ -17,7 +17,7 @@ use std::fs; use std::fs::File; use std::io::{Read, Write, Error as IoError, ErrorKind}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::fmt::{Display, Formatter, Error as FmtError}; use util::migration::{Manager as MigrationManager, Config as MigrationConfig, MigrationIterator}; use util::kvdb::{Database, DatabaseConfig, CompactionProfile}; @@ -26,7 +26,7 @@ use ethcore::migrations; /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; /// Current version of database models. -const CURRENT_VERSION: u32 = 6; +const CURRENT_VERSION: u32 = 7; /// Defines how many items are migrated to the new version of database at once. const BATCH_SIZE: usize = 1024; /// Version file name. @@ -66,15 +66,15 @@ impl From for Error { } /// Returns the version file path. -fn version_file_path(path: &PathBuf) -> PathBuf { - let mut file_path = path.clone(); +fn version_file_path(path: &Path) -> PathBuf { + let mut file_path = path.to_owned(); file_path.push(VERSION_FILE_NAME); file_path } /// Reads current database version from the file at given path. /// If the file does not exist returns `DEFAULT_VERSION`. -fn current_version(path: &PathBuf) -> Result { +fn current_version(path: &Path) -> Result { match File::open(version_file_path(path)) { Err(ref err) if err.kind() == ErrorKind::NotFound => Ok(DEFAULT_VERSION), Err(_) => Err(Error::UnknownDatabaseVersion), @@ -88,7 +88,7 @@ fn current_version(path: &PathBuf) -> Result { /// Writes current database version to the file. /// Creates a new file if the version file does not exist yet. -fn update_version(path: &PathBuf) -> Result<(), Error> { +fn update_version(path: &Path) -> Result<(), Error> { try!(fs::create_dir_all(path)); let mut file = try!(File::create(version_file_path(path))); try!(file.write_all(format!("{}", CURRENT_VERSION).as_bytes())); @@ -96,30 +96,37 @@ fn update_version(path: &PathBuf) -> Result<(), Error> { } /// Blocks database path. -fn blocks_database_path(path: &PathBuf) -> PathBuf { - let mut blocks_path = path.clone(); +fn blocks_database_path(path: &Path) -> PathBuf { + let mut blocks_path = path.to_owned(); blocks_path.push("blocks"); blocks_path } /// Extras database path. -fn extras_database_path(path: &PathBuf) -> PathBuf { - let mut extras_path = path.clone(); +fn extras_database_path(path: &Path) -> PathBuf { + let mut extras_path = path.to_owned(); extras_path.push("extras"); extras_path } +/// Extras database path. +fn state_database_path(path: &Path) -> PathBuf { + let mut state_path = path.to_owned(); + state_path.push("state"); + state_path +} + /// Temporary database path used for migration. -fn temp_database_path(path: &PathBuf) -> PathBuf { - let mut temp_path = path.clone(); +fn temp_database_path(path: &Path) -> PathBuf { + let mut temp_path = path.to_owned(); temp_path.pop(); temp_path.push("temp_migration"); temp_path } /// Database backup -fn backup_database_path(path: &PathBuf) -> PathBuf { - let mut backup_path = path.clone(); +fn backup_database_path(path: &Path) -> PathBuf { + let mut backup_path = path.to_owned(); backup_path.pop(); backup_path.push("temp_backup"); backup_path @@ -132,19 +139,26 @@ fn default_migration_settings() -> MigrationConfig { } } -/// Migrations on blocks database. +/// Migrations on the blocks database. fn blocks_database_migrations() -> Result { let manager = MigrationManager::new(default_migration_settings()); Ok(manager) } -/// Migrations on extras database. +/// Migrations on the extras database. fn extras_database_migrations() -> Result { let mut manager = MigrationManager::new(default_migration_settings()); try!(manager.add_migration(migrations::extras::ToV6).map_err(|_| Error::MigrationImpossible)); Ok(manager) } +/// Migrations on the state database. +fn state_database_migrations() -> Result { + let mut manager = MigrationManager::new(default_migration_settings()); + try!(manager.add_migration(migrations::state::ToV7).map_err(|_| Error::MigrationImpossible)); + Ok(manager) +} + /// Migrates database at given position with given migration rules. fn migrate_database(version: u32, path: PathBuf, migrations: MigrationManager) -> Result<(), Error> { // check if migration is needed @@ -192,12 +206,12 @@ fn migrate_database(version: u32, path: PathBuf, migrations: MigrationManager) - Ok(()) } -fn exists(path: &PathBuf) -> bool { +fn exists(path: &Path) -> bool { fs::metadata(path).is_ok() } /// Migrates the database. -pub fn migrate(path: &PathBuf) -> Result<(), Error> { +pub fn migrate(path: &Path) -> Result<(), Error> { // read version file. let version = try!(current_version(path)); @@ -207,6 +221,7 @@ pub fn migrate(path: &PathBuf) -> Result<(), Error> { println!("Migrating database from version {} to {}", version, CURRENT_VERSION); try!(migrate_database(version, blocks_database_path(path), try!(blocks_database_migrations()))); try!(migrate_database(version, extras_database_path(path), try!(extras_database_migrations()))); + try!(migrate_database(version, state_database_path(path), try!(state_database_migrations()))); println!("Migration finished"); }