Fix db upgrade from sapling

This commit is contained in:
Hanh 2022-11-18 19:02:53 +08:00
parent c4e3c52825
commit 598459e114
5 changed files with 65 additions and 17 deletions

View File

@ -50,9 +50,11 @@ void dart_post_cobject(DartPostCObjectFnType ptr);
void deallocate_str(char *s); void deallocate_str(char *s);
void init_wallet(char *db_path); CResult init_wallet(uint8_t coin, char *db_path);
void migrate_db(char *db_path); CResult migrate_db(uint8_t coin, char *db_path);
CResult migrate_data_db(uint8_t coin);
void set_active(uint8_t active); void set_active(uint8_t active);

View File

@ -1,4 +1,4 @@
use crate::coinconfig::{init_coin, migrate_coin, CoinConfig, MEMPOOL, MEMPOOL_RUNNER}; use crate::coinconfig::{init_coin, CoinConfig, MEMPOOL, MEMPOOL_RUNNER};
use crate::note_selection::TransactionReport; use crate::note_selection::TransactionReport;
use crate::{ChainError, TransactionPlan, Tx}; use crate::{ChainError, TransactionPlan, Tx};
use allo_isolate::{ffi, IntoDart}; use allo_isolate::{ffi, IntoDart};
@ -90,24 +90,25 @@ pub struct CResult<T> {
error: *mut c_char, error: *mut c_char,
} }
const COIN_DBNAMES: &[&str] = &["zec.db", "yec.db"];
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn init_wallet(db_path: *mut c_char) { pub unsafe extern "C" fn init_wallet(coin: u8, db_path: *mut c_char) -> CResult<()> {
try_init_logger(); try_init_logger();
from_c_str!(db_path); from_c_str!(db_path);
for (coin, filename) in COIN_DBNAMES.iter().enumerate() { to_cresult(init_coin(coin, &db_path))
let _ = init_coin(coin as u8, &format!("{}/{}", &db_path, filename));
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn migrate_db(db_path: *mut c_char) { pub unsafe extern "C" fn migrate_db(coin: u8, db_path: *mut c_char) -> CResult<()> {
try_init_logger(); try_init_logger();
from_c_str!(db_path); from_c_str!(db_path);
for (coin, filename) in COIN_DBNAMES.iter().enumerate() { to_cresult(crate::coinconfig::migrate_db(coin, &db_path))
let _ = migrate_coin(coin as u8, &format!("{}/{}", &db_path, filename)); }
}
#[no_mangle]
#[tokio::main]
pub async unsafe extern "C" fn migrate_data_db(coin: u8) -> CResult<()> {
try_init_logger();
to_cresult(crate::coinconfig::migrate_data(coin).await)
} }
#[no_mangle] #[no_mangle]

View File

@ -62,12 +62,20 @@ pub fn init_coin(coin: u8, db_path: &str) -> anyhow::Result<()> {
/// Upgrade database schema for given coin and db path /// Upgrade database schema for given coin and db path
/// Used from ywallet /// Used from ywallet
pub fn migrate_coin(coin: u8, db_path: &str) -> anyhow::Result<()> { pub fn migrate_db(coin: u8, db_path: &str) -> anyhow::Result<()> {
let chain = get_coin_chain(get_coin_type(coin)); let chain = get_coin_chain(get_coin_type(coin));
DbAdapter::migrate_db(chain.network(), db_path, chain.has_unified())?; DbAdapter::migrate_db(chain.network(), db_path, chain.has_unified())?;
Ok(()) Ok(())
} }
pub async fn migrate_data(coin: u8) -> anyhow::Result<()> {
let c = CoinConfig::get(coin);
let db = c.db()?;
let mut client = c.connect_lwd().await?;
db.migrate_data(&mut client).await?;
Ok(())
}
#[derive(Clone)] #[derive(Clone)]
pub struct CoinConfig { pub struct CoinConfig {
pub coin: u8, pub coin: u8,

View File

@ -8,7 +8,7 @@ use crate::sync::tree::{CTree, TreeCheckpoint};
use crate::taddr::{derive_tkeys, TBalance}; use crate::taddr::{derive_tkeys, TBalance};
use crate::transaction::{GetTransactionDetailRequest, TransactionDetails}; use crate::transaction::{GetTransactionDetailRequest, TransactionDetails};
use crate::unified::UnifiedAddressType; use crate::unified::UnifiedAddressType;
use crate::{sync, Hash}; use crate::{sync, BlockId, CompactTxStreamerClient, Hash};
use orchard::keys::FullViewingKey; use orchard::keys::FullViewingKey;
use rusqlite::Error::QueryReturnedNoRows; use rusqlite::Error::QueryReturnedNoRows;
use rusqlite::{params, Connection, OptionalExtension, Transaction}; use rusqlite::{params, Connection, OptionalExtension, Transaction};
@ -16,6 +16,8 @@ use serde::{Deserialize, Serialize};
use serde_with::serde_as; use serde_with::serde_as;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use tonic::transport::Channel;
use tonic::Request;
use zcash_client_backend::encoding::decode_extended_full_viewing_key; use zcash_client_backend::encoding::decode_extended_full_viewing_key;
use zcash_params::coin::{get_coin_chain, get_coin_id, CoinType}; use zcash_params::coin::{get_coin_chain, get_coin_id, CoinType};
use zcash_primitives::consensus::{Network, NetworkUpgrade, Parameters}; use zcash_primitives::consensus::{Network, NetworkUpgrade, Parameters};
@ -119,6 +121,39 @@ impl DbAdapter {
Ok(()) Ok(())
} }
pub async fn migrate_data(
&self,
client: &mut CompactTxStreamerClient<Channel>,
) -> anyhow::Result<()> {
let mut stmt = self.connection.prepare("select s.height from sapling_tree s LEFT JOIN orchard_tree o ON s.height = o.height WHERE o.height IS NULL")?;
let rows = stmt.query_map([], |row| {
let height: u32 = row.get(0)?;
Ok(height)
})?;
let mut trees = HashMap::new();
for r in rows {
trees.insert(r?, vec![]);
}
for (height, tree) in trees.iter_mut() {
let tree_state = client
.get_tree_state(Request::new(BlockId {
height: *height as u64,
hash: vec![],
}))
.await?
.into_inner();
let orchard_tree = hex::decode(&tree_state.orchard_tree).unwrap();
tree.extend(orchard_tree);
}
for (height, tree) in trees.iter() {
self.connection.execute(
"INSERT INTO orchard_tree(height, tree) VALUES (?1, ?2) ON CONFLICT DO NOTHING",
params![height, tree],
)?;
}
Ok(())
}
pub fn disable_wal(db_path: &str) -> anyhow::Result<()> { pub fn disable_wal(db_path: &str) -> anyhow::Result<()> {
let connection = Connection::open(db_path)?; let connection = Connection::open(db_path)?;
connection.query_row("PRAGMA journal_mode = OFF", [], |_| Ok(()))?; connection.query_row("PRAGMA journal_mode = OFF", [], |_| Ok(()))?;

View File

@ -34,6 +34,8 @@ pub fn reset_db(connection: &Connection) -> anyhow::Result<()> {
Ok(()) Ok(())
} }
const LATEST_VERSION: u32 = 5;
pub fn init_db(connection: &Connection, network: &Network, has_ua: bool) -> anyhow::Result<()> { pub fn init_db(connection: &Connection, network: &Network, has_ua: bool) -> anyhow::Result<()> {
connection.execute( connection.execute(
"CREATE TABLE IF NOT EXISTS schema_version ( "CREATE TABLE IF NOT EXISTS schema_version (
@ -265,8 +267,8 @@ pub fn init_db(connection: &Connection, network: &Network, has_ua: bool) -> anyh
)?; )?;
} }
if version != 5 { if version != LATEST_VERSION {
update_schema_version(connection, 5)?; update_schema_version(connection, LATEST_VERSION)?;
connection.cache_flush()?; connection.cache_flush()?;
log::info!("Database migrated"); log::info!("Database migrated");
} }