From 5f4876688351ba96d56b37e07792eec4038a5a2a Mon Sep 17 00:00:00 2001 From: Hanh Date: Tue, 28 Feb 2023 18:55:46 +1000 Subject: [PATCH] Return sapling fvk in Backup --- binding.h | 22 ++-- src/api/account.rs | 66 +++++----- src/api/dart_ffi.rs | 9 +- src/db/data_generated.rs | 261 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+), 45 deletions(-) diff --git a/binding.h b/binding.h index d1f7b9f..45fad8f 100644 --- a/binding.h +++ b/binding.h @@ -34,6 +34,12 @@ typedef struct CResult_u32 { uint32_t len; } CResult_u32; +typedef struct CResult______u8 { + const uint8_t *value; + char *error; + uint32_t len; +} CResult______u8; + typedef struct CResult_____c_char { char *value; char *error; @@ -46,12 +52,6 @@ typedef struct CResult_u64 { uint32_t len; } CResult_u64; -typedef struct CResult______u8 { - const uint8_t *value; - char *error; - uint32_t len; -} CResult______u8; - #define Account_VT_ID 4 #define Account_VT_NAME 6 @@ -138,6 +138,14 @@ typedef struct CResult______u8 { #define AddressBalance_VT_INDEX 4 +#define Backup_VT_SEED 6 + +#define Backup_VT_SK 10 + +#define Backup_VT_FVK 12 + +#define Backup_VT_UVK 14 + void dummy_export(void); void dart_post_cobject(DartPostCObjectFnType ptr); @@ -170,7 +178,7 @@ void new_sub_account(char *name, int32_t index, uint32_t count); struct CResult_u8 convert_to_watchonly(uint8_t coin, uint32_t id_account); -struct CResult_____c_char get_backup(uint8_t coin, uint32_t id_account); +struct CResult______u8 get_backup(uint8_t coin, uint32_t id_account); struct CResult_____c_char get_address(uint8_t coin, uint32_t id_account, uint8_t ua_type); diff --git a/src/api/account.rs b/src/api/account.rs index c87ba40..12b1abe 100644 --- a/src/api/account.rs +++ b/src/api/account.rs @@ -4,7 +4,8 @@ use crate::coinconfig::CoinConfig; use crate::db::data_generated::fb::{ - AddressBalance, AddressBalanceArgs, AddressBalanceVec, AddressBalanceVecArgs, + AddressBalance, AddressBalanceArgs, AddressBalanceVec, AddressBalanceVecArgs, Backup, + BackupArgs, }; use crate::db::AccountData; use crate::key2::decode_key; @@ -119,7 +120,8 @@ pub fn convert_to_watchonly(coin: u8, id_account: u32) -> anyhow::Result<()> { Ok(()) } -pub fn get_backup_package(coin: u8, id_account: u32) -> anyhow::Result { +pub fn get_backup_package(coin: u8, id_account: u32) -> anyhow::Result> { + let mut builder = flatbuffers::FlatBufferBuilder::new(); let c = CoinConfig::get(coin); let network = c.chain.network(); let db = c.db()?; @@ -131,29 +133,36 @@ pub fn get_backup_package(coin: u8, id_account: u32) -> anyhow::Result { aindex, .. } = db.get_account_info(id_account)?; + let name = builder.create_string(&name); + let seed = seed.map(|seed| builder.create_string(&seed)); + let sk = sk.map(|sk| builder.create_string(&sk)); let orchard_keys = db.get_orchard(id_account)?; - let fvk = match orchard_keys { - None => fvk, - Some(OrchardKeyBytes { fvk: ofvk, .. }) => { - // orchard sk is not serializable and must derived from seed - let sapling_efvk = decode_extended_full_viewing_key( - network.hrp_sapling_extended_full_viewing_key(), - &fvk, - ) - .unwrap(); - let sapling_dfvk = sapling_efvk.to_diversifiable_full_viewing_key(); - let orchard_fvk = orchard::keys::FullViewingKey::from_bytes(&ofvk); - let ufvk = UnifiedFullViewingKey::new(Some(sapling_dfvk), orchard_fvk).unwrap(); - ufvk.encode(network) - } - }; - Ok(Backup { - name, - seed, - index: aindex, - sk, - ivk: fvk, - }) + let uvk = orchard_keys.map(|OrchardKeyBytes { fvk: ofvk, .. }| { + // orchard sk is not serializable and must derived from seed + let sapling_efvk = + decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), &fvk) + .unwrap(); + let sapling_dfvk = sapling_efvk.to_diversifiable_full_viewing_key(); + let orchard_fvk = orchard::keys::FullViewingKey::from_bytes(&ofvk); + let ufvk = UnifiedFullViewingKey::new(Some(sapling_dfvk), orchard_fvk).unwrap(); + let ufvk = ufvk.encode(network); + builder.create_string(&ufvk) + }); + let fvk = builder.create_string(&fvk); + let backup = Backup::create( + &mut builder, + &BackupArgs { + name: Some(name), + seed, + index: aindex, + sk, + fvk: Some(fvk), + uvk, + }, + ); + builder.finish(backup, None); + let data = builder.finished_data().to_vec(); + Ok(data) } /// Update the transparent secret key for the given account from a derivation path @@ -440,12 +449,3 @@ pub fn decode_unified_address(coin: u8, address: &str) -> anyhow::Result let res = crate::decode_unified_address(c.chain.network(), address)?; Ok(res.to_string()) } - -#[derive(Serialize)] -pub struct Backup { - name: String, - seed: Option, - index: u32, - sk: Option, - ivk: String, -} diff --git a/src/api/dart_ffi.rs b/src/api/dart_ffi.rs index b551097..ccfe491 100644 --- a/src/api/dart_ffi.rs +++ b/src/api/dart_ffi.rs @@ -236,14 +236,13 @@ pub unsafe extern "C" fn convert_to_watchonly(coin: u8, id_account: u32) -> CRes } #[no_mangle] -pub unsafe extern "C" fn get_backup(coin: u8, id_account: u32) -> CResult<*mut c_char> { +pub unsafe extern "C" fn get_backup(coin: u8, id_account: u32) -> CResult<*const u8> { let res = || { - let backup = crate::api::account::get_backup_package(coin, id_account)?; - let backup_str = serde_json::to_string(&backup)?; - Ok::<_, anyhow::Error>(backup_str) + let backup_bytes = crate::api::account::get_backup_package(coin, id_account)?; + Ok::<_, anyhow::Error>(backup_bytes) }; - to_cresult_str(res()) + to_cresult_bytes(res()) } #[no_mangle] diff --git a/src/db/data_generated.rs b/src/db/data_generated.rs index 7dc00ad..11ea586 100644 --- a/src/db/data_generated.rs +++ b/src/db/data_generated.rs @@ -4438,5 +4438,266 @@ impl CheckpointVecT { }) } } +pub enum BackupOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct Backup<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Backup<'a> { + type Inner = Backup<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> Backup<'a> { + pub const VT_NAME: flatbuffers::VOffsetT = 4; + pub const VT_SEED: flatbuffers::VOffsetT = 6; + pub const VT_INDEX: flatbuffers::VOffsetT = 8; + pub const VT_SK: flatbuffers::VOffsetT = 10; + pub const VT_FVK: flatbuffers::VOffsetT = 12; + pub const VT_UVK: flatbuffers::VOffsetT = 14; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Backup { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args BackupArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = BackupBuilder::new(_fbb); + if let Some(x) = args.uvk { builder.add_uvk(x); } + if let Some(x) = args.fvk { builder.add_fvk(x); } + if let Some(x) = args.sk { builder.add_sk(x); } + builder.add_index(args.index); + if let Some(x) = args.seed { builder.add_seed(x); } + if let Some(x) = args.name { builder.add_name(x); } + builder.finish() + } + + pub fn unpack(&self) -> BackupT { + let name = self.name().map(|x| { + x.to_string() + }); + let seed = self.seed().map(|x| { + x.to_string() + }); + let index = self.index(); + let sk = self.sk().map(|x| { + x.to_string() + }); + let fvk = self.fvk().map(|x| { + x.to_string() + }); + let uvk = self.uvk().map(|x| { + x.to_string() + }); + BackupT { + name, + seed, + index, + sk, + fvk, + uvk, + } + } + + #[inline] + pub fn name(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(Backup::VT_NAME, None)} + } + #[inline] + pub fn seed(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(Backup::VT_SEED, None)} + } + #[inline] + pub fn index(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Backup::VT_INDEX, Some(0)).unwrap()} + } + #[inline] + pub fn sk(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(Backup::VT_SK, None)} + } + #[inline] + pub fn fvk(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(Backup::VT_FVK, None)} + } + #[inline] + pub fn uvk(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(Backup::VT_UVK, None)} + } +} + +impl flatbuffers::Verifiable for Backup<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>("name", Self::VT_NAME, false)? + .visit_field::>("seed", Self::VT_SEED, false)? + .visit_field::("index", Self::VT_INDEX, false)? + .visit_field::>("sk", Self::VT_SK, false)? + .visit_field::>("fvk", Self::VT_FVK, false)? + .visit_field::>("uvk", Self::VT_UVK, false)? + .finish(); + Ok(()) + } +} +pub struct BackupArgs<'a> { + pub name: Option>, + pub seed: Option>, + pub index: u32, + pub sk: Option>, + pub fvk: Option>, + pub uvk: Option>, +} +impl<'a> Default for BackupArgs<'a> { + #[inline] + fn default() -> Self { + BackupArgs { + name: None, + seed: None, + index: 0, + sk: None, + fvk: None, + uvk: None, + } + } +} + +pub struct BackupBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> BackupBuilder<'a, 'b> { + #[inline] + pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(Backup::VT_NAME, name); + } + #[inline] + pub fn add_seed(&mut self, seed: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(Backup::VT_SEED, seed); + } + #[inline] + pub fn add_index(&mut self, index: u32) { + self.fbb_.push_slot::(Backup::VT_INDEX, index, 0); + } + #[inline] + pub fn add_sk(&mut self, sk: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(Backup::VT_SK, sk); + } + #[inline] + pub fn add_fvk(&mut self, fvk: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(Backup::VT_FVK, fvk); + } + #[inline] + pub fn add_uvk(&mut self, uvk: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(Backup::VT_UVK, uvk); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> BackupBuilder<'a, 'b> { + let start = _fbb.start_table(); + BackupBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +impl core::fmt::Debug for Backup<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("Backup"); + ds.field("name", &self.name()); + ds.field("seed", &self.seed()); + ds.field("index", &self.index()); + ds.field("sk", &self.sk()); + ds.field("fvk", &self.fvk()); + ds.field("uvk", &self.uvk()); + ds.finish() + } +} +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq)] +pub struct BackupT { + pub name: Option, + pub seed: Option, + pub index: u32, + pub sk: Option, + pub fvk: Option, + pub uvk: Option, +} +impl Default for BackupT { + fn default() -> Self { + Self { + name: None, + seed: None, + index: 0, + sk: None, + fvk: None, + uvk: None, + } + } +} +impl BackupT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let name = self.name.as_ref().map(|x|{ + _fbb.create_string(x) + }); + let seed = self.seed.as_ref().map(|x|{ + _fbb.create_string(x) + }); + let index = self.index; + let sk = self.sk.as_ref().map(|x|{ + _fbb.create_string(x) + }); + let fvk = self.fvk.as_ref().map(|x|{ + _fbb.create_string(x) + }); + let uvk = self.uvk.as_ref().map(|x|{ + _fbb.create_string(x) + }); + Backup::create(_fbb, &BackupArgs{ + name, + seed, + index, + sk, + fvk, + uvk, + }) + } +} } // pub mod fb