diff --git a/binding.h b/binding.h index 9e0690a..ca0e518 100644 --- a/binding.h +++ b/binding.h @@ -1,4 +1,3 @@ -#ifndef __APPLE__ typedef char int8_t; typedef unsigned char uint8_t; typedef short int uint16_t; @@ -10,9 +9,9 @@ typedef long int uint32_t; #ifndef __cplusplus typedef char bool; #endif -#endif typedef void *DartPostCObjectFnType; + #define QR_DATA_SIZE 256 #define MAX_ATTEMPTS 10 @@ -22,29 +21,99 @@ typedef void *DartPostCObjectFnType; typedef struct CResult_u8 { uint8_t value; char *error; + uint32_t len; } CResult_u8; typedef struct CResult_u32 { uint32_t value; char *error; + uint32_t len; } CResult_u32; typedef struct CResult_____c_char { char *value; char *error; + uint32_t len; } CResult_____c_char; typedef struct CResult_u64 { uint64_t value; char *error; + 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 + +#define Account_VT_BALANCE 8 + +#define AccountVec_VT_ACCOUNTS 4 + +#define Balance_VT_SHIELDED 4 + +#define Balance_VT_UNCONFIRMED_SPENT 6 + +#define Balance_VT_UNDER_CONFIRMED 10 + +#define Balance_VT_EXCLUDED 12 + +#define Balance_VT_SAPLING 14 + +#define Balance_VT_ORCHARD 16 + +#define Height_VT_HEIGHT 4 + +#define Height_VT_TIMESTAMP 6 + +#define ShieldedNote_VT_VALUE 8 + +#define ShieldedNote_VT_SPENT 16 + +#define ShieldedNoteVec_VT_NOTES 4 + +#define AdressbookEntry_VT_ID_ADDRESS 4 + +#define AdressbookEntry_VT_ADDRESS 8 + +#define Addressbook_VT_CONTACTS 6 + +#define AccountBalance_VT_COIN 4 + +#define AccountBalance_VT_ID_ACCOUNT 6 + +#define AccountBalance_VT_TBALANCE 12 + +#define ZMessage_VT_TX_ID 6 + +#define ZMessage_VT_INCOMING 8 + +#define ZMessage_VT_SENDER 10 + +#define ZMessage_VT_RECIPIENT 12 + +#define ZMessage_VT_SUBJECT 14 + +#define ZMessage_VT_BODY 16 + +#define ZMessage_VT_READ 22 + +#define ZMessages_VT_MESSAGES 4 + void dummy_export(void); void dart_post_cobject(DartPostCObjectFnType ptr); void deallocate_str(char *s); +void deallocate_bytes(uint8_t *ptr, uint32_t len); + struct CResult_u8 init_wallet(uint8_t coin, char *db_path); struct CResult_u8 migrate_db(uint8_t coin, char *db_path); @@ -184,6 +253,22 @@ struct CResult_u32 save_send_template(uint8_t coin, char *template_); struct CResult_u8 delete_send_template(uint8_t coin, uint32_t id); +struct CResult______u8 get_account_list(uint8_t coin); + +struct CResult_u32 get_available_account_id(uint8_t coin, uint32_t id); + +struct CResult_____c_char get_t_addr(uint8_t coin, uint32_t id); + +struct CResult_____c_char get_sk(uint8_t coin, uint32_t id); + +struct CResult_u8 update_account_name(uint8_t coin, uint32_t id, char *name); + +struct CResult______u8 get_balances(uint8_t coin, uint32_t id, uint32_t confirmed_height); + +struct CResult______u8 get_db_height(uint8_t coin); + +struct CResult______u8 get_notes(uint8_t coin, uint32_t id); + bool has_cuda(void); bool has_metal(void); diff --git a/src/api/dart_ffi.rs b/src/api/dart_ffi.rs index 46af26b..ff29ee7 100644 --- a/src/api/dart_ffi.rs +++ b/src/api/dart_ffi.rs @@ -1,7 +1,7 @@ use crate::coinconfig::{init_coin, CoinConfig, MEMPOOL, MEMPOOL_RUNNER}; use crate::db::FullEncryptedBackup; use crate::note_selection::TransactionReport; -use crate::{ChainError, TransactionPlan, Tx}; +use crate::{ChainError, DbAdapter, TransactionPlan, Tx}; use allo_isolate::{ffi, IntoDart}; use android_logger::Config; use lazy_static::lazy_static; @@ -9,7 +9,8 @@ use log::Level; use std::ffi::{CStr, CString}; use std::os::raw::c_char; use std::path::Path; -use std::sync::Mutex; +use std::sync::{Mutex, MutexGuard}; +use rusqlite::Connection; use tokio::sync::Semaphore; use zcash_primitives::transaction::builder::Progress; use crate::template::SendTemplate; @@ -41,12 +42,14 @@ fn to_cresult(res: Result) -> CResult { match res { Ok(v) => CResult { value: v, + len: 0, error: std::ptr::null_mut::(), }, Err(e) => { log::error!("{}", e); CResult { value: unsafe { std::mem::zeroed() }, + len: 0, error: to_c_str(e), } } @@ -64,11 +67,39 @@ fn log_error(res: Result<(), anyhow::Error>) { } } +fn to_cresult_bytes(res: Result, anyhow::Error>) -> CResult<*const u8> { + match res { + Ok(v) => { + let ptr = v.as_ptr(); + let len = v.len(); + std::mem::forget(v); + CResult { + value: ptr, + len: len as u32, + error: std::ptr::null_mut::(), + } + }, + Err(e) => { + log::error!("{}", e); + CResult { + value: unsafe { std::mem::zeroed() }, + len: 0, + error: to_c_str(e.to_string()), + } + } + } +} + #[no_mangle] pub unsafe extern "C" fn deallocate_str(s: *mut c_char) { let _ = CString::from_raw(s); } +#[no_mangle] +pub unsafe extern "C" fn deallocate_bytes(ptr: *mut u8, len: u32) { + drop(Vec::from_raw_parts(ptr, len as usize, len as usize)); +} + fn try_init_logger() { android_logger::init_once( Config::default() @@ -90,6 +121,7 @@ fn try_init_logger() { pub struct CResult { value: T, error: *mut c_char, + pub len: u32, } #[no_mangle] @@ -796,6 +828,86 @@ pub unsafe extern "C" fn delete_send_template(coin: u8, id: u32) -> CResult to_cresult(res()) } +fn with_account anyhow::Result>(coin: u8, id: u32, f: F) -> anyhow::Result { + let c = CoinConfig::get(coin); + let db = c.db()?; + let connection = &db.connection; + f(coin, id, connection) +} + +#[no_mangle] +pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> { + let res = |coin: u8, id: u32, connection: &Connection| { + let accounts = crate::db::read::get_account_list(connection)?; + Ok(accounts) + }; + to_cresult_bytes(with_account(coin, 0, res)) +} + +#[no_mangle] +pub unsafe extern "C" fn get_available_account_id(coin: u8, id: u32) -> CResult { + let res = |coin: u8, id: u32, connection: &Connection| { + let new_id = crate::db::read::get_available_account_id(connection, id)?; + Ok(new_id) + }; + to_cresult(with_account(coin, id, res)) +} + +#[no_mangle] +pub unsafe extern "C" fn get_t_addr(coin: u8, id: u32) -> CResult<*mut c_char> { + let res = |coin: u8, id: u32, connection: &Connection| { + let address = crate::db::read::get_t_addr(connection, id)?; + Ok(address) + }; + to_cresult_str(with_account(coin, id, res)) +} + +#[no_mangle] +pub unsafe extern "C" fn get_sk(coin: u8, id: u32) -> CResult<*mut c_char> { + let res = |coin: u8, id: u32, connection: &Connection| { + let sk = crate::db::read::get_sk(connection, id)?; + Ok(sk) + }; + to_cresult_str(with_account(coin, id, res)) +} + +#[no_mangle] +pub unsafe extern "C" fn update_account_name(coin: u8, id: u32, name: *mut c_char) -> CResult { + from_c_str!(name); + let res = |coin: u8, id: u32, connection: &Connection| { + crate::db::read::update_account_name(connection, id, &name)?; + Ok(0) + }; + to_cresult(with_account(coin, id, res)) +} + +#[no_mangle] +pub unsafe extern "C" fn get_balances(coin: u8, id: u32, confirmed_height: u32) -> CResult<*const u8> { + let res = |coin: u8, id: u32, connection: &Connection| { + let data = crate::db::read::get_balances(connection, id, confirmed_height)?; + Ok(data) + }; + to_cresult_bytes(with_account(coin, id, res)) +} + +#[no_mangle] +pub unsafe extern "C" fn get_db_height(coin: u8) -> CResult<*const u8> { + let res = |coin: u8, _id: u32, connection: &Connection| { + let data = crate::db::read::get_db_height(connection)?; + Ok(data) + }; + to_cresult_bytes(with_account(coin, 0, res)) +} + +#[no_mangle] +pub unsafe extern "C" fn get_notes(coin: u8, id: u32) -> CResult<*const u8> { + let res = |coin: u8, id: u32, connection: &Connection| { + let data = crate::db::read::get_notes(connection, id)?; + Ok(data) + }; + to_cresult_bytes(with_account(coin, id, res)) +} + #[no_mangle] pub unsafe extern "C" fn has_cuda() -> bool { crate::gpu::has_cuda() diff --git a/src/db.rs b/src/db.rs index 97f03ae..30cbffd 100644 --- a/src/db.rs +++ b/src/db.rs @@ -26,6 +26,8 @@ use zcash_primitives::zip32::{DiversifierIndex, ExtendedFullViewingKey}; mod backup; mod migration; +pub mod data_generated; +pub mod read; pub use backup::FullEncryptedBackup; use crate::template::SendTemplate; diff --git a/src/db/data_generated.rs b/src/db/data_generated.rs new file mode 100644 index 0000000..76c6ade --- /dev/null +++ b/src/db/data_generated.rs @@ -0,0 +1,1713 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +// @generated + +use core::mem; +use core::cmp::Ordering; + +extern crate flatbuffers; +use self::flatbuffers::{EndianScalar, Follow}; + +#[allow(unused_imports, dead_code)] +pub mod fb { + + use core::mem; + use core::cmp::Ordering; + + extern crate flatbuffers; + use self::flatbuffers::{EndianScalar, Follow}; + +pub enum AccountOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct Account<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Account<'a> { + type Inner = Account<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> Account<'a> { + pub const VT_ID: flatbuffers::VOffsetT = 4; + pub const VT_NAME: flatbuffers::VOffsetT = 6; + pub const VT_BALANCE: flatbuffers::VOffsetT = 8; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Account { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args AccountArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = AccountBuilder::new(_fbb); + builder.add_balance(args.balance); + if let Some(x) = args.name { builder.add_name(x); } + builder.add_id(args.id); + builder.finish() + } + + + #[inline] + pub fn id(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Account::VT_ID, Some(0)).unwrap()} + } + #[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::>(Account::VT_NAME, None)} + } + #[inline] + pub fn balance(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Account::VT_BALANCE, Some(0)).unwrap()} + } +} + +impl flatbuffers::Verifiable for Account<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("id", Self::VT_ID, false)? + .visit_field::>("name", Self::VT_NAME, false)? + .visit_field::("balance", Self::VT_BALANCE, false)? + .finish(); + Ok(()) + } +} +pub struct AccountArgs<'a> { + pub id: u32, + pub name: Option>, + pub balance: u64, +} +impl<'a> Default for AccountArgs<'a> { + #[inline] + fn default() -> Self { + AccountArgs { + id: 0, + name: None, + balance: 0, + } + } +} + +pub struct AccountBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> AccountBuilder<'a, 'b> { + #[inline] + pub fn add_id(&mut self, id: u32) { + self.fbb_.push_slot::(Account::VT_ID, id, 0); + } + #[inline] + pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(Account::VT_NAME, name); + } + #[inline] + pub fn add_balance(&mut self, balance: u64) { + self.fbb_.push_slot::(Account::VT_BALANCE, balance, 0); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AccountBuilder<'a, 'b> { + let start = _fbb.start_table(); + AccountBuilder { + 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 Account<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("Account"); + ds.field("id", &self.id()); + ds.field("name", &self.name()); + ds.field("balance", &self.balance()); + ds.finish() + } +} +pub enum AccountVecOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct AccountVec<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for AccountVec<'a> { + type Inner = AccountVec<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> AccountVec<'a> { + pub const VT_ACCOUNTS: flatbuffers::VOffsetT = 4; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + AccountVec { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args AccountVecArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = AccountVecBuilder::new(_fbb); + if let Some(x) = args.accounts { builder.add_accounts(x); } + builder.finish() + } + + + #[inline] + pub fn accounts(&self) -> Option>>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>>(AccountVec::VT_ACCOUNTS, None)} + } +} + +impl flatbuffers::Verifiable for AccountVec<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>>("accounts", Self::VT_ACCOUNTS, false)? + .finish(); + Ok(()) + } +} +pub struct AccountVecArgs<'a> { + pub accounts: Option>>>>, +} +impl<'a> Default for AccountVecArgs<'a> { + #[inline] + fn default() -> Self { + AccountVecArgs { + accounts: None, + } + } +} + +pub struct AccountVecBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> AccountVecBuilder<'a, 'b> { + #[inline] + pub fn add_accounts(&mut self, accounts: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(AccountVec::VT_ACCOUNTS, accounts); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AccountVecBuilder<'a, 'b> { + let start = _fbb.start_table(); + AccountVecBuilder { + 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 AccountVec<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("AccountVec"); + ds.field("accounts", &self.accounts()); + ds.finish() + } +} +pub enum BalanceOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct Balance<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Balance<'a> { + type Inner = Balance<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> Balance<'a> { + pub const VT_SHIELDED: flatbuffers::VOffsetT = 4; + pub const VT_UNCONFIRMED_SPENT: flatbuffers::VOffsetT = 6; + pub const VT_BALANCE: flatbuffers::VOffsetT = 8; + pub const VT_UNDER_CONFIRMED: flatbuffers::VOffsetT = 10; + pub const VT_EXCLUDED: flatbuffers::VOffsetT = 12; + pub const VT_SAPLING: flatbuffers::VOffsetT = 14; + pub const VT_ORCHARD: flatbuffers::VOffsetT = 16; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Balance { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args BalanceArgs + ) -> flatbuffers::WIPOffset> { + let mut builder = BalanceBuilder::new(_fbb); + builder.add_orchard(args.orchard); + builder.add_sapling(args.sapling); + builder.add_excluded(args.excluded); + builder.add_under_confirmed(args.under_confirmed); + builder.add_balance(args.balance); + builder.add_unconfirmed_spent(args.unconfirmed_spent); + builder.add_shielded(args.shielded); + builder.finish() + } + + + #[inline] + pub fn shielded(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Balance::VT_SHIELDED, Some(0)).unwrap()} + } + #[inline] + pub fn unconfirmed_spent(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Balance::VT_UNCONFIRMED_SPENT, Some(0)).unwrap()} + } + #[inline] + pub fn balance(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Balance::VT_BALANCE, Some(0)).unwrap()} + } + #[inline] + pub fn under_confirmed(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Balance::VT_UNDER_CONFIRMED, Some(0)).unwrap()} + } + #[inline] + pub fn excluded(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Balance::VT_EXCLUDED, Some(0)).unwrap()} + } + #[inline] + pub fn sapling(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Balance::VT_SAPLING, Some(0)).unwrap()} + } + #[inline] + pub fn orchard(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Balance::VT_ORCHARD, Some(0)).unwrap()} + } +} + +impl flatbuffers::Verifiable for Balance<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("shielded", Self::VT_SHIELDED, false)? + .visit_field::("unconfirmed_spent", Self::VT_UNCONFIRMED_SPENT, false)? + .visit_field::("balance", Self::VT_BALANCE, false)? + .visit_field::("under_confirmed", Self::VT_UNDER_CONFIRMED, false)? + .visit_field::("excluded", Self::VT_EXCLUDED, false)? + .visit_field::("sapling", Self::VT_SAPLING, false)? + .visit_field::("orchard", Self::VT_ORCHARD, false)? + .finish(); + Ok(()) + } +} +pub struct BalanceArgs { + pub shielded: u64, + pub unconfirmed_spent: u64, + pub balance: u64, + pub under_confirmed: u64, + pub excluded: u64, + pub sapling: u64, + pub orchard: u64, +} +impl<'a> Default for BalanceArgs { + #[inline] + fn default() -> Self { + BalanceArgs { + shielded: 0, + unconfirmed_spent: 0, + balance: 0, + under_confirmed: 0, + excluded: 0, + sapling: 0, + orchard: 0, + } + } +} + +pub struct BalanceBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> BalanceBuilder<'a, 'b> { + #[inline] + pub fn add_shielded(&mut self, shielded: u64) { + self.fbb_.push_slot::(Balance::VT_SHIELDED, shielded, 0); + } + #[inline] + pub fn add_unconfirmed_spent(&mut self, unconfirmed_spent: u64) { + self.fbb_.push_slot::(Balance::VT_UNCONFIRMED_SPENT, unconfirmed_spent, 0); + } + #[inline] + pub fn add_balance(&mut self, balance: u64) { + self.fbb_.push_slot::(Balance::VT_BALANCE, balance, 0); + } + #[inline] + pub fn add_under_confirmed(&mut self, under_confirmed: u64) { + self.fbb_.push_slot::(Balance::VT_UNDER_CONFIRMED, under_confirmed, 0); + } + #[inline] + pub fn add_excluded(&mut self, excluded: u64) { + self.fbb_.push_slot::(Balance::VT_EXCLUDED, excluded, 0); + } + #[inline] + pub fn add_sapling(&mut self, sapling: u64) { + self.fbb_.push_slot::(Balance::VT_SAPLING, sapling, 0); + } + #[inline] + pub fn add_orchard(&mut self, orchard: u64) { + self.fbb_.push_slot::(Balance::VT_ORCHARD, orchard, 0); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> BalanceBuilder<'a, 'b> { + let start = _fbb.start_table(); + BalanceBuilder { + 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 Balance<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("Balance"); + ds.field("shielded", &self.shielded()); + ds.field("unconfirmed_spent", &self.unconfirmed_spent()); + ds.field("balance", &self.balance()); + ds.field("under_confirmed", &self.under_confirmed()); + ds.field("excluded", &self.excluded()); + ds.field("sapling", &self.sapling()); + ds.field("orchard", &self.orchard()); + ds.finish() + } +} +pub enum HeightOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct Height<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Height<'a> { + type Inner = Height<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> Height<'a> { + pub const VT_HEIGHT: flatbuffers::VOffsetT = 4; + pub const VT_TIMESTAMP: flatbuffers::VOffsetT = 6; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Height { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args HeightArgs + ) -> flatbuffers::WIPOffset> { + let mut builder = HeightBuilder::new(_fbb); + builder.add_timestamp(args.timestamp); + builder.add_height(args.height); + builder.finish() + } + + + #[inline] + pub fn height(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Height::VT_HEIGHT, Some(0)).unwrap()} + } + #[inline] + pub fn timestamp(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Height::VT_TIMESTAMP, Some(0)).unwrap()} + } +} + +impl flatbuffers::Verifiable for Height<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("height", Self::VT_HEIGHT, false)? + .visit_field::("timestamp", Self::VT_TIMESTAMP, false)? + .finish(); + Ok(()) + } +} +pub struct HeightArgs { + pub height: u32, + pub timestamp: u32, +} +impl<'a> Default for HeightArgs { + #[inline] + fn default() -> Self { + HeightArgs { + height: 0, + timestamp: 0, + } + } +} + +pub struct HeightBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> HeightBuilder<'a, 'b> { + #[inline] + pub fn add_height(&mut self, height: u32) { + self.fbb_.push_slot::(Height::VT_HEIGHT, height, 0); + } + #[inline] + pub fn add_timestamp(&mut self, timestamp: u32) { + self.fbb_.push_slot::(Height::VT_TIMESTAMP, timestamp, 0); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> HeightBuilder<'a, 'b> { + let start = _fbb.start_table(); + HeightBuilder { + 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 Height<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("Height"); + ds.field("height", &self.height()); + ds.field("timestamp", &self.timestamp()); + ds.finish() + } +} +pub enum ShieldedNoteOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct ShieldedNote<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ShieldedNote<'a> { + type Inner = ShieldedNote<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> ShieldedNote<'a> { + pub const VT_ID: flatbuffers::VOffsetT = 4; + pub const VT_HEIGHT: flatbuffers::VOffsetT = 6; + pub const VT_VALUE: flatbuffers::VOffsetT = 8; + pub const VT_TIMESTAMP: flatbuffers::VOffsetT = 10; + pub const VT_ORCHARD: flatbuffers::VOffsetT = 12; + pub const VT_EXCLUDED: flatbuffers::VOffsetT = 14; + pub const VT_SPENT: flatbuffers::VOffsetT = 16; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ShieldedNote { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ShieldedNoteArgs + ) -> flatbuffers::WIPOffset> { + let mut builder = ShieldedNoteBuilder::new(_fbb); + builder.add_value(args.value); + builder.add_timestamp(args.timestamp); + builder.add_height(args.height); + builder.add_id(args.id); + builder.add_spent(args.spent); + builder.add_excluded(args.excluded); + builder.add_orchard(args.orchard); + builder.finish() + } + + + #[inline] + pub fn id(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ShieldedNote::VT_ID, Some(0)).unwrap()} + } + #[inline] + pub fn height(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ShieldedNote::VT_HEIGHT, Some(0)).unwrap()} + } + #[inline] + pub fn value(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ShieldedNote::VT_VALUE, Some(0)).unwrap()} + } + #[inline] + pub fn timestamp(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ShieldedNote::VT_TIMESTAMP, Some(0)).unwrap()} + } + #[inline] + pub fn orchard(&self) -> bool { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ShieldedNote::VT_ORCHARD, Some(false)).unwrap()} + } + #[inline] + pub fn excluded(&self) -> bool { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ShieldedNote::VT_EXCLUDED, Some(false)).unwrap()} + } + #[inline] + pub fn spent(&self) -> bool { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ShieldedNote::VT_SPENT, Some(false)).unwrap()} + } +} + +impl flatbuffers::Verifiable for ShieldedNote<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("id", Self::VT_ID, false)? + .visit_field::("height", Self::VT_HEIGHT, false)? + .visit_field::("value", Self::VT_VALUE, false)? + .visit_field::("timestamp", Self::VT_TIMESTAMP, false)? + .visit_field::("orchard", Self::VT_ORCHARD, false)? + .visit_field::("excluded", Self::VT_EXCLUDED, false)? + .visit_field::("spent", Self::VT_SPENT, false)? + .finish(); + Ok(()) + } +} +pub struct ShieldedNoteArgs { + pub id: u32, + pub height: u32, + pub value: u64, + pub timestamp: u32, + pub orchard: bool, + pub excluded: bool, + pub spent: bool, +} +impl<'a> Default for ShieldedNoteArgs { + #[inline] + fn default() -> Self { + ShieldedNoteArgs { + id: 0, + height: 0, + value: 0, + timestamp: 0, + orchard: false, + excluded: false, + spent: false, + } + } +} + +pub struct ShieldedNoteBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ShieldedNoteBuilder<'a, 'b> { + #[inline] + pub fn add_id(&mut self, id: u32) { + self.fbb_.push_slot::(ShieldedNote::VT_ID, id, 0); + } + #[inline] + pub fn add_height(&mut self, height: u32) { + self.fbb_.push_slot::(ShieldedNote::VT_HEIGHT, height, 0); + } + #[inline] + pub fn add_value(&mut self, value: u64) { + self.fbb_.push_slot::(ShieldedNote::VT_VALUE, value, 0); + } + #[inline] + pub fn add_timestamp(&mut self, timestamp: u32) { + self.fbb_.push_slot::(ShieldedNote::VT_TIMESTAMP, timestamp, 0); + } + #[inline] + pub fn add_orchard(&mut self, orchard: bool) { + self.fbb_.push_slot::(ShieldedNote::VT_ORCHARD, orchard, false); + } + #[inline] + pub fn add_excluded(&mut self, excluded: bool) { + self.fbb_.push_slot::(ShieldedNote::VT_EXCLUDED, excluded, false); + } + #[inline] + pub fn add_spent(&mut self, spent: bool) { + self.fbb_.push_slot::(ShieldedNote::VT_SPENT, spent, false); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ShieldedNoteBuilder<'a, 'b> { + let start = _fbb.start_table(); + ShieldedNoteBuilder { + 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 ShieldedNote<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("ShieldedNote"); + ds.field("id", &self.id()); + ds.field("height", &self.height()); + ds.field("value", &self.value()); + ds.field("timestamp", &self.timestamp()); + ds.field("orchard", &self.orchard()); + ds.field("excluded", &self.excluded()); + ds.field("spent", &self.spent()); + ds.finish() + } +} +pub enum ShieldedNoteVecOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct ShieldedNoteVec<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ShieldedNoteVec<'a> { + type Inner = ShieldedNoteVec<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> ShieldedNoteVec<'a> { + pub const VT_NOTES: flatbuffers::VOffsetT = 4; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ShieldedNoteVec { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ShieldedNoteVecArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = ShieldedNoteVecBuilder::new(_fbb); + if let Some(x) = args.notes { builder.add_notes(x); } + builder.finish() + } + + + #[inline] + pub fn notes(&self) -> Option>>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>>(ShieldedNoteVec::VT_NOTES, None)} + } +} + +impl flatbuffers::Verifiable for ShieldedNoteVec<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>>("notes", Self::VT_NOTES, false)? + .finish(); + Ok(()) + } +} +pub struct ShieldedNoteVecArgs<'a> { + pub notes: Option>>>>, +} +impl<'a> Default for ShieldedNoteVecArgs<'a> { + #[inline] + fn default() -> Self { + ShieldedNoteVecArgs { + notes: None, + } + } +} + +pub struct ShieldedNoteVecBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ShieldedNoteVecBuilder<'a, 'b> { + #[inline] + pub fn add_notes(&mut self, notes: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(ShieldedNoteVec::VT_NOTES, notes); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ShieldedNoteVecBuilder<'a, 'b> { + let start = _fbb.start_table(); + ShieldedNoteVecBuilder { + 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 ShieldedNoteVec<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("ShieldedNoteVec"); + ds.field("notes", &self.notes()); + ds.finish() + } +} +pub enum AdressbookEntryOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct AdressbookEntry<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for AdressbookEntry<'a> { + type Inner = AdressbookEntry<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> AdressbookEntry<'a> { + pub const VT_ID_ADDRESS: flatbuffers::VOffsetT = 4; + pub const VT_NAME: flatbuffers::VOffsetT = 6; + pub const VT_ADDRESS: flatbuffers::VOffsetT = 8; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + AdressbookEntry { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args AdressbookEntryArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = AdressbookEntryBuilder::new(_fbb); + if let Some(x) = args.address { builder.add_address(x); } + if let Some(x) = args.name { builder.add_name(x); } + builder.add_id_address(args.id_address); + builder.finish() + } + + + #[inline] + pub fn id_address(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(AdressbookEntry::VT_ID_ADDRESS, Some(0)).unwrap()} + } + #[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::>(AdressbookEntry::VT_NAME, None)} + } + #[inline] + pub fn address(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(AdressbookEntry::VT_ADDRESS, None)} + } +} + +impl flatbuffers::Verifiable for AdressbookEntry<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("id_address", Self::VT_ID_ADDRESS, false)? + .visit_field::>("name", Self::VT_NAME, false)? + .visit_field::>("address", Self::VT_ADDRESS, false)? + .finish(); + Ok(()) + } +} +pub struct AdressbookEntryArgs<'a> { + pub id_address: u32, + pub name: Option>, + pub address: Option>, +} +impl<'a> Default for AdressbookEntryArgs<'a> { + #[inline] + fn default() -> Self { + AdressbookEntryArgs { + id_address: 0, + name: None, + address: None, + } + } +} + +pub struct AdressbookEntryBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> AdressbookEntryBuilder<'a, 'b> { + #[inline] + pub fn add_id_address(&mut self, id_address: u32) { + self.fbb_.push_slot::(AdressbookEntry::VT_ID_ADDRESS, id_address, 0); + } + #[inline] + pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(AdressbookEntry::VT_NAME, name); + } + #[inline] + pub fn add_address(&mut self, address: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(AdressbookEntry::VT_ADDRESS, address); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AdressbookEntryBuilder<'a, 'b> { + let start = _fbb.start_table(); + AdressbookEntryBuilder { + 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 AdressbookEntry<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("AdressbookEntry"); + ds.field("id_address", &self.id_address()); + ds.field("name", &self.name()); + ds.field("address", &self.address()); + ds.finish() + } +} +pub enum AddressbookOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct Addressbook<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Addressbook<'a> { + type Inner = Addressbook<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> Addressbook<'a> { + pub const VT_ACCOUNTS: flatbuffers::VOffsetT = 4; + pub const VT_CONTACTS: flatbuffers::VOffsetT = 6; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Addressbook { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args AddressbookArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = AddressbookBuilder::new(_fbb); + if let Some(x) = args.contacts { builder.add_contacts(x); } + if let Some(x) = args.accounts { builder.add_accounts(x); } + builder.finish() + } + + + #[inline] + pub fn accounts(&self) -> Option>>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>>(Addressbook::VT_ACCOUNTS, None)} + } + #[inline] + pub fn contacts(&self) -> Option>>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>>(Addressbook::VT_CONTACTS, None)} + } +} + +impl flatbuffers::Verifiable for Addressbook<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>>("accounts", Self::VT_ACCOUNTS, false)? + .visit_field::>>>("contacts", Self::VT_CONTACTS, false)? + .finish(); + Ok(()) + } +} +pub struct AddressbookArgs<'a> { + pub accounts: Option>>>>, + pub contacts: Option>>>>, +} +impl<'a> Default for AddressbookArgs<'a> { + #[inline] + fn default() -> Self { + AddressbookArgs { + accounts: None, + contacts: None, + } + } +} + +pub struct AddressbookBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> AddressbookBuilder<'a, 'b> { + #[inline] + pub fn add_accounts(&mut self, accounts: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(Addressbook::VT_ACCOUNTS, accounts); + } + #[inline] + pub fn add_contacts(&mut self, contacts: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(Addressbook::VT_CONTACTS, contacts); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AddressbookBuilder<'a, 'b> { + let start = _fbb.start_table(); + AddressbookBuilder { + 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 Addressbook<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("Addressbook"); + ds.field("accounts", &self.accounts()); + ds.field("contacts", &self.contacts()); + ds.finish() + } +} +pub enum AccountBalanceOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct AccountBalance<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for AccountBalance<'a> { + type Inner = AccountBalance<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> AccountBalance<'a> { + pub const VT_COIN: flatbuffers::VOffsetT = 4; + pub const VT_ID_ACCOUNT: flatbuffers::VOffsetT = 6; + pub const VT_NAME: flatbuffers::VOffsetT = 8; + pub const VT_BALANCE: flatbuffers::VOffsetT = 10; + pub const VT_TBALANCE: flatbuffers::VOffsetT = 12; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + AccountBalance { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args AccountBalanceArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = AccountBalanceBuilder::new(_fbb); + builder.add_tbalance(args.tbalance); + builder.add_balance(args.balance); + if let Some(x) = args.name { builder.add_name(x); } + builder.add_id_account(args.id_account); + builder.add_coin(args.coin); + builder.finish() + } + + + #[inline] + pub fn coin(&self) -> u8 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(AccountBalance::VT_COIN, Some(0)).unwrap()} + } + #[inline] + pub fn id_account(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(AccountBalance::VT_ID_ACCOUNT, Some(0)).unwrap()} + } + #[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::>(AccountBalance::VT_NAME, None)} + } + #[inline] + pub fn balance(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(AccountBalance::VT_BALANCE, Some(0)).unwrap()} + } + #[inline] + pub fn tbalance(&self) -> u64 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(AccountBalance::VT_TBALANCE, Some(0)).unwrap()} + } +} + +impl flatbuffers::Verifiable for AccountBalance<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("coin", Self::VT_COIN, false)? + .visit_field::("id_account", Self::VT_ID_ACCOUNT, false)? + .visit_field::>("name", Self::VT_NAME, false)? + .visit_field::("balance", Self::VT_BALANCE, false)? + .visit_field::("tbalance", Self::VT_TBALANCE, false)? + .finish(); + Ok(()) + } +} +pub struct AccountBalanceArgs<'a> { + pub coin: u8, + pub id_account: u32, + pub name: Option>, + pub balance: u64, + pub tbalance: u64, +} +impl<'a> Default for AccountBalanceArgs<'a> { + #[inline] + fn default() -> Self { + AccountBalanceArgs { + coin: 0, + id_account: 0, + name: None, + balance: 0, + tbalance: 0, + } + } +} + +pub struct AccountBalanceBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> AccountBalanceBuilder<'a, 'b> { + #[inline] + pub fn add_coin(&mut self, coin: u8) { + self.fbb_.push_slot::(AccountBalance::VT_COIN, coin, 0); + } + #[inline] + pub fn add_id_account(&mut self, id_account: u32) { + self.fbb_.push_slot::(AccountBalance::VT_ID_ACCOUNT, id_account, 0); + } + #[inline] + pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(AccountBalance::VT_NAME, name); + } + #[inline] + pub fn add_balance(&mut self, balance: u64) { + self.fbb_.push_slot::(AccountBalance::VT_BALANCE, balance, 0); + } + #[inline] + pub fn add_tbalance(&mut self, tbalance: u64) { + self.fbb_.push_slot::(AccountBalance::VT_TBALANCE, tbalance, 0); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AccountBalanceBuilder<'a, 'b> { + let start = _fbb.start_table(); + AccountBalanceBuilder { + 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 AccountBalance<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("AccountBalance"); + ds.field("coin", &self.coin()); + ds.field("id_account", &self.id_account()); + ds.field("name", &self.name()); + ds.field("balance", &self.balance()); + ds.field("tbalance", &self.tbalance()); + ds.finish() + } +} +pub enum AccountBalancesOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct AccountBalances<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for AccountBalances<'a> { + type Inner = AccountBalances<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> AccountBalances<'a> { + pub const VT_ACCOUNTS: flatbuffers::VOffsetT = 4; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + AccountBalances { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args AccountBalancesArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = AccountBalancesBuilder::new(_fbb); + if let Some(x) = args.accounts { builder.add_accounts(x); } + builder.finish() + } + + + #[inline] + pub fn accounts(&self) -> Option>>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>>(AccountBalances::VT_ACCOUNTS, None)} + } +} + +impl flatbuffers::Verifiable for AccountBalances<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>>("accounts", Self::VT_ACCOUNTS, false)? + .finish(); + Ok(()) + } +} +pub struct AccountBalancesArgs<'a> { + pub accounts: Option>>>>, +} +impl<'a> Default for AccountBalancesArgs<'a> { + #[inline] + fn default() -> Self { + AccountBalancesArgs { + accounts: None, + } + } +} + +pub struct AccountBalancesBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> AccountBalancesBuilder<'a, 'b> { + #[inline] + pub fn add_accounts(&mut self, accounts: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(AccountBalances::VT_ACCOUNTS, accounts); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AccountBalancesBuilder<'a, 'b> { + let start = _fbb.start_table(); + AccountBalancesBuilder { + 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 AccountBalances<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("AccountBalances"); + ds.field("accounts", &self.accounts()); + ds.finish() + } +} +pub enum ZMessageOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct ZMessage<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ZMessage<'a> { + type Inner = ZMessage<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> ZMessage<'a> { + pub const VT_ID: flatbuffers::VOffsetT = 4; + pub const VT_TX_ID: flatbuffers::VOffsetT = 6; + pub const VT_INCOMING: flatbuffers::VOffsetT = 8; + pub const VT_SENDER: flatbuffers::VOffsetT = 10; + pub const VT_RECIPIENT: flatbuffers::VOffsetT = 12; + pub const VT_SUBJECT: flatbuffers::VOffsetT = 14; + pub const VT_BODY: flatbuffers::VOffsetT = 16; + pub const VT_TIMESTAMP: flatbuffers::VOffsetT = 18; + pub const VT_HEIGHT: flatbuffers::VOffsetT = 20; + pub const VT_READ: flatbuffers::VOffsetT = 22; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ZMessage { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ZMessageArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = ZMessageBuilder::new(_fbb); + builder.add_height(args.height); + builder.add_timestamp(args.timestamp); + if let Some(x) = args.body { builder.add_body(x); } + if let Some(x) = args.subject { builder.add_subject(x); } + if let Some(x) = args.recipient { builder.add_recipient(x); } + if let Some(x) = args.sender { builder.add_sender(x); } + builder.add_tx_id(args.tx_id); + builder.add_id(args.id); + builder.add_read(args.read); + builder.add_incoming(args.incoming); + builder.finish() + } + + + #[inline] + pub fn id(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ZMessage::VT_ID, Some(0)).unwrap()} + } + #[inline] + pub fn tx_id(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ZMessage::VT_TX_ID, Some(0)).unwrap()} + } + #[inline] + pub fn incoming(&self) -> bool { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ZMessage::VT_INCOMING, Some(false)).unwrap()} + } + #[inline] + pub fn sender(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(ZMessage::VT_SENDER, None)} + } + #[inline] + pub fn recipient(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(ZMessage::VT_RECIPIENT, None)} + } + #[inline] + pub fn subject(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(ZMessage::VT_SUBJECT, None)} + } + #[inline] + pub fn body(&self) -> Option<&'a str> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>(ZMessage::VT_BODY, None)} + } + #[inline] + pub fn timestamp(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ZMessage::VT_TIMESTAMP, Some(0)).unwrap()} + } + #[inline] + pub fn height(&self) -> u32 { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ZMessage::VT_HEIGHT, Some(0)).unwrap()} + } + #[inline] + pub fn read(&self) -> bool { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(ZMessage::VT_READ, Some(false)).unwrap()} + } +} + +impl flatbuffers::Verifiable for ZMessage<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::("id", Self::VT_ID, false)? + .visit_field::("tx_id", Self::VT_TX_ID, false)? + .visit_field::("incoming", Self::VT_INCOMING, false)? + .visit_field::>("sender", Self::VT_SENDER, false)? + .visit_field::>("recipient", Self::VT_RECIPIENT, false)? + .visit_field::>("subject", Self::VT_SUBJECT, false)? + .visit_field::>("body", Self::VT_BODY, false)? + .visit_field::("timestamp", Self::VT_TIMESTAMP, false)? + .visit_field::("height", Self::VT_HEIGHT, false)? + .visit_field::("read", Self::VT_READ, false)? + .finish(); + Ok(()) + } +} +pub struct ZMessageArgs<'a> { + pub id: u32, + pub tx_id: u32, + pub incoming: bool, + pub sender: Option>, + pub recipient: Option>, + pub subject: Option>, + pub body: Option>, + pub timestamp: u32, + pub height: u32, + pub read: bool, +} +impl<'a> Default for ZMessageArgs<'a> { + #[inline] + fn default() -> Self { + ZMessageArgs { + id: 0, + tx_id: 0, + incoming: false, + sender: None, + recipient: None, + subject: None, + body: None, + timestamp: 0, + height: 0, + read: false, + } + } +} + +pub struct ZMessageBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ZMessageBuilder<'a, 'b> { + #[inline] + pub fn add_id(&mut self, id: u32) { + self.fbb_.push_slot::(ZMessage::VT_ID, id, 0); + } + #[inline] + pub fn add_tx_id(&mut self, tx_id: u32) { + self.fbb_.push_slot::(ZMessage::VT_TX_ID, tx_id, 0); + } + #[inline] + pub fn add_incoming(&mut self, incoming: bool) { + self.fbb_.push_slot::(ZMessage::VT_INCOMING, incoming, false); + } + #[inline] + pub fn add_sender(&mut self, sender: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(ZMessage::VT_SENDER, sender); + } + #[inline] + pub fn add_recipient(&mut self, recipient: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(ZMessage::VT_RECIPIENT, recipient); + } + #[inline] + pub fn add_subject(&mut self, subject: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(ZMessage::VT_SUBJECT, subject); + } + #[inline] + pub fn add_body(&mut self, body: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(ZMessage::VT_BODY, body); + } + #[inline] + pub fn add_timestamp(&mut self, timestamp: u32) { + self.fbb_.push_slot::(ZMessage::VT_TIMESTAMP, timestamp, 0); + } + #[inline] + pub fn add_height(&mut self, height: u32) { + self.fbb_.push_slot::(ZMessage::VT_HEIGHT, height, 0); + } + #[inline] + pub fn add_read(&mut self, read: bool) { + self.fbb_.push_slot::(ZMessage::VT_READ, read, false); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ZMessageBuilder<'a, 'b> { + let start = _fbb.start_table(); + ZMessageBuilder { + 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 ZMessage<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("ZMessage"); + ds.field("id", &self.id()); + ds.field("tx_id", &self.tx_id()); + ds.field("incoming", &self.incoming()); + ds.field("sender", &self.sender()); + ds.field("recipient", &self.recipient()); + ds.field("subject", &self.subject()); + ds.field("body", &self.body()); + ds.field("timestamp", &self.timestamp()); + ds.field("height", &self.height()); + ds.field("read", &self.read()); + ds.finish() + } +} +pub enum ZMessagesOffset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct ZMessages<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ZMessages<'a> { + type Inner = ZMessages<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> ZMessages<'a> { + pub const VT_MESSAGES: flatbuffers::VOffsetT = 4; + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ZMessages { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ZMessagesArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = ZMessagesBuilder::new(_fbb); + if let Some(x) = args.messages { builder.add_messages(x); } + builder.finish() + } + + + #[inline] + pub fn messages(&self) -> Option>>> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>>(ZMessages::VT_MESSAGES, None)} + } +} + +impl flatbuffers::Verifiable for ZMessages<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>>("messages", Self::VT_MESSAGES, false)? + .finish(); + Ok(()) + } +} +pub struct ZMessagesArgs<'a> { + pub messages: Option>>>>, +} +impl<'a> Default for ZMessagesArgs<'a> { + #[inline] + fn default() -> Self { + ZMessagesArgs { + messages: None, + } + } +} + +pub struct ZMessagesBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ZMessagesBuilder<'a, 'b> { + #[inline] + pub fn add_messages(&mut self, messages: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(ZMessages::VT_MESSAGES, messages); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ZMessagesBuilder<'a, 'b> { + let start = _fbb.start_table(); + ZMessagesBuilder { + 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 ZMessages<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("ZMessages"); + ds.field("messages", &self.messages()); + ds.finish() + } +} +} // pub mod fb + diff --git a/src/db/read.rs b/src/db/read.rs new file mode 100644 index 0000000..db87c0d --- /dev/null +++ b/src/db/read.rs @@ -0,0 +1,315 @@ +use rusqlite::{Connection, OptionalExtension, params}; +use anyhow::Result; +use crate::db::data_generated::fb::*; +use crate::DbAdapter; + +pub fn has_account(connection: &Connection) -> Result { + let res = connection.query_row("SELECT 1 FROM accounts", [], |_| { Ok(()) }).optional()?; + Ok(res.is_some()) +} + +pub fn get_account_list(connection: &Connection) -> Result> { + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let mut stmt = connection.prepare("WITH notes AS (SELECT a.id_account, a.name, CASE WHEN r.spent IS NULL THEN r.value ELSE 0 END AS nv FROM accounts a LEFT JOIN received_notes r ON a.id_account = r.account), \ + accounts2 AS (SELECT id_account, name, COALESCE(sum(nv), 0) AS balance FROM notes GROUP by id_account) \ + SELECT a.id_account, a.name, a.balance FROM accounts2 a")?; + let rows = stmt.query_map([], |row| { + let id: u32 = row.get("id_account")?; + let name: String = row.get("name")?; + let balance: i64 = row.get("balance")?; + let name = builder.create_string(&name); + let account = Account::create(&mut builder, &AccountArgs { + id, + name: Some(name), + balance: balance as u64, + }); + Ok(account) + })?; + let mut accounts = vec![]; + for r in rows { + accounts.push(r?); + } + let accounts = builder.create_vector(&accounts); + let accounts = AccountVec::create(&mut builder, &AccountVecArgs { accounts: Some(accounts) }); + builder.finish(accounts, None); + let data = builder.finished_data().to_vec(); + Ok(data) +} + +pub fn get_available_account_id(connection: &Connection, id: u32) -> Result { + let r = connection.query_row("SELECT 1 FROM accounts WHERE id_account = ?1", [id], |_| { Ok(()) }).optional()?; + if r.is_some() { return Ok(id) } + let r = connection.query_row("SELECT MAX(id_account) FROM accounts", [], |row| { + let id: Option = row.get(0)?; + Ok(id) + })?.unwrap_or(0); + Ok(r) +} + +pub fn get_t_addr(connection: &Connection, id: u32) -> Result { + let address = connection.query_row("SELECT address FROM taddrs WHERE account = ?1", [id], |row| { + let address: String = row.get(0)?; + Ok(address) + })?; + Ok(address) +} + +pub fn get_sk(connection: &Connection, id: u32) -> Result { + let sk = connection.query_row("SELECT sk FROM accounts WHERE id_account = ?1", [id], |row| { + let sk: Option = row.get(0)?; + Ok(sk.unwrap_or(String::new())) + })?; + Ok(sk) +} + +pub fn update_account_name(connection: &Connection, id: u32, name: &str) -> Result<()> { + connection.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1", params![id, name])?; + Ok(()) +} + +pub fn get_balances(connection: &Connection, id: u32, confirmed_height: u32) -> Result> { + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let shielded = connection.query_row( + "SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL", + params![id], |row| { + let value: Option = row.get(0)?; + Ok(value.unwrap_or(0) as u64) + })?; // funds not spent yet + let unconfirmed_spent = connection.query_row( + "SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent = 0", + params![id], |row| { + let value: Option = row.get(0)?; + Ok(value.unwrap_or(0) as u64) + })?; // funds used in unconfirmed tx + let balance = shielded + unconfirmed_spent; + let under_confirmed = connection.query_row( + "SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL AND height > ?2", + params![id, confirmed_height], |row| { + let value: Option = row.get(0)?; + Ok(value.unwrap_or(0) as u64) + })?; // funds received but not old enough + let excluded = connection.query_row( + "SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL \ + AND height <= ?2 AND excluded", + params![id, confirmed_height], |row| { + let value: Option = row.get(0)?; + Ok(value.unwrap_or(0) as u64) + })?; // funds excluded from spending + let sapling = connection.query_row( + "SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL AND orchard = 0 AND height <= ?2", + params![id, confirmed_height], |row| { + let value: Option = row.get(0)?; + Ok(value.unwrap_or(0) as u64) + })?; + let orchard = connection.query_row( + "SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL AND orchard = 1 AND height <= ?2", + params![id, confirmed_height], |row| { + let value: Option = row.get(0)?; + Ok(value.unwrap_or(0) as u64) + })?; + + let balance = Balance::create(&mut builder, &BalanceArgs { + shielded, + unconfirmed_spent, + balance, + under_confirmed, + excluded, + sapling, + orchard + }); + builder.finish(balance, None); + let data = builder.finished_data().to_vec(); + Ok(data) +} + +pub fn get_db_height(connection: &Connection) -> Result> { + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let height = connection.query_row( + "SELECT height, timestamp FROM blocks WHERE height = (SELECT MAX(height) FROM blocks)", + [], |row| { + let height: u32 = row.get(0)?; + let timestamp: u32 = row.get(1)?; + let height = Height::create(&mut builder, &HeightArgs { + height, + timestamp, + }); + Ok(height) + }).optional()?; + let data = height.map(|h| { + builder.finish(h, None); + builder.finished_data().to_vec() + }).unwrap_or(vec![]); + Ok(data) +} + +pub fn get_notes(connection: &Connection, id: u32) -> Result> { + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let mut stmt = connection.prepare( + "SELECT n.id_note, n.height, n.value, t.timestamp, n.orchard, n.excluded, n.spent FROM received_notes n, transactions t \ + WHERE n.account = ?1 AND (n.spent IS NULL OR n.spent = 0) \ + AND n.tx = t.id_tx ORDER BY n.height DESC")?; + let rows = stmt.query_map(params![id], |row| { + let id: u32 = row.get("id_note")?; + let height: u32 = row.get("height")?; + let value: i64 = row.get("value")?; + let timestamp: u32 = row.get("timestamp")?; + let orchard: u8 = row.get("orchard")?; + let excluded: Option = row.get("excluded")?; + let spent: Option = row.get("spent")?; + let note = ShieldedNote::create(&mut builder, &ShieldedNoteArgs { + id, + height, + value: value as u64, + timestamp, + orchard: orchard == 1, + excluded: excluded.unwrap_or(false), + spent: spent.is_some() + }); + Ok(note) + })?; + let mut notes = vec![]; + for r in rows { + notes.push(r?); + } + let notes = builder.create_vector(¬es); + let notes = ShieldedNoteVec::create(&mut builder, &ShieldedNoteVecArgs { notes: Some(notes) }); + builder.finish(notes, None); + let data = builder.finished_data().to_vec(); + Ok(data) +} + + +/* final id = row['id_note']; + final height = row['height']; + final timestamp = DateTime.fromMillisecondsSinceEpoch(row['timestamp'] * 1000); + final orchard = row['orchard'] != 0; + final excluded = (row['excluded'] ?? 0) != 0; + final spent = row['spent'] == 0; + + + + + final rows = await db.rawQuery("SELECT height, timestamp FROM blocks WHERE height = (SELECT MAX(height) FROM blocks)"); + if (rows.isNotEmpty) { + final row = rows.first; + final height = row['height'] as int; + final timestampEpoch = row['timestamp'] as int; + final timestamp = DateTime.fromMillisecondsSinceEpoch(timestampEpoch * 1000); + final blockInfo = BlockInfo(height, timestamp); + return blockInfo; + } + return null; + + return Sqflite.firstIntValue(await db.rawQuery("SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL AND orchard = 0", + [id])) ?? 0; + } + + Future getOrchardBalance() async { + return Sqflite.firstIntValue(await db.rawQuery("SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL AND orchard = 1", + [id])) ?? 0; + + final balance = Sqflite.firstIntValue(await db.rawQuery( + "SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND (spent IS NULL OR spent = 0)", + [id])) ?? 0; + final shieldedBalance = Sqflite.firstIntValue(await db.rawQuery( + "SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL", + [id])) ?? 0; + final unconfirmedSpentBalance = Sqflite.firstIntValue(await db.rawQuery( + "SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent = 0", + [id])) ?? 0; + final underConfirmedBalance = Sqflite.firstIntValue(await db.rawQuery( + "SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL AND height > ?2", + [id, confirmHeight])) ?? 0; + final excludedBalance = Sqflite.firstIntValue(await db.rawQuery( + "SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL " + "AND height <= ?2 AND excluded", + [id, confirmHeight])) ?? 0; + + + "", [id]); + await db.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1", + + + final List res1 = await db.rawQuery( + "SELECT address FROM taddrs WHERE account = ?1", [id]); + final taddress = res1.isNotEmpty ? res1[0]['address'] : ""; + return taddress; + + + // check that the account still exists + // if not, pick any account + // if there are none, return 0 + Future getAvailableAccountId() async { + final List res1 = await db.rawQuery( + "SELECT 1 FROM accounts WHERE id_account = ?1", [id]); + if (res1.isNotEmpty) + return AccountId(coin, id); + final List res2 = await db.rawQuery( + "SELECT id_account FROM accounts", []); + if (res2.isNotEmpty) { + final id = res2[0]['id_account']; + return AccountId(coin, id); + } + return null; + } + + + + Future> getAccountList() async { + List accounts = []; + + final List res = await db.rawQuery( + "WITH notes AS (SELECT a.id_account, a.name, CASE WHEN r.spent IS NULL THEN r.value ELSE 0 END AS nv FROM accounts a LEFT JOIN received_notes r ON a.id_account = r.account)," + "accounts2 AS (SELECT id_account, name, COALESCE(sum(nv), 0) AS balance FROM notes GROUP by id_account) " + "SELECT a.id_account, a.name, a.balance FROM accounts2 a", + []); + for (var r in res) { + final int id = r['id_account']; + final account = Account( + coin, + id, + r['name'], + r['balance'], + 0, + null); + accounts.add(account); + } + return accounts; + } + + // check that the account still exists + // if not, pick any account + // if there are none, return 0 + Future getAvailableAccountId() async { + final List res1 = await db.rawQuery( + "SELECT 1 FROM accounts WHERE id_account = ?1", [id]); + if (res1.isNotEmpty) + return AccountId(coin, id); + final List res2 = await db.rawQuery( + "SELECT id_account FROM accounts", []); + if (res2.isNotEmpty) { + final id = res2[0]['id_account']; + return AccountId(coin, id); + } + return null; + } + + Future getTAddr() async { + final List res1 = await db.rawQuery( + "SELECT address FROM taddrs WHERE account = ?1", [id]); + final taddress = res1.isNotEmpty ? res1[0]['address'] : ""; + return taddress; + } + + Future getSK() async { + final List res1 = await db.rawQuery( + "SELECT sk FROM accounts WHERE id_account = ?1", [id]); + final sk = res1.isNotEmpty ? res1[0]['address'] : null; + return sk; + } + + Future changeAccountName(String name) async { + await db.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1", + [id, name]); + } + */ \ No newline at end of file