Compare commits

..

No commits in common. "eb925c21f7b868cb19af3d9abd0b6242f77ee506" and "dbbce675f5eee3ffedfbc077b9a07e9df614a107" have entirely different histories.

3 changed files with 106 additions and 242 deletions

View file

@ -77,7 +77,6 @@ import Zenith.Types
, TransparentSpendingKeyDB , TransparentSpendingKeyDB
, UnifiedAddressDB(..) , UnifiedAddressDB(..)
, ZcashNetDB(..) , ZcashNetDB(..)
, ZcashPool(..)
) )
share share
@ -247,15 +246,6 @@ share
position Int position Int
UniqueSSPos tx position UniqueSSPos tx position
deriving Show Eq deriving Show Eq
QrCode
address WalletAddressId OnDeleteCascade OnUpdateCascade
version ZcashPool
bytes BS.ByteString
height Int
width Int
name T.Text
UniqueQr address version
deriving Show Eq
|] |]
-- * Database functions -- * Database functions
@ -426,16 +416,6 @@ getWalletAddresses pool w = do
addrs <- mapM (getAddresses pool . entityKey) accs addrs <- mapM (getAddresses pool . entityKey) accs
return $ concat addrs return $ concat addrs
getExternalAddresses :: ConnectionPool -> IO [Entity WalletAddress]
getExternalAddresses pool = do
runNoLoggingT $
PS.retryOnBusy $
flip PS.runSqlPool pool $ do
select $ do
addrs <- from $ table @WalletAddress
where_ $ addrs ^. WalletAddressScope ==. val (ScopeDB External)
return addrs
-- | Returns the largest address index for the given account -- | Returns the largest address index for the given account
getMaxAddress :: getMaxAddress ::
ConnectionPool -- ^ The database path ConnectionPool -- ^ The database path
@ -568,41 +548,6 @@ getZcashTransactions pool b =
orderBy [asc $ txs ^. ZcashTransactionBlock] orderBy [asc $ txs ^. ZcashTransactionBlock]
return txs return txs
-- ** QR codes
-- | Functions to manage the QR codes stored in the database
saveQrCode ::
ConnectionPool -- ^ the connection pool
-> QrCode
-> NoLoggingT IO (Maybe (Entity QrCode))
saveQrCode pool qr =
PS.retryOnBusy $ flip PS.runSqlPool pool $ insertUniqueEntity qr
getQrCodes ::
ConnectionPool -- ^ the connection pool
-> WalletAddressId
-> IO [Entity QrCode]
getQrCodes pool wId =
runNoLoggingT $
PS.retryOnBusy $
flip PS.runSqlPool pool $ do
select $ do
qrs <- from $ table @QrCode
where_ $ qrs ^. QrCodeAddress ==. val wId
return qrs
getQrCode :: ConnectionPool -> ZcashPool -> WalletAddressId -> IO (Maybe QrCode)
getQrCode pool zp wId = do
r <-
runNoLoggingT $
PS.retryOnBusy $
flip PS.runSqlPool pool $ do
selectOne $ do
qrs <- from $ table @QrCode
where_ $ qrs ^. QrCodeAddress ==. val wId
where_ $ qrs ^. QrCodeVersion ==. val zp
return qrs
return $ entityVal <$> r
-- * Wallet -- * Wallet
-- | Get the block of the last transaction known to the wallet -- | Get the block of the last transaction known to the wallet
getMaxWalletBlock :: getMaxWalletBlock ::

View file

@ -15,7 +15,6 @@ import Data.Maybe (fromMaybe, isJust)
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as E import qualified Data.Text.Encoding as E
import Data.Time.Clock.POSIX (posixSecondsToUTCTime) import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import Database.Esqueleto.Experimental (ConnectionPool)
import Database.Persist import Database.Persist
import Lens.Micro ((&), (+~), (.~), (?~), (^.), set) import Lens.Micro ((&), (+~), (.~), (?~), (^.), set)
import Lens.Micro.TH import Lens.Micro.TH
@ -36,17 +35,6 @@ import Zenith.GUI.Theme
import Zenith.Types hiding (ZcashAddress) import Zenith.Types hiding (ZcashAddress)
import Zenith.Utils (displayAmount, showAddress) import Zenith.Utils (displayAmount, showAddress)
data AppEvent
= AppInit
| ShowMsg !T.Text
| CloseMsg
| WalletClicked
| AccountClicked
| SetPool !ZcashPool
| SwitchQr !(Maybe QrCode)
| SwitchAddr !Int
deriving (Eq, Show)
data AppModel = AppModel data AppModel = AppModel
{ _configuration :: !Config { _configuration :: !Config
, _network :: !ZcashNet , _network :: !ZcashNet
@ -63,11 +51,19 @@ data AppModel = AppModel
, _balance :: !Integer , _balance :: !Integer
, _unconfBalance :: !(Maybe Integer) , _unconfBalance :: !(Maybe Integer)
, _selPool :: !ZcashPool , _selPool :: !ZcashPool
, _qrCodeWidget :: !(Maybe QrCode)
} deriving (Eq, Show) } deriving (Eq, Show)
makeLenses ''AppModel makeLenses ''AppModel
data AppEvent
= AppInit
| ShowMsg !T.Text
| CloseMsg
| WalletClicked
| AccountClicked
| SetPool !ZcashPool
deriving (Eq, Show)
remixArrowRightWideLine :: T.Text remixArrowRightWideLine :: T.Text
remixArrowRightWideLine = toGlyph 0xF496 remixArrowRightWideLine = toGlyph 0xF496
@ -172,84 +168,108 @@ buildUI wenv model = widgetTree
"addrScroll" "addrScroll"
]) `styleBasic` ]) `styleBasic`
[padding 3, radius 2, bgColor white] [padding 3, radius 2, bgColor white]
, addrQRCode , addrQRCode currentAddress (model ^. selPool)
] ]
addrQRCode :: WidgetNode AppModel AppEvent addrQRCode ::
addrQRCode = Maybe (Entity WalletAddress)
box_ -> ZcashPool
[alignMiddle] -> WidgetNode AppModel AppEvent
(hstack addrQRCode wAddr zp =
[ filler case encodeText (defaultQRCodeOptions L) Utf8WithoutECI =<< dispAddr of
, vstack Just qr ->
[ box_ box_
[onClick (SetPool Orchard)] [alignMiddle]
(remixIcon remixShieldCheckFill `styleBasic` (hstack
[ textSize 14 [ filler
, padding 4 , vstack
, styleIf (model ^. selPool == Orchard) (bgColor btnColor) [ box_
, styleIf (model ^. selPool == Orchard) (textColor white) [onClick (SetPool Orchard)]
]) (remixIcon remixShieldCheckFill `styleBasic`
[ textSize 14
, padding 4
, styleIf
(model ^. selPool == Orchard)
(bgColor btnColor)
])
, filler
, box_
[onClick (SetPool Sapling)]
(remixIcon remixShieldLine `styleBasic`
[ textSize 14
, padding 4
, styleIf
(model ^. selPool == Sapling)
(bgColor btnColor)
])
, filler
, box_
[onClick (SetPool Transparent)]
(remixIcon remixDislikeLine `styleBasic`
[ textSize 14
, padding 4
, styleIf
(model ^. selPool == Transparent)
(bgColor btnColor)
])
]
, vstack
[ label
(case model ^. selPool of
Orchard -> "Unified"
Sapling -> "Legacy Shielded"
Transparent -> "Transparent"
Sprout -> "Unknown")
, imageMem_
(T.pack $ show zp)
(qrCodeBytes qr)
(qrCodeSize qr)
[fitNone]
]
, filler , filler
, box_ ])
[onClick (SetPool Sapling)] Nothing ->
(remixIcon remixShieldLine `styleBasic` box_ [alignMiddle] (image_ "./assets/2620_color.png" [fitFill])
[ textSize 14 where
, padding 4 qrCodeImg :: QRImage -> Image PixelRGBA8
, styleIf (model ^. selPool == Sapling) (bgColor btnColor) qrCodeImg qr = promoteImage (toImage 4 1 qr)
, styleIf (model ^. selPool == Sapling) (textColor white) qrCodeSize :: QRImage -> Size
]) qrCodeSize qr =
, filler Size
, box_ (fromIntegral $ imageWidth $ qrCodeImg qr)
[onClick (SetPool Transparent)] (fromIntegral $ imageHeight $ qrCodeImg qr)
(remixIcon remixDislikeLine `styleBasic` qrCodeBytes :: QRImage -> BS.ByteString
[ textSize 14 qrCodeBytes qr =
, padding 4 BS.pack $
, styleIf pixelFold
(model ^. selPool == Transparent) (\bs _ _ (PixelRGBA8 i j k l) -> bs <> [i, j, k, l])
(bgColor btnColor) []
, styleIf (qrCodeImg qr)
(model ^. selPool == Transparent) dispAddr :: Maybe T.Text
(textColor white) dispAddr =
]) case zp of
] Transparent ->
, vstack T.append "zcash:" . encodeTransparentReceiver (model ^. network) <$>
[ label (t_rec =<<
(case model ^. selPool of (isValidUnifiedAddress .
Orchard -> "Unified" E.encodeUtf8 . getUA . walletAddressUAddress . entityVal) =<<
Sapling -> "Legacy Shielded" wAddr)
Transparent -> "Transparent" Sapling ->
Sprout -> "Unknown") `styleBasic` T.append "zcash:" <$>
[textColor white] (getSaplingFromUA .
, box_ E.encodeUtf8 . getUA . walletAddressUAddress . entityVal =<<
[alignMiddle] wAddr)
(case model ^. qrCodeWidget of Orchard ->
Just qr -> T.append "zcash:" . getUA . walletAddressUAddress . entityVal <$>
imageMem_ wAddr
(qrCodeName qr) Sprout -> Nothing
(qrCodeBytes qr)
(Size
(fromIntegral $ qrCodeHeight qr)
(fromIntegral $ qrCodeWidth qr))
[fitWidth]
Nothing -> image_ "./assets/2620_color.png" [fitEither]) `styleBasic`
[bgColor white, height 100, width 100]
] `styleBasic`
[bgColor btnColor, border 2 btnColor]
, filler
] `styleBasic`
[bgColor white])
addrRow :: Int -> Entity WalletAddress -> WidgetNode AppModel AppEvent addrRow :: Int -> Entity WalletAddress -> WidgetNode AppModel AppEvent
addrRow idx wAddr = addrRow idx wAddr =
box_ box_
[onClick $ SwitchAddr idx, alignLeft] [onClick $ ShowMsg ("You clicked address " <> showt idx), alignLeft]
(label (label
(walletAddressName (entityVal wAddr) <> (walletAddressName (entityVal wAddr) <>
": " <> showAddress (walletAddressUAddress $ entityVal wAddr))) `styleBasic` ": " <> showAddress (walletAddressUAddress $ entityVal wAddr))) `styleBasic`
[ padding 1 [padding 1, borderB 1 gray]
, borderB 1 gray
, styleIf (model ^. selAddr == idx) (borderL 2 btnHiLite)
, styleIf (model ^. selAddr == idx) (borderR 2 btnHiLite)
]
txBox = txBox =
boxShadow $ boxShadow $
box_ box_
@ -307,74 +327,6 @@ buildUI wenv model = widgetTree
alert CloseMsg $ alert CloseMsg $
hstack [filler, label $ fromMaybe "" (model ^. msg), filler] hstack [filler, label $ fromMaybe "" (model ^. msg), filler]
generateQRCodes :: Config -> IO ()
generateQRCodes config = do
let dbFilePath = c_dbPath config
pool <- runNoLoggingT $ initPool dbFilePath
addrs <- getExternalAddresses pool
mapM_ (checkExistingQrs pool) addrs
where
checkExistingQrs :: ConnectionPool -> Entity WalletAddress -> IO ()
checkExistingQrs pool wAddr = do
s <- getQrCodes pool (entityKey wAddr)
if not (null s)
then return ()
else do
generateOneQr pool Orchard wAddr
generateOneQr pool Sapling wAddr
generateOneQr pool Transparent wAddr
generateOneQr ::
ConnectionPool -> ZcashPool -> Entity WalletAddress -> IO ()
generateOneQr p zp wAddr =
case encodeText (defaultQRCodeOptions L) Utf8WithoutECI =<<
dispAddr zp (entityVal wAddr) of
Just qr -> do
_ <-
runNoLoggingT $
saveQrCode p $
QrCode
(entityKey wAddr)
zp
(qrCodeData qr)
(qrCodeH qr)
(qrCodeW qr)
(walletAddressName (entityVal wAddr) <> T.pack (show zp))
return ()
Nothing -> return ()
qrCodeImg :: QRImage -> Image PixelRGBA8
qrCodeImg qr = promoteImage (toImage 4 2 qr)
qrCodeH :: QRImage -> Int
qrCodeH qr = fromIntegral $ imageHeight $ qrCodeImg qr
qrCodeW :: QRImage -> Int
qrCodeW qr = fromIntegral $ imageWidth $ qrCodeImg qr
qrCodeData :: QRImage -> BS.ByteString
qrCodeData qr =
BS.pack $
pixelFold
(\bs _ _ (PixelRGBA8 i j k l) -> bs <> [i, j, k, l])
[]
(qrCodeImg qr)
dispAddr :: ZcashPool -> WalletAddress -> Maybe T.Text
dispAddr zp w =
case zp of
Transparent ->
T.append "zcash:" .
encodeTransparentReceiver
(maybe
TestNet
ua_net
((isValidUnifiedAddress .
E.encodeUtf8 . getUA . walletAddressUAddress)
w)) <$>
(t_rec =<<
(isValidUnifiedAddress . E.encodeUtf8 . getUA . walletAddressUAddress)
w)
Sapling ->
T.append "zcash:" <$>
(getSaplingFromUA . E.encodeUtf8 . getUA . walletAddressUAddress) w
Orchard -> Just $ (T.append "zcash:" . getUA . walletAddressUAddress) w
Sprout -> Nothing
handleEvent :: handleEvent ::
WidgetEnv AppModel AppEvent WidgetEnv AppModel AppEvent
-> WidgetNode AppModel AppEvent -> WidgetNode AppModel AppEvent
@ -387,31 +339,8 @@ handleEvent wenv node model evt =
ShowMsg t -> [Model $ model & msg ?~ t] ShowMsg t -> [Model $ model & msg ?~ t]
WalletClicked -> [Model $ model & msg ?~ "You clicked Wallet!"] WalletClicked -> [Model $ model & msg ?~ "You clicked Wallet!"]
AccountClicked -> [Model $ model & msg ?~ "You clicked Account!"] AccountClicked -> [Model $ model & msg ?~ "You clicked Account!"]
SetPool p -> SetPool p -> [Model $ model & selPool .~ p]
[ Model $ model & selPool .~ p
, Task $
SwitchQr <$> do
dbPool <- runNoLoggingT $ initPool $ c_dbPath $ model ^. configuration
case currentAddress of
Nothing -> return Nothing
Just wAddr -> getQrCode dbPool p $ entityKey wAddr
]
SwitchQr q -> [Model $ model & qrCodeWidget .~ q]
SwitchAddr i -> [Model $ model & selAddr .~ i, Event $ SetPool Orchard]
CloseMsg -> [Model $ model & msg .~ Nothing] CloseMsg -> [Model $ model & msg .~ Nothing]
where
currentWallet =
if null (model ^. wallets)
then Nothing
else Just ((model ^. wallets) !! (model ^. selWallet))
currentAccount =
if null (model ^. accounts)
then Nothing
else Just ((model ^. accounts) !! (model ^. selAcc))
currentAddress =
if null (model ^. addresses)
then Nothing
else Just ((model ^. addresses) !! (model ^. selAddr))
runZenithGUI :: Config -> IO () runZenithGUI :: Config -> IO ()
runZenithGUI config = do runZenithGUI config = do
@ -429,7 +358,6 @@ runZenithGUI config = do
Left e1 -> throwIO e1 Left e1 -> throwIO e1
Right chainInfo -> do Right chainInfo -> do
initDb dbFilePath initDb dbFilePath
generateQRCodes config
walList <- getWallets pool $ zgb_net chainInfo walList <- getWallets pool $ zgb_net chainInfo
accList <- accList <-
if not (null walList) if not (null walList)
@ -443,10 +371,6 @@ runZenithGUI config = do
if not (null addrList) if not (null addrList)
then getUserTx pool $ entityKey $ head addrList then getUserTx pool $ entityKey $ head addrList
else return [] else return []
qr <-
if not (null addrList)
then getQrCode pool Orchard $ entityKey $ head addrList
else return Nothing
let model = let model =
AppModel AppModel
config config
@ -463,8 +387,7 @@ runZenithGUI config = do
True True
314259000 314259000
(Just 300000) (Just 300000)
Orchard Transparent
qr
startApp model handleEvent buildUI params startApp model handleEvent buildUI params
Left e -> do Left e -> do
initDb dbFilePath initDb dbFilePath
@ -487,12 +410,10 @@ runZenithGUI config = do
314259000 314259000
(Just 30000) (Just 30000)
Orchard Orchard
Nothing
startApp model handleEvent buildUI params startApp model handleEvent buildUI params
where where
params = params =
[ appWindowTitle "Zenith - Zcash Full Node Wallet" [ appWindowTitle "Zenith - Zcash Full Node Wallet"
, appWindowState $ MainWindowNormal (1000, 600)
, appTheme zenithTheme , appTheme zenithTheme
, appFontDef "Regular" "./assets/Atkinson-Hyperlegible-Regular-102.ttf" --"./assets/DejaVuSansMono.ttf" , appFontDef "Regular" "./assets/Atkinson-Hyperlegible-Regular-102.ttf" --"./assets/DejaVuSansMono.ttf"
, appFontDef "Bold" "./assets/Atkinson-Hyperlegible-Bold-102.ttf" , appFontDef "Bold" "./assets/Atkinson-Hyperlegible-Bold-102.ttf"

View file

@ -143,9 +143,7 @@ data ZcashPool
| Sprout | Sprout
| Sapling | Sapling
| Orchard | Orchard
deriving (Show, Read, Eq, Generic, ToJSON) deriving (Show, Eq, Generic, ToJSON)
derivePersistField "ZcashPool"
instance FromJSON ZcashPool where instance FromJSON ZcashPool where
parseJSON = parseJSON =