Milestone 3: RPC server, ZIP-320 #104
4 changed files with 87 additions and 38 deletions
|
@ -10,7 +10,7 @@ import qualified Brick.BChan as BC
|
||||||
import qualified Brick.Focus as F
|
import qualified Brick.Focus as F
|
||||||
import Brick.Forms
|
import Brick.Forms
|
||||||
( Form(..)
|
( Form(..)
|
||||||
, radioField
|
, (@@=)
|
||||||
, allFieldsValid
|
, allFieldsValid
|
||||||
, editShowableFieldWithValidate
|
, editShowableFieldWithValidate
|
||||||
, editTextField
|
, editTextField
|
||||||
|
@ -18,10 +18,10 @@ import Brick.Forms
|
||||||
, handleFormEvent
|
, handleFormEvent
|
||||||
, invalidFormInputAttr
|
, invalidFormInputAttr
|
||||||
, newForm
|
, newForm
|
||||||
|
, radioField
|
||||||
, renderForm
|
, renderForm
|
||||||
, setFieldValid
|
, setFieldValid
|
||||||
, updateFormState
|
, updateFormState
|
||||||
, (@@=)
|
|
||||||
)
|
)
|
||||||
import qualified Brick.Main as M
|
import qualified Brick.Main as M
|
||||||
import qualified Brick.Types as BT
|
import qualified Brick.Types as BT
|
||||||
|
@ -99,9 +99,9 @@ import Zenith.Types
|
||||||
( Config(..)
|
( Config(..)
|
||||||
, HexStringDB(..)
|
, HexStringDB(..)
|
||||||
, PhraseDB(..)
|
, PhraseDB(..)
|
||||||
|
, PrivacyPolicy(..)
|
||||||
, UnifiedAddressDB(..)
|
, UnifiedAddressDB(..)
|
||||||
, ZcashNetDB(..)
|
, ZcashNetDB(..)
|
||||||
, PrivacyPolicy(..)
|
|
||||||
)
|
)
|
||||||
import Zenith.Utils
|
import Zenith.Utils
|
||||||
( displayTaz
|
( displayTaz
|
||||||
|
@ -184,7 +184,8 @@ data Tick
|
||||||
| TickMsg !String
|
| TickMsg !String
|
||||||
| TickTx !HexString
|
| TickTx !HexString
|
||||||
|
|
||||||
data DropDownItem = DropdownItem String
|
data DropDownItem =
|
||||||
|
DropdownItem String
|
||||||
|
|
||||||
data State = State
|
data State = State
|
||||||
{ _network :: !ZcashNet
|
{ _network :: !ZcashNet
|
||||||
|
@ -619,11 +620,13 @@ mkSendForm :: Integer -> SendInput -> Form SendInput e Name
|
||||||
mkSendForm bal =
|
mkSendForm bal =
|
||||||
newForm
|
newForm
|
||||||
[ label "Privacy Level :" @@=
|
[ label "Privacy Level :" @@=
|
||||||
radioField policyField [ (Full, PrivacyFullField, "Full")
|
radioField
|
||||||
, (Medium, PrivacyMediumField, "Medium")
|
policyField
|
||||||
, (Low, PrivacyLowField, "Low")
|
[ (Full, PrivacyFullField, "Full")
|
||||||
, (None, PrivacyNoneField, "None")
|
, (Medium, PrivacyMediumField, "Medium")
|
||||||
]
|
, (Low, PrivacyLowField, "Low")
|
||||||
|
, (None, PrivacyNoneField, "None")
|
||||||
|
]
|
||||||
, label "To: " @@= editTextField sendTo RecField (Just 1)
|
, label "To: " @@= editTextField sendTo RecField (Just 1)
|
||||||
, label "Amount: " @@=
|
, label "Amount: " @@=
|
||||||
editShowableFieldWithValidate sendAmt AmtField (isAmountValid bal)
|
editShowableFieldWithValidate sendAmt AmtField (isAmountValid bal)
|
||||||
|
@ -1403,6 +1406,7 @@ runZenithTUI config = do
|
||||||
Left e1 -> throwIO e1
|
Left e1 -> throwIO e1
|
||||||
Right chainInfo -> do
|
Right chainInfo -> do
|
||||||
x <- initDb dbFilePath
|
x <- initDb dbFilePath
|
||||||
|
_ <- upgradeQrTable pool
|
||||||
case x of
|
case x of
|
||||||
Left e2 -> throwIO $ userError e2
|
Left e2 -> throwIO $ userError e2
|
||||||
Right x' -> do
|
Right x' -> do
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
module Zenith.DB where
|
module Zenith.DB where
|
||||||
|
|
||||||
import Control.Exception (SomeException(..), throw, throwIO, try)
|
import Control.Exception (SomeException(..), throw, throwIO, try)
|
||||||
import Control.Monad (when)
|
import Control.Monad (unless, when)
|
||||||
import Control.Monad.IO.Class (MonadIO, liftIO)
|
import Control.Monad.IO.Class (MonadIO, liftIO)
|
||||||
import Control.Monad.Logger (NoLoggingT, runNoLoggingT)
|
import Control.Monad.Logger (NoLoggingT, runNoLoggingT)
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
|
@ -448,8 +448,10 @@ initDb dbName = do
|
||||||
(Either SomeException [T.Text])
|
(Either SomeException [T.Text])
|
||||||
case m of
|
case m of
|
||||||
Left e2 -> return $ Left $ "Failed to migrate data tables" ++ show e2
|
Left e2 -> return $ Left $ "Failed to migrate data tables" ++ show e2
|
||||||
Right _ -> return $ Right True
|
Right _ -> do
|
||||||
Right _ -> return $ Right False
|
return $ Right True
|
||||||
|
Right _ -> do
|
||||||
|
return $ Right False
|
||||||
|
|
||||||
initPool :: T.Text -> NoLoggingT IO ConnectionPool
|
initPool :: T.Text -> NoLoggingT IO ConnectionPool
|
||||||
initPool dbPath = do
|
initPool dbPath = do
|
||||||
|
@ -839,6 +841,32 @@ getQrCode pool zp wId = do
|
||||||
return qrs
|
return qrs
|
||||||
return $ entityVal <$> r
|
return $ entityVal <$> r
|
||||||
|
|
||||||
|
upgradeQrTable :: ConnectionPool -> IO ()
|
||||||
|
upgradeQrTable pool = do
|
||||||
|
r <-
|
||||||
|
runNoLoggingT $
|
||||||
|
PS.retryOnBusy $
|
||||||
|
flip PS.runSqlPool pool $
|
||||||
|
selectOne $ do
|
||||||
|
qrs <- from $ table @QrCode
|
||||||
|
where_ $ qrs ^. QrCodeVersion ==. val OrchardPool
|
||||||
|
return countRows
|
||||||
|
unless (maybe 0 (\(Value x) -> x) r > (0 :: Int)) $ do
|
||||||
|
_ <-
|
||||||
|
runNoLoggingT $
|
||||||
|
PS.retryOnBusy $
|
||||||
|
flip PS.runSqlPool pool $ do
|
||||||
|
rawExecute
|
||||||
|
"update qr_code set version = ? where version = ?"
|
||||||
|
[PersistText "OrchardPool", PersistText "Orchard"]
|
||||||
|
rawExecute
|
||||||
|
"update qr_code set version = ? where version = ?"
|
||||||
|
[PersistText "SaplingPool", PersistText "Sapling"]
|
||||||
|
rawExecute
|
||||||
|
"update qr_code set version = ? where version = ?"
|
||||||
|
[PersistText "TransparentPool", PersistText "Transparent"]
|
||||||
|
return ()
|
||||||
|
|
||||||
-- * 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 ::
|
||||||
|
|
|
@ -32,7 +32,11 @@ import Text.Printf
|
||||||
import Text.Wrap (FillScope(..), FillStrategy(..), WrapSettings(..), wrapText)
|
import Text.Wrap (FillScope(..), FillStrategy(..), WrapSettings(..), wrapText)
|
||||||
import TextShow hiding (toText)
|
import TextShow hiding (toText)
|
||||||
import ZcashHaskell.Keys (generateWalletSeedPhrase)
|
import ZcashHaskell.Keys (generateWalletSeedPhrase)
|
||||||
import ZcashHaskell.Orchard (getSaplingFromUA, isValidUnifiedAddress)
|
import ZcashHaskell.Orchard
|
||||||
|
( getSaplingFromUA
|
||||||
|
, isValidUnifiedAddress
|
||||||
|
, parseAddress
|
||||||
|
)
|
||||||
import ZcashHaskell.Transparent (encodeTransparentReceiver)
|
import ZcashHaskell.Transparent (encodeTransparentReceiver)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( BlockResponse(..)
|
( BlockResponse(..)
|
||||||
|
@ -51,13 +55,11 @@ import Zenith.Scanner (checkIntegrity, processTx, rescanZebra, updateConfs)
|
||||||
import Zenith.Types hiding (ZcashAddress(..))
|
import Zenith.Types hiding (ZcashAddress(..))
|
||||||
import Zenith.Utils
|
import Zenith.Utils
|
||||||
( displayAmount
|
( displayAmount
|
||||||
, isRecipientValid
|
|
||||||
, isRecipientValidGUI
|
, isRecipientValidGUI
|
||||||
, isZecAddressValid
|
|
||||||
, isValidString
|
, isValidString
|
||||||
|
, isZecAddressValid
|
||||||
, jsonNumber
|
, jsonNumber
|
||||||
, padWithZero
|
, padWithZero
|
||||||
, parseAddressUA
|
|
||||||
, showAddress
|
, showAddress
|
||||||
, validBarValue
|
, validBarValue
|
||||||
)
|
)
|
||||||
|
@ -604,29 +606,29 @@ buildUI wenv model = widgetTree
|
||||||
[textFont "Bold", textSize 12])
|
[textFont "Bold", textSize 12])
|
||||||
, separatorLine `styleBasic` [fgColor btnColor]
|
, separatorLine `styleBasic` [fgColor btnColor]
|
||||||
, spacer
|
, spacer
|
||||||
, hstack
|
, hstack
|
||||||
[
|
[ label "Privacy Level:" `styleBasic`
|
||||||
label "Privacy Level:" `styleBasic` [width 70, textFont "Bold"]
|
[width 70, textFont "Bold"]
|
||||||
, spacer
|
, spacer
|
||||||
, label "Full " `styleBasic` [width 40]
|
, label "Full " `styleBasic` [width 40]
|
||||||
, radio Full privacyChoice
|
, radio Full privacyChoice
|
||||||
, spacer
|
, spacer
|
||||||
, label "Medium " `styleBasic` [width 40]
|
, label "Medium " `styleBasic` [width 40]
|
||||||
, radio Medium privacyChoice
|
, radio Medium privacyChoice
|
||||||
]
|
]
|
||||||
, hstack
|
, hstack
|
||||||
[
|
[ label " " `styleBasic`
|
||||||
label " " `styleBasic` [width 70, textFont "Bold"]
|
[width 70, textFont "Bold"]
|
||||||
, spacer
|
, spacer
|
||||||
, label "Low " `styleBasic` [width 40]
|
, label "Low " `styleBasic` [width 40]
|
||||||
, radio Low privacyChoice
|
, radio Low privacyChoice
|
||||||
, spacer
|
, spacer
|
||||||
, label "None " `styleBasic` [width 40]
|
, label "None " `styleBasic` [width 40]
|
||||||
, radio None privacyChoice
|
, radio None privacyChoice
|
||||||
]
|
]
|
||||||
, spacer
|
, spacer
|
||||||
, hstack
|
, hstack
|
||||||
[ label "To:" `styleBasic` [width 50, textFont "Bold"]
|
[ label "To:" `styleBasic` [width 50, textFont "Bold"]
|
||||||
, spacer
|
, spacer
|
||||||
, textField_ sendRecipient [onChange CheckRecipient] `styleBasic`
|
, textField_ sendRecipient [onChange CheckRecipient] `styleBasic`
|
||||||
[ width 150
|
[ width 150
|
||||||
|
@ -636,7 +638,8 @@ buildUI wenv model = widgetTree
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
, hstack
|
, hstack
|
||||||
[ label "Amount:" `styleBasic` [width 50, textFont "Bold"]
|
[ label "Amount:" `styleBasic`
|
||||||
|
[width 50, textFont "Bold"]
|
||||||
, spacer
|
, spacer
|
||||||
, numericField_
|
, numericField_
|
||||||
sendAmount
|
sendAmount
|
||||||
|
@ -654,7 +657,8 @@ buildUI wenv model = widgetTree
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
, hstack
|
, hstack
|
||||||
[ label "Memo:" `styleBasic` [width 50, textFont "Bold"]
|
[ label "Memo:" `styleBasic`
|
||||||
|
[width 50, textFont "Bold"]
|
||||||
, spacer
|
, spacer
|
||||||
, textArea sendMemo `styleBasic`
|
, textArea sendMemo `styleBasic`
|
||||||
[width 150, height 40]
|
[width 150, height 40]
|
||||||
|
@ -1079,7 +1083,11 @@ handleEvent wenv node model evt =
|
||||||
]
|
]
|
||||||
ConfirmCancel -> [Model $ model & confirmTitle .~ Nothing & mainInput .~ ""]
|
ConfirmCancel -> [Model $ model & confirmTitle .~ Nothing & mainInput .~ ""]
|
||||||
ShowSeed -> [Model $ model & showSeed .~ True & menuPopup .~ False]
|
ShowSeed -> [Model $ model & showSeed .~ True & menuPopup .~ False]
|
||||||
ShowSend -> [Model $ model & openSend .~ True & privacyChoice .~ Full & recipientValid .~ False]
|
ShowSend ->
|
||||||
|
[ Model $
|
||||||
|
model & openSend .~ True & privacyChoice .~ Full & recipientValid .~
|
||||||
|
False
|
||||||
|
]
|
||||||
SendTx ->
|
SendTx ->
|
||||||
case currentAccount of
|
case currentAccount of
|
||||||
Nothing -> [Event $ ShowError "No account available", Event CancelSend]
|
Nothing -> [Event $ ShowError "No account available", Event CancelSend]
|
||||||
|
@ -1097,6 +1105,7 @@ handleEvent wenv node model evt =
|
||||||
(model ^. sendAmount)
|
(model ^. sendAmount)
|
||||||
(model ^. sendRecipient)
|
(model ^. sendRecipient)
|
||||||
(model ^. sendMemo)
|
(model ^. sendMemo)
|
||||||
|
(model ^. privacyChoice)
|
||||||
, Event CancelSend
|
, Event CancelSend
|
||||||
]
|
]
|
||||||
CancelSend ->
|
CancelSend ->
|
||||||
|
@ -1262,10 +1271,11 @@ handleEvent wenv node model evt =
|
||||||
("Wallet Sync: " <>
|
("Wallet Sync: " <>
|
||||||
T.pack (printf "%.2f%%" (model ^. barValue * 100)))
|
T.pack (printf "%.2f%%" (model ^. barValue * 100)))
|
||||||
]
|
]
|
||||||
ResetRecipientValid -> [Model $ model & recipientValid .~ False]
|
ResetRecipientValid -> [Model $ model & recipientValid .~ False]
|
||||||
CheckRecipient a -> [Model $
|
CheckRecipient a ->
|
||||||
model & recipientValid .~ isRecipientValidGUI (model ^.privacyChoice) a ]
|
[ Model $
|
||||||
-- model & recipientValid .~ ((model ^. privacyChoice) == Low) ]
|
model & recipientValid .~ isRecipientValidGUI (model ^. privacyChoice) a
|
||||||
|
]
|
||||||
CheckAmount i ->
|
CheckAmount i ->
|
||||||
[ Model $
|
[ Model $
|
||||||
model & amountValid .~
|
model & amountValid .~
|
||||||
|
@ -1465,6 +1475,7 @@ handleEvent wenv node model evt =
|
||||||
res <- liftIO $ updateAdrsInAdrBook pool d a a
|
res <- liftIO $ updateAdrsInAdrBook pool d a a
|
||||||
return $ ShowMessage "Address Book entry updated!!"
|
return $ ShowMessage "Address Book entry updated!!"
|
||||||
|
|
||||||
|
-- model & recipientValid .~ ((model ^. privacyChoice) == Low) ]
|
||||||
scanZebra :: T.Text -> T.Text -> Int -> ZcashNet -> (AppEvent -> IO ()) -> IO ()
|
scanZebra :: T.Text -> T.Text -> Int -> ZcashNet -> (AppEvent -> IO ()) -> IO ()
|
||||||
scanZebra dbPath zHost zPort net sendMsg = do
|
scanZebra dbPath zHost zPort net sendMsg = do
|
||||||
bStatus <- liftIO $ checkBlockChain zHost zPort
|
bStatus <- liftIO $ checkBlockChain zHost zPort
|
||||||
|
@ -1533,20 +1544,21 @@ sendTransaction ::
|
||||||
-> Float
|
-> Float
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> T.Text
|
-> T.Text
|
||||||
|
-> PrivacyPolicy
|
||||||
-> (AppEvent -> IO ())
|
-> (AppEvent -> IO ())
|
||||||
-> IO ()
|
-> IO ()
|
||||||
sendTransaction config znet accId bl amt ua memo sendMsg = do
|
sendTransaction config znet accId bl amt ua memo policy sendMsg = do
|
||||||
sendMsg $ ShowModal "Preparing transaction..."
|
sendMsg $ ShowModal "Preparing transaction..."
|
||||||
case parseAddressUA ua znet of
|
case parseAddress (E.encodeUtf8 ua) of
|
||||||
Nothing -> sendMsg $ ShowError "Incorrect address"
|
Nothing -> sendMsg $ ShowError "Incorrect address"
|
||||||
Just outUA -> do
|
Just addr -> do
|
||||||
let dbPath = c_dbPath config
|
let dbPath = c_dbPath config
|
||||||
let zHost = c_zebraHost config
|
let zHost = c_zebraHost config
|
||||||
let zPort = c_zebraPort config
|
let zPort = c_zebraPort config
|
||||||
pool <- runNoLoggingT $ initPool dbPath
|
pool <- runNoLoggingT $ initPool dbPath
|
||||||
res <-
|
res <-
|
||||||
runFileLoggingT "zenith.log" $
|
runFileLoggingT "zenith.log" $
|
||||||
prepareTx pool zHost zPort znet accId bl amt outUA memo
|
prepareTxV2 pool zHost zPort znet accId bl amt addr memo policy
|
||||||
case res of
|
case res of
|
||||||
Left e -> sendMsg $ ShowError $ T.pack $ show e
|
Left e -> sendMsg $ ShowError $ T.pack $ show e
|
||||||
Right rawTx -> do
|
Right rawTx -> do
|
||||||
|
@ -1593,6 +1605,7 @@ runZenithGUI config = do
|
||||||
Left e1 -> throwIO e1
|
Left e1 -> throwIO e1
|
||||||
Right chainInfo -> do
|
Right chainInfo -> do
|
||||||
x <- initDb dbFilePath
|
x <- initDb dbFilePath
|
||||||
|
_ <- upgradeQrTable pool
|
||||||
case x of
|
case x of
|
||||||
Left e2 -> throwIO $ userError e2
|
Left e2 -> throwIO $ userError e2
|
||||||
Right x' -> do
|
Right x' -> do
|
||||||
|
|
|
@ -48,6 +48,7 @@ import Zenith.DB
|
||||||
, saveConfs
|
, saveConfs
|
||||||
, saveTransaction
|
, saveTransaction
|
||||||
, updateWalletSync
|
, updateWalletSync
|
||||||
|
, upgradeQrTable
|
||||||
)
|
)
|
||||||
import Zenith.Types (Config(..), HexStringDB(..), ZcashNetDB(..))
|
import Zenith.Types (Config(..), HexStringDB(..), ZcashNetDB(..))
|
||||||
import Zenith.Utils (jsonNumber)
|
import Zenith.Utils (jsonNumber)
|
||||||
|
@ -69,6 +70,8 @@ rescanZebra host port dbFilePath = do
|
||||||
pool1 <- runNoLoggingT $ initPool dbFilePath
|
pool1 <- runNoLoggingT $ initPool dbFilePath
|
||||||
{-pool2 <- runNoLoggingT $ initPool dbFilePath-}
|
{-pool2 <- runNoLoggingT $ initPool dbFilePath-}
|
||||||
{-pool3 <- runNoLoggingT $ initPool dbFilePath-}
|
{-pool3 <- runNoLoggingT $ initPool dbFilePath-}
|
||||||
|
_ <- initDb dbFilePath
|
||||||
|
upgradeQrTable pool1
|
||||||
clearWalletTransactions pool1
|
clearWalletTransactions pool1
|
||||||
clearWalletData pool1
|
clearWalletData pool1
|
||||||
dbBlock <- getMaxBlock pool1 znet
|
dbBlock <- getMaxBlock pool1 znet
|
||||||
|
@ -211,6 +214,7 @@ clearSync config = do
|
||||||
Left e1 -> throwIO e1
|
Left e1 -> throwIO e1
|
||||||
Right chainInfo -> do
|
Right chainInfo -> do
|
||||||
x <- initDb dbPath
|
x <- initDb dbPath
|
||||||
|
_ <- upgradeQrTable pool
|
||||||
case x of
|
case x of
|
||||||
Left e2 -> throwIO $ userError e2
|
Left e2 -> throwIO $ userError e2
|
||||||
Right x' -> do
|
Right x' -> do
|
||||||
|
|
Loading…
Reference in a new issue