pub struct WalletMigrator { /* private fields */ }
Expand description
A migrator that sets up the internal structure of the wallet database.
This procedure will automatically perform migration operations to update the wallet database to the database structure required by the current version of this library, and should be invoked at least once any time a client program upgrades to a new version of this library. The operation of this procedure is idempotent, so it is safe (though not required) to invoke this operation every time the wallet is opened.
In order to correctly apply migrations to accounts derived from a seed, sometimes the
seed is required. The migrator should first be used without calling Self::with_seed
;
if a pending migration requires the seed, Self::init_or_migrate
returns
Err(schemerz::MigratorError::Migration { error: WalletMigrationError::SeedRequired, .. })
.
The caller can then call Self::with_seed
and then re-call Self::init_or_migrate
with the necessary seed.
Note that currently only one seed can be provided; as such, wallets containing accounts derived from several different seeds are unsupported, and will result in an error. Support for multi-seed wallets is being tracked in zcash/librustzcash#1284.
When a seed is provided, it is checked against the database for relevance: if any
account in the wallet for which Account::source
is AccountSource::Derived
can
be derived from the given seed, the seed is relevant to the wallet. If the given seed
is not relevant, Self::init_or_migrate
returns
Err(schemerz::MigratorError::Migration { error: WalletMigrationError::SeedNotRelevant, .. })
or Err(schemerz::MigratorError::Adapter(WalletMigrationError::SeedNotRelevant))
.
We do not check whether the seed is relevant to any imported account, because that would require brute-forcing the ZIP 32 account index space. Consequentially, seed-requiring migrations cannot be applied to imported accounts.
It is safe to use a wallet database previously created without the ability to create
transparent spends with a build that enables transparent spends (via use of the
transparent-inputs
feature flag.) The reverse is unsafe, as wallet balance
calculations would ignore the transparent UTXOs already controlled by the wallet.
§Examples
use rand_core::OsRng;
use zcash_protocol::consensus::Network;
use zcash_client_sqlite::{
WalletDb,
util::SystemClock,
wallet::init::{WalletMigrationError, WalletMigrator},
};
let mut db = WalletDb::for_path(get_data_db_path(), Network::TestNetwork, SystemClock, OsRng)?;
match WalletMigrator::new().init_or_migrate(&mut db) {
Err(e)
if matches!(
e.source().and_then(|e| e.downcast_ref()),
Some(&WalletMigrationError::SeedRequired)
) =>
{
let seed = load_seed()?;
WalletMigrator::new()
.with_seed(seed)
.init_or_migrate(&mut db)
}
res => res,
}?;
Implementations§
Source§impl WalletMigrator
impl WalletMigrator
Sourcepub fn with_external_migrations(
self,
migrations: Vec<Box<dyn RusqliteMigration<Error = WalletMigrationError>>>,
) -> Self
pub fn with_external_migrations( self, migrations: Vec<Box<dyn RusqliteMigration<Error = WalletMigrationError>>>, ) -> Self
Sets the external migration graph to apply alongside the internal migrations.
From a data management perspective, it can be useful to store additional data
alongside the zcash_client_sqlite
wallet database. This method enables you to
provide an external [schemerz
] migration graph that the migrator will apply to
the wallet database.
§WARNING
DO NOT depend on or modify internal details of the zcash_client_sqlite
schema!
The internal migrations are written to take into account internal relationships
between the zcash_client_sqlite
tables, but they will never take into account
external tables. In particular, this means that you MUST NOT:
- Modify the structure or contents of any internal table.
- Assume that internal IDs will exist indefinitely (instead have a backup plan for recovering your data relationships if a new internal migration affects your foreign keys).
The zcash_client_sqlite
schema does not have any common prefix it uses for
tables, indexes, or views. However, we promise to not use the prefix ext_
for
any internal names. Schema created by external migrations MUST use name
prefixing with a prefix that is unlikely to collide with either the internal names
or other potential external schemas (e.g. ext_myappname_*
).
§Integration
In order to enable anchoring your external migrations correctly with respect to
this library’s internal migrations, we provide constants in the migrations
module (for each release that adds a migration) which you can include within your
[schemerz::Migration::dependencies
] set.
Each migration runs inside a database transaction, which has the following implications:
PRAGMA foreign_keys
has no effect inside a transaction, so the migrator handles foreign key enforcement itself:PRAGMA foreign_keys = OFF
is set before running any migrations.PRAGMA foreign_keys = ON
is set after all migrations are successful.
PRAGMA legacy_alter_table
should only be used in cases where its effect is explicitly intended, so the migrator does not use it globally. If you want to rename tables without breaking foreign key relationships, you need to do so yourself inside individual migrations:PRAGMA legacy_alter_table = ON; DROP TABLE table_name; ALTER TABLE table_name_new RENAME TO table_name; PRAGMA legacy_alter_table = OFF;
Sourcepub fn init_or_migrate<C: BorrowMut<Connection>, P: Parameters + 'static, CL: Clock + Clone + 'static, R: RngCore + Clone + 'static>(
self,
wdb: &mut WalletDb<C, P, CL, R>,
) -> Result<(), MigratorError<Uuid, WalletMigrationError>>
pub fn init_or_migrate<C: BorrowMut<Connection>, P: Parameters + 'static, CL: Clock + Clone + 'static, R: RngCore + Clone + 'static>( self, wdb: &mut WalletDb<C, P, CL, R>, ) -> Result<(), MigratorError<Uuid, WalletMigrationError>>
Sets up the internal structure of the given wallet database to be compatible with this library version.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for WalletMigrator
impl !RefUnwindSafe for WalletMigrator
impl !Send for WalletMigrator
impl !Sync for WalletMigrator
impl Unpin for WalletMigrator
impl !UnwindSafe for WalletMigrator
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered
].§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.