Merge pull request 'New Wallet creation flow' (#67) from rav001 into dev041
Reviewed-on: #67
This commit is contained in:
commit
43970a8393
9 changed files with 223 additions and 106 deletions
|
@ -36,13 +36,13 @@ Zenith is a command-line interface for the Zcash Full Node (`zcashd`). It has th
|
||||||
git clone https://git.vergara.tech/Vergara_Tech/zenith.git
|
git clone https://git.vergara.tech/Vergara_Tech/zenith.git
|
||||||
cd zenith
|
cd zenith
|
||||||
git submodule init
|
git submodule init
|
||||||
git submodule update
|
git submodule update --remote
|
||||||
```
|
```
|
||||||
|
|
||||||
- Install using `stack`:
|
- Install using `cabal`:
|
||||||
|
|
||||||
```
|
```
|
||||||
stack install
|
cabal install
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
|
@ -199,7 +199,7 @@ main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
config <- load ["zenith.cfg"]
|
config <- load ["zenith.cfg"]
|
||||||
args <- getArgs
|
args <- getArgs
|
||||||
dbName <- require config "dbName"
|
dbFilePath <- require config "dbFilePath"
|
||||||
nodeUser <- require config "nodeUser"
|
nodeUser <- require config "nodeUser"
|
||||||
nodePwd <- require config "nodePwd"
|
nodePwd <- require config "nodePwd"
|
||||||
zebraPort <- require config "zebraPort"
|
zebraPort <- require config "zebraPort"
|
||||||
|
@ -217,7 +217,7 @@ main = do
|
||||||
" ______ _ _ _ \n |___ / (_) | | | \n / / ___ _ __ _| |_| |__ \n / / / _ \\ '_ \\| | __| '_ \\ \n / /_| __/ | | | | |_| | | |\n /_____\\___|_| |_|_|\\__|_| |_|\n Zcash Full Node CLI v0.4.0"
|
" ______ _ _ _ \n |___ / (_) | | | \n / / ___ _ __ _| |_| |__ \n / / / _ \\ '_ \\| | __| '_ \\ \n / /_| __/ | | | | |_| | | |\n /_____\\___|_| |_|_|\\__|_| |_|\n Zcash Full Node CLI v0.4.0"
|
||||||
}
|
}
|
||||||
(root nodeUser nodePwd)
|
(root nodeUser nodePwd)
|
||||||
"cli" -> runZenithCLI zebraHost zebraPort dbName
|
"cli" -> runZenithCLI zebraHost zebraPort dbFilePath
|
||||||
_ -> printUsage
|
_ -> printUsage
|
||||||
else printUsage
|
else printUsage
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ module Zenith.CLI where
|
||||||
|
|
||||||
import Control.Monad (void)
|
import Control.Monad (void)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Data.Maybe (fromMaybe)
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Graphics.Vty as V
|
import qualified Graphics.Vty as V
|
||||||
import Lens.Micro ((&), (.~), (^.), set)
|
import Lens.Micro ((&), (.~), (^.), set)
|
||||||
|
@ -22,6 +21,7 @@ import Brick.Forms
|
||||||
, handleFormEvent
|
, handleFormEvent
|
||||||
, newForm
|
, newForm
|
||||||
, renderForm
|
, renderForm
|
||||||
|
, 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
|
||||||
|
@ -42,6 +42,7 @@ import Brick.Widgets.Core
|
||||||
, padBottom
|
, padBottom
|
||||||
, padRight
|
, padRight
|
||||||
, str
|
, str
|
||||||
|
, txt
|
||||||
, vBox
|
, vBox
|
||||||
, vLimit
|
, vLimit
|
||||||
, withAttr
|
, withAttr
|
||||||
|
@ -51,7 +52,7 @@ import qualified Brick.Widgets.Dialog as D
|
||||||
import qualified Brick.Widgets.List as L
|
import qualified Brick.Widgets.List as L
|
||||||
import qualified Data.Vector as Vec
|
import qualified Data.Vector as Vec
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Network.HTTP.Simple
|
import ZcashHaskell.Keys (generateWalletSeedPhrase)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
import Zenith.Core
|
import Zenith.Core
|
||||||
import Zenith.DB
|
import Zenith.DB
|
||||||
|
@ -61,14 +62,19 @@ data Name
|
||||||
| AList
|
| AList
|
||||||
| TList
|
| TList
|
||||||
| HelpDialog
|
| HelpDialog
|
||||||
| WalNameField
|
| DialogInputField
|
||||||
deriving (Eq, Show, Ord)
|
deriving (Eq, Show, Ord)
|
||||||
|
|
||||||
data WalletName = WalletName
|
data DialogInput = DialogInput
|
||||||
{ _walName :: !T.Text
|
{ _dialogInput :: !T.Text
|
||||||
} deriving (Show)
|
} deriving (Show)
|
||||||
|
|
||||||
makeLenses ''WalletName
|
makeLenses ''DialogInput
|
||||||
|
|
||||||
|
data DialogType
|
||||||
|
= WName
|
||||||
|
| AName
|
||||||
|
| Blank
|
||||||
|
|
||||||
data State = State
|
data State = State
|
||||||
{ _network :: !String
|
{ _network :: !String
|
||||||
|
@ -77,25 +83,36 @@ data State = State
|
||||||
, _transactions :: !(L.List Name String)
|
, _transactions :: !(L.List Name String)
|
||||||
, _msg :: !String
|
, _msg :: !String
|
||||||
, _helpBox :: !Bool
|
, _helpBox :: !Bool
|
||||||
, _walletBox :: !Bool
|
, _dialogBox :: !DialogType
|
||||||
, _splashBox :: !Bool
|
, _splashBox :: !Bool
|
||||||
, _walletForm :: !(Form WalletName () Name)
|
, _inputForm :: !(Form DialogInput () Name)
|
||||||
, _focusRing :: !(F.FocusRing Name)
|
, _focusRing :: !(F.FocusRing Name)
|
||||||
|
, _startBlock :: !Int
|
||||||
|
, _dbPath :: !T.Text
|
||||||
}
|
}
|
||||||
|
|
||||||
makeLenses ''State
|
makeLenses ''State
|
||||||
|
|
||||||
drawUI :: State -> [Widget Name]
|
drawUI :: State -> [Widget Name]
|
||||||
drawUI s = [splashDialog s, helpDialog s, walletDialog s, ui s]
|
drawUI s = [splashDialog s, helpDialog s, inputDialog s, ui s]
|
||||||
where
|
where
|
||||||
ui :: State -> Widget Name
|
ui :: State -> Widget Name
|
||||||
ui s =
|
ui st =
|
||||||
joinBorders $
|
joinBorders $
|
||||||
withBorderStyle unicode $
|
withBorderStyle unicode $
|
||||||
B.borderWithLabel (str $ "Zenith - " <> s ^. network) $
|
B.borderWithLabel
|
||||||
(C.center (listBox "Addresses" (s ^. addresses)) <+>
|
(str
|
||||||
B.vBorder <+> C.center (listBox "Transactions" (s ^. transactions))) <=>
|
("Zenith - " <>
|
||||||
msgBox (s ^. msg)
|
st ^. network <>
|
||||||
|
" - " <>
|
||||||
|
T.unpack
|
||||||
|
(maybe
|
||||||
|
"(None)"
|
||||||
|
(\(_, w) -> zcashWalletName $ entityVal w)
|
||||||
|
(L.listSelectedElement (st ^. wallets))))) $
|
||||||
|
(C.center (listBox "Addresses" (st ^. addresses)) <+>
|
||||||
|
B.vBorder <+> C.center (listBox "Transactions" (st ^. transactions))) <=>
|
||||||
|
msgBox (st ^. msg)
|
||||||
listBox :: String -> L.List Name String -> Widget Name
|
listBox :: String -> L.List Name String -> Widget Name
|
||||||
listBox titleLabel l =
|
listBox titleLabel l =
|
||||||
C.vCenter $
|
C.vCenter $
|
||||||
|
@ -111,8 +128,8 @@ drawUI s = [splashDialog s, helpDialog s, walletDialog s, ui s]
|
||||||
vBox
|
vBox
|
||||||
[B.hBorderWithLabel (str "Messages"), hLimit 70 $ padRight Max $ str m]
|
[B.hBorderWithLabel (str "Messages"), hLimit 70 $ padRight Max $ str m]
|
||||||
helpDialog :: State -> Widget Name
|
helpDialog :: State -> Widget Name
|
||||||
helpDialog s =
|
helpDialog st =
|
||||||
if s ^. helpBox
|
if st ^. helpBox
|
||||||
then D.renderDialog
|
then D.renderDialog
|
||||||
(D.dialog (Just (str "Commands")) Nothing 55)
|
(D.dialog (Just (str "Commands")) Nothing 55)
|
||||||
(vBox ([C.hCenter $ str "Key", B.hBorder] <> keyList) <+>
|
(vBox ([C.hCenter $ str "Key", B.hBorder] <> keyList) <+>
|
||||||
|
@ -124,16 +141,21 @@ drawUI s = [splashDialog s, helpDialog s, walletDialog s, ui s]
|
||||||
map
|
map
|
||||||
(hLimit 40 . str)
|
(hLimit 40 . str)
|
||||||
["Open help", "Close dialog", "Create Wallet", "Quit"]
|
["Open help", "Close dialog", "Create Wallet", "Quit"]
|
||||||
walletDialog :: State -> Widget Name
|
inputDialog :: State -> Widget Name
|
||||||
walletDialog s =
|
inputDialog st =
|
||||||
if s ^. walletBox
|
case st ^. dialogBox of
|
||||||
then D.renderDialog
|
WName ->
|
||||||
|
D.renderDialog
|
||||||
(D.dialog (Just (str "Create Wallet")) Nothing 50)
|
(D.dialog (Just (str "Create Wallet")) Nothing 50)
|
||||||
(renderForm $ s ^. walletForm)
|
(renderForm $ st ^. inputForm)
|
||||||
else emptyWidget
|
AName ->
|
||||||
|
D.renderDialog
|
||||||
|
(D.dialog (Just (str "Create Account")) Nothing 50)
|
||||||
|
(renderForm $ st ^. inputForm)
|
||||||
|
Blank -> emptyWidget
|
||||||
splashDialog :: State -> Widget Name
|
splashDialog :: State -> Widget Name
|
||||||
splashDialog s =
|
splashDialog st =
|
||||||
if s ^. splashBox
|
if st ^. splashBox
|
||||||
then withBorderStyle unicodeBold $
|
then withBorderStyle unicodeBold $
|
||||||
D.renderDialog
|
D.renderDialog
|
||||||
(D.dialog Nothing Nothing 30)
|
(D.dialog Nothing Nothing 30)
|
||||||
|
@ -141,13 +163,14 @@ drawUI s = [splashDialog s, helpDialog s, walletDialog s, ui s]
|
||||||
titleAttr
|
titleAttr
|
||||||
(str
|
(str
|
||||||
" _____ _ _ _ \n|__ /___ _ __ (_) |_| |__\n / // _ \\ '_ \\| | __| '_ \\\n / /| __/ | | | | |_| | | |\n/____\\___|_| |_|_|\\__|_| |_|") <=>
|
" _____ _ _ _ \n|__ /___ _ __ (_) |_| |__\n / // _ \\ '_ \\| | __| '_ \\\n / /| __/ | | | | |_| | | |\n/____\\___|_| |_|_|\\__|_| |_|") <=>
|
||||||
C.hCenter (withAttr titleAttr (str "Zcash Wallet v0.4.1")) <=>
|
C.hCenter (withAttr titleAttr (str "Zcash Wallet v0.4.3.0")) <=>
|
||||||
C.hCenter (withAttr blinkAttr $ str "Press any key..."))
|
C.hCenter (withAttr blinkAttr $ str "Press any key..."))
|
||||||
else emptyWidget
|
else emptyWidget
|
||||||
|
|
||||||
mkWalletForm :: WalletName -> Form WalletName e Name
|
mkInputForm :: DialogInput -> Form DialogInput e Name
|
||||||
mkWalletForm =
|
mkInputForm =
|
||||||
newForm [label "Name: " @@= editTextField walName WalNameField (Just 1)]
|
newForm
|
||||||
|
[label "Name: " @@= editTextField dialogInput DialogInputField (Just 1)]
|
||||||
where
|
where
|
||||||
label s w =
|
label s w =
|
||||||
padBottom (Pad 1) $ vLimit 1 (hLimit 15 $ str s <+> fill ' ') <+> w
|
padBottom (Pad 1) $ vLimit 1 (hLimit 15 $ str s <+> fill ' ') <+> w
|
||||||
|
@ -180,35 +203,57 @@ appEvent (BT.VtyEvent e) = do
|
||||||
case e of
|
case e of
|
||||||
V.EvKey V.KEsc [] -> do
|
V.EvKey V.KEsc [] -> do
|
||||||
BT.modify $ set helpBox False
|
BT.modify $ set helpBox False
|
||||||
ev -> return ()
|
_ev -> return ()
|
||||||
else do
|
else do
|
||||||
if s ^. walletBox
|
case s ^. dialogBox of
|
||||||
then do
|
WName -> do
|
||||||
case e of
|
case e of
|
||||||
V.EvKey V.KEsc [] -> BT.modify $ set walletBox False
|
V.EvKey V.KEsc [] -> BT.modify $ set dialogBox Blank
|
||||||
V.EvKey V.KEnter [] -> do
|
V.EvKey V.KEnter [] -> do
|
||||||
BT.modify $ set walletBox False
|
fs <- BT.zoom inputForm $ BT.gets formState
|
||||||
fs <- BT.zoom walletForm $ BT.gets formState
|
nw <- liftIO $ addNewWallet (fs ^. dialogInput) s
|
||||||
|
BT.modify $ set wallets nw
|
||||||
printMsg $
|
printMsg $
|
||||||
"Creating new wallet " <> (T.unpack $ fs ^. walName)
|
"Creating new wallet " <> T.unpack (fs ^. dialogInput)
|
||||||
ev -> BT.zoom walletForm $ handleFormEvent (BT.VtyEvent ev)
|
BT.modify $ set dialogBox Blank
|
||||||
else do
|
ev -> BT.zoom inputForm $ handleFormEvent (BT.VtyEvent ev)
|
||||||
|
AName -> do
|
||||||
|
case e of
|
||||||
|
V.EvKey V.KEsc [] -> BT.modify $ set dialogBox Blank
|
||||||
|
V.EvKey V.KEnter [] -> do
|
||||||
|
BT.modify $ set dialogBox Blank
|
||||||
|
fs <- BT.zoom inputForm $ BT.gets formState
|
||||||
|
printMsg $
|
||||||
|
"Creating new address " <> T.unpack (fs ^. dialogInput)
|
||||||
|
ev -> BT.zoom inputForm $ handleFormEvent (BT.VtyEvent ev)
|
||||||
|
Blank -> do
|
||||||
case e of
|
case e of
|
||||||
V.EvKey (V.KChar '\t') [] -> focusRing %= F.focusNext
|
V.EvKey (V.KChar '\t') [] -> focusRing %= F.focusNext
|
||||||
V.EvKey (V.KChar 'q') [] -> M.halt
|
V.EvKey (V.KChar 'q') [] -> M.halt
|
||||||
V.EvKey (V.KChar '?') [] -> BT.modify $ set helpBox True
|
V.EvKey (V.KChar '?') [] -> BT.modify $ set helpBox True
|
||||||
V.EvKey (V.KChar 'c') [] -> BT.modify $ set walletBox True
|
V.EvKey (V.KChar 'w') [] -> do
|
||||||
V.EvKey (V.KChar 's') [] -> printMsg "You pressed S!"
|
BT.modify $
|
||||||
|
set inputForm $
|
||||||
|
updateFormState (DialogInput "New Wallet") $
|
||||||
|
s ^. inputForm
|
||||||
|
BT.modify $ set dialogBox WName
|
||||||
|
V.EvKey (V.KChar 'a') [] -> do
|
||||||
|
BT.modify $
|
||||||
|
set inputForm $
|
||||||
|
updateFormState (DialogInput "New Account") $
|
||||||
|
s ^. inputForm
|
||||||
|
BT.modify $ set dialogBox AName
|
||||||
ev ->
|
ev ->
|
||||||
case r of
|
case r of
|
||||||
Just AList -> BT.zoom addresses $ L.handleListEvent ev
|
Just AList -> BT.zoom addresses $ L.handleListEvent ev
|
||||||
Just TList -> BT.zoom transactions $ L.handleListEvent ev
|
Just TList -> BT.zoom transactions $ L.handleListEvent ev
|
||||||
Nothing -> return ()
|
_anyName -> return ()
|
||||||
where
|
where
|
||||||
printMsg :: String -> BT.EventM Name State ()
|
printMsg :: String -> BT.EventM Name State ()
|
||||||
printMsg s = BT.modify $ updateMsg s
|
printMsg s = BT.modify $ updateMsg s
|
||||||
updateMsg :: String -> State -> State
|
updateMsg :: String -> State -> State
|
||||||
updateMsg = set msg
|
updateMsg = set msg
|
||||||
|
appEvent _ = return ()
|
||||||
|
|
||||||
theMap :: A.AttrMap
|
theMap :: A.AttrMap
|
||||||
theMap =
|
theMap =
|
||||||
|
@ -233,7 +278,7 @@ theApp =
|
||||||
}
|
}
|
||||||
|
|
||||||
runZenithCLI :: T.Text -> Int -> T.Text -> IO ()
|
runZenithCLI :: T.Text -> Int -> T.Text -> IO ()
|
||||||
runZenithCLI host port dbName = do
|
runZenithCLI host port dbFilePath = do
|
||||||
w <- checkZebra host port
|
w <- checkZebra host port
|
||||||
case (w :: Maybe ZebraGetInfo) of
|
case (w :: Maybe ZebraGetInfo) of
|
||||||
Just zebra -> do
|
Just zebra -> do
|
||||||
|
@ -241,7 +286,8 @@ runZenithCLI host port dbName = do
|
||||||
case (bc :: Maybe ZebraGetBlockChainInfo) of
|
case (bc :: Maybe ZebraGetBlockChainInfo) of
|
||||||
Nothing -> print "Unable to determine blockchain status"
|
Nothing -> print "Unable to determine blockchain status"
|
||||||
Just chainInfo -> do
|
Just chainInfo -> do
|
||||||
walList <- getWallets $ zgb_net chainInfo
|
initDb dbFilePath
|
||||||
|
walList <- getWallets dbFilePath $ zgb_net chainInfo
|
||||||
void $
|
void $
|
||||||
M.defaultMain theApp $
|
M.defaultMain theApp $
|
||||||
State
|
State
|
||||||
|
@ -252,11 +298,25 @@ runZenithCLI host port dbName = do
|
||||||
("Start up Ok! Connected to Zebra " ++
|
("Start up Ok! Connected to Zebra " ++
|
||||||
(T.unpack . zgi_build) zebra ++ " on port " ++ show port ++ ".")
|
(T.unpack . zgi_build) zebra ++ " on port " ++ show port ++ ".")
|
||||||
False
|
False
|
||||||
(null walList)
|
(if null walList
|
||||||
|
then WName
|
||||||
|
else Blank)
|
||||||
True
|
True
|
||||||
(mkWalletForm $ WalletName "Main")
|
(mkInputForm $ DialogInput "Main")
|
||||||
(F.focusRing [AList, TList])
|
(F.focusRing [AList, TList])
|
||||||
|
(zgb_blocks chainInfo)
|
||||||
|
dbFilePath
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
print $
|
print $
|
||||||
"No Zebra node available on port " <>
|
"No Zebra node available on port " <>
|
||||||
show port <> ". Check your configuration"
|
show port <> ". Check your configuration"
|
||||||
|
|
||||||
|
addNewWallet ::
|
||||||
|
T.Text -> State -> IO (L.GenericList Name Vec.Vector (Entity ZcashWallet))
|
||||||
|
addNewWallet n s = do
|
||||||
|
sP <- generateWalletSeedPhrase
|
||||||
|
let bH = s ^. startBlock
|
||||||
|
let netName = read $ s ^. network
|
||||||
|
_ <- saveWallet (s ^. dbPath) $ ZcashWallet sP bH n netName
|
||||||
|
wL <- getWallets (s ^. dbPath) netName
|
||||||
|
return $ L.listReplace (Vec.fromList wL) (Just 0) $ s ^. wallets
|
||||||
|
|
|
@ -13,14 +13,40 @@ import ZcashHaskell.Utils
|
||||||
import Zenith.DB
|
import Zenith.DB
|
||||||
|
|
||||||
-- * Database functions
|
-- * Database functions
|
||||||
-- | Returns the list of wallets available in the given database
|
-- | Initializes the database
|
||||||
checkWallets ::
|
initDb ::
|
||||||
T.Text -- ^ The database name to check
|
T.Text -- ^ The database path to check
|
||||||
-> ZcashNet -- ^ The network the wallet is running
|
-> IO ()
|
||||||
-> IO [Entity ZcashWallet]
|
initDb dbName = do
|
||||||
checkWallets dbName znet = do
|
|
||||||
runSqlite dbName $ do runMigration migrateAll
|
runSqlite dbName $ do runMigration migrateAll
|
||||||
runSqlite dbName $ selectList [ZcashWalletNetwork ==. znet] []
|
|
||||||
|
-- | Save a new wallet to the database
|
||||||
|
saveWallet ::
|
||||||
|
T.Text -- ^ The database path to use
|
||||||
|
-> ZcashWallet -- ^ The wallet to add to the database
|
||||||
|
-> IO ZcashWalletId
|
||||||
|
saveWallet dbFp w = runSqlite dbFp $ insert w
|
||||||
|
|
||||||
|
-- | Returns a list of accounts associated with the given wallet
|
||||||
|
getAccounts ::
|
||||||
|
T.Text -- ^ The database path
|
||||||
|
-> ZcashWalletId -- ^ The wallet ID to check
|
||||||
|
-> IO [Entity ZcashAccount]
|
||||||
|
getAccounts dbFp w = runSqlite dbFp $ selectList [ZcashAccountWalletId ==. w] []
|
||||||
|
|
||||||
|
-- | Save a new account to the database
|
||||||
|
saveAccount ::
|
||||||
|
T.Text -- ^ The database path
|
||||||
|
-> ZcashAccount -- ^ The account to add to the database
|
||||||
|
-> IO ZcashAccountId
|
||||||
|
saveAccount dbFp a = runSqlite dbFp $ insert a
|
||||||
|
|
||||||
|
-- | Returns a list of addresses associated with the given account
|
||||||
|
getAddresses ::
|
||||||
|
T.Text -- ^ The database path
|
||||||
|
-> ZcashAccountId -- ^ The account ID to check
|
||||||
|
-> IO [Entity WalletAddress]
|
||||||
|
getAddresses dbFp a = runSqlite dbFp $ selectList [WalletAddressAccId ==. a] []
|
||||||
|
|
||||||
-- * Zebra Node interaction
|
-- * Zebra Node interaction
|
||||||
-- | Checks the status of the `zebrad` node
|
-- | Checks the status of the `zebrad` node
|
||||||
|
@ -28,8 +54,8 @@ checkZebra ::
|
||||||
T.Text -- ^ Host where `zebrad` is available
|
T.Text -- ^ Host where `zebrad` is available
|
||||||
-> Int -- ^ Port where `zebrad` is available
|
-> Int -- ^ Port where `zebrad` is available
|
||||||
-> IO (Maybe ZebraGetInfo)
|
-> IO (Maybe ZebraGetInfo)
|
||||||
checkZebra host port = do
|
checkZebra nodeHost nodePort = do
|
||||||
res <- makeZebraCall host port "getinfo" []
|
res <- makeZebraCall nodeHost nodePort "getinfo" []
|
||||||
let body = responseBody (res :: Response (RpcResponse ZebraGetInfo))
|
let body = responseBody (res :: Response (RpcResponse ZebraGetInfo))
|
||||||
return $ result body
|
return $ result body
|
||||||
|
|
||||||
|
@ -38,14 +64,14 @@ checkBlockChain ::
|
||||||
T.Text -- ^ Host where `zebrad` is available
|
T.Text -- ^ Host where `zebrad` is available
|
||||||
-> Int -- ^ Port where `zebrad` is available
|
-> Int -- ^ Port where `zebrad` is available
|
||||||
-> IO (Maybe ZebraGetBlockChainInfo)
|
-> IO (Maybe ZebraGetBlockChainInfo)
|
||||||
checkBlockChain host port = do
|
checkBlockChain nodeHost nodePort = do
|
||||||
let f = makeZebraCall host port
|
let f = makeZebraCall nodeHost nodePort
|
||||||
result <$> (responseBody <$> f "getblockchaininfo" [])
|
result <$> (responseBody <$> f "getblockchaininfo" [])
|
||||||
|
|
||||||
-- | Generic RPC call function
|
-- | Generic RPC call function
|
||||||
connectZebra ::
|
connectZebra ::
|
||||||
FromJSON a => T.Text -> Int -> T.Text -> [Data.Aeson.Value] -> IO (Maybe a)
|
FromJSON a => T.Text -> Int -> T.Text -> [Data.Aeson.Value] -> IO (Maybe a)
|
||||||
connectZebra host port m params = do
|
connectZebra nodeHost nodePort m params = do
|
||||||
res <- makeZebraCall host port m params
|
res <- makeZebraCall nodeHost nodePort m params
|
||||||
let body = responseBody res
|
let body = responseBody res
|
||||||
return $ result body
|
return $ result body
|
||||||
|
|
|
@ -31,16 +31,29 @@ share
|
||||||
[persistLowerCase|
|
[persistLowerCase|
|
||||||
ZcashWallet
|
ZcashWallet
|
||||||
seedPhrase Phrase
|
seedPhrase Phrase
|
||||||
spendingKey BS.ByteString
|
|
||||||
tPrivateKey BS.ByteString
|
|
||||||
birthdayHeight Int
|
birthdayHeight Int
|
||||||
name T.Text
|
name T.Text
|
||||||
network ZcashNet
|
network ZcashNet
|
||||||
deriving Show
|
deriving Show
|
||||||
|
ZcashAccount
|
||||||
|
walletId ZcashWalletId
|
||||||
|
index Int
|
||||||
|
orchSpendKey BS.ByteString
|
||||||
|
sapSpendKey BS.ByteString
|
||||||
|
tPrivateKey BS.ByteString
|
||||||
|
deriving Show
|
||||||
|
WalletAddress
|
||||||
|
accId ZcashAccountId
|
||||||
|
index Int
|
||||||
|
orchRec BS.ByteString Maybe
|
||||||
|
sapRec BS.ByteString Maybe
|
||||||
|
tRec BS.ByteString Maybe
|
||||||
|
encoded T.Text
|
||||||
|
deriving Show
|
||||||
|]
|
|]
|
||||||
|
|
||||||
getWallets :: ZcashNet -> IO [Entity ZcashWallet]
|
getWallets :: T.Text -> ZcashNet -> IO [Entity ZcashWallet]
|
||||||
getWallets n =
|
getWallets dbFp n =
|
||||||
runSqlite "zenith.db" $ do
|
runSqlite dbFp $ do
|
||||||
s <- selectList [ZcashWalletNetwork ==. n] []
|
s <- selectList [ZcashWalletNetwork ==. n] []
|
||||||
liftIO $ return s
|
liftIO $ return s
|
||||||
|
|
31
test/Spec.hs
31
test/Spec.hs
|
@ -1,31 +1,30 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad (when)
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Database.Persist.Sqlite
|
import Database.Persist.Sqlite
|
||||||
|
import System.Directory
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import ZcashHaskell.Types (ZcashNet(..))
|
import ZcashHaskell.Types (ZcashNet(..))
|
||||||
|
import Zenith.Core (getAccounts)
|
||||||
import Zenith.DB
|
import Zenith.DB
|
||||||
import Zenith.DB
|
|
||||||
( EntityField(ZcashWalletId, ZcashWalletName)
|
|
||||||
, ZcashWallet(zcashWalletName)
|
|
||||||
)
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
checkDbFile <- doesFileExist "test.db"
|
||||||
|
when checkDbFile $ removeFile "test.db"
|
||||||
hspec $ do
|
hspec $ do
|
||||||
describe "Database tests" $ do
|
describe "Database tests" $ do
|
||||||
it "Create table" $ do
|
it "Create table" $ do
|
||||||
s <- runSqlite "test.db" $ do runMigration migrateAll
|
s <- runSqlite "test.db" $ do runMigration migrateAll
|
||||||
s `shouldBe` ()
|
s `shouldBe` ()
|
||||||
|
describe "Wallet Table" $ do
|
||||||
it "insert wallet record" $ do
|
it "insert wallet record" $ do
|
||||||
s <-
|
s <-
|
||||||
runSqlite "test.db" $ do
|
runSqlite "test.db" $ do
|
||||||
insert $
|
insert $
|
||||||
ZcashWallet
|
ZcashWallet
|
||||||
"one two three four five six seven eight nine ten eleven twelve"
|
"one two three four five six seven eight nine ten eleven twelve"
|
||||||
"123456789"
|
|
||||||
"987654321"
|
|
||||||
2000000
|
2000000
|
||||||
"Main Wallet"
|
"Main Wallet"
|
||||||
MainNet
|
MainNet
|
||||||
|
@ -49,3 +48,21 @@ main = do
|
||||||
delete recId
|
delete recId
|
||||||
get recId
|
get recId
|
||||||
"None" `shouldBe` maybe "None" zcashWalletName s
|
"None" `shouldBe` maybe "None" zcashWalletName s
|
||||||
|
describe "Account table" $ do
|
||||||
|
it "insert account" $ do
|
||||||
|
s <-
|
||||||
|
runSqlite "test.db" $ do
|
||||||
|
insert $
|
||||||
|
ZcashWallet
|
||||||
|
"one two three four five six seven eight nine ten eleven twelve"
|
||||||
|
2000000
|
||||||
|
"Main Wallet"
|
||||||
|
MainNet
|
||||||
|
t <-
|
||||||
|
runSqlite "test.db" $ do
|
||||||
|
insert $ ZcashAccount s 0 "132465798" "987654321" "739182462"
|
||||||
|
fromSqlKey t `shouldBe` 1
|
||||||
|
it "read accounts for wallet" $ do
|
||||||
|
wList <- getWallets "test.db" MainNet
|
||||||
|
acc <- getAccounts "test.db" $ entityKey (head wList)
|
||||||
|
length acc `shouldBe` 1
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 419f041ca9d1dd921673721c56a673fe1dc058e8
|
Subproject commit a52d2231f1a4f85a6504bfb9228a1475a0773088
|
|
@ -104,6 +104,7 @@ test-suite zenith-tests
|
||||||
, persistent
|
, persistent
|
||||||
, persistent-sqlite
|
, persistent-sqlite
|
||||||
, hspec
|
, hspec
|
||||||
|
, directory
|
||||||
, zcash-haskell
|
, zcash-haskell
|
||||||
, zenith
|
, zenith
|
||||||
pkgconfig-depends: rustzcash_wrapper
|
pkgconfig-depends: rustzcash_wrapper
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
nodeUser = "user"
|
nodeUser = "user"
|
||||||
nodePwd = "superSecret"
|
nodePwd = "superSecret"
|
||||||
dbName = "zenith.db"
|
dbFilePath = "zenith.db"
|
||||||
zebraHost = "127.0.0.1"
|
zebraHost = "127.0.0.1"
|
||||||
zebraPort = 18232
|
zebraPort = 18232
|
||||||
|
|
Loading…
Reference in a new issue