Compare commits
No commits in common. "8ec2fe31a440ba773decdc6b8caf2a487fd50f0e" and "a36de0a307395bfcf17663503fa21ba1d0024050" have entirely different histories.
8ec2fe31a4
...
a36de0a307
11 changed files with 100 additions and 1429 deletions
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -5,31 +5,6 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [0.4.6.0]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Display of account balance
|
|
||||||
- Functions to identify spends
|
|
||||||
- Functions to display transactions per address
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Update `zcash-haskell`
|
|
||||||
|
|
||||||
## [0.4.5.0]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Functions to scan relevant transparent notes
|
|
||||||
- Functions to scan relevant Sapling notes
|
|
||||||
- Functions to scan relevant Orchard notes
|
|
||||||
- Function to query `zebrad` for commitment trees
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Update `zcash-haskell`
|
|
||||||
|
|
||||||
## [0.4.4.3]
|
## [0.4.4.3]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -16,10 +16,8 @@ import System.Environment (getArgs)
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.IO
|
import System.IO
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
import ZcashHaskell.Types
|
|
||||||
import Zenith.CLI
|
import Zenith.CLI
|
||||||
import Zenith.Core (clearSync, testSync)
|
import Zenith.Types (ZcashAddress(..), ZcashPool(..), ZcashTx(..))
|
||||||
import Zenith.Types (Config(..), ZcashAddress(..), ZcashPool(..), ZcashTx(..))
|
|
||||||
import Zenith.Utils
|
import Zenith.Utils
|
||||||
import Zenith.Zcashd
|
import Zenith.Zcashd
|
||||||
|
|
||||||
|
@ -206,7 +204,6 @@ main = do
|
||||||
nodePwd <- require config "nodePwd"
|
nodePwd <- require config "nodePwd"
|
||||||
zebraPort <- require config "zebraPort"
|
zebraPort <- require config "zebraPort"
|
||||||
zebraHost <- require config "zebraHost"
|
zebraHost <- require config "zebraHost"
|
||||||
let myConfig = Config dbFilePath zebraHost zebraPort
|
|
||||||
if not (null args)
|
if not (null args)
|
||||||
then do
|
then do
|
||||||
case head args of
|
case head args of
|
||||||
|
@ -220,9 +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 myConfig
|
"cli" -> runZenithCLI zebraHost zebraPort dbFilePath
|
||||||
"sync" -> testSync myConfig
|
|
||||||
"rescan" -> clearSync myConfig
|
|
||||||
_ -> printUsage
|
_ -> printUsage
|
||||||
else printUsage
|
else printUsage
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ import Brick.Widgets.Core
|
||||||
, padBottom
|
, padBottom
|
||||||
, str
|
, str
|
||||||
, strWrap
|
, strWrap
|
||||||
, strWrapWith
|
|
||||||
, txt
|
, txt
|
||||||
, txtWrap
|
, txtWrap
|
||||||
, txtWrapWith
|
, txtWrapWith
|
||||||
|
@ -54,7 +53,6 @@ import Control.Monad.IO.Class (liftIO)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
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 qualified Data.Vector as Vec
|
import qualified Data.Vector as Vec
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import qualified Graphics.Vty as V
|
import qualified Graphics.Vty as V
|
||||||
|
@ -63,18 +61,13 @@ import Lens.Micro.Mtl
|
||||||
import Lens.Micro.TH
|
import Lens.Micro.TH
|
||||||
import Text.Wrap (FillScope(..), FillStrategy(..), WrapSettings(..), wrapText)
|
import Text.Wrap (FillScope(..), FillStrategy(..), WrapSettings(..), wrapText)
|
||||||
import ZcashHaskell.Keys (generateWalletSeedPhrase, getWalletSeed)
|
import ZcashHaskell.Keys (generateWalletSeedPhrase, getWalletSeed)
|
||||||
import ZcashHaskell.Orchard (getSaplingFromUA, isValidUnifiedAddress)
|
import ZcashHaskell.Orchard (isValidUnifiedAddress)
|
||||||
import ZcashHaskell.Transparent (encodeTransparentReceiver)
|
import ZcashHaskell.Transparent (encodeTransparent)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
import Zenith.Core
|
import Zenith.Core
|
||||||
import Zenith.DB
|
import Zenith.DB
|
||||||
import Zenith.Types
|
import Zenith.Types (PhraseDB(..), UnifiedAddressDB(..), ZcashNetDB(..))
|
||||||
( Config(..)
|
import Zenith.Utils (showAddress)
|
||||||
, PhraseDB(..)
|
|
||||||
, UnifiedAddressDB(..)
|
|
||||||
, ZcashNetDB(..)
|
|
||||||
)
|
|
||||||
import Zenith.Utils (displayTaz, displayZec, showAddress)
|
|
||||||
|
|
||||||
data Name
|
data Name
|
||||||
= WList
|
= WList
|
||||||
|
@ -103,7 +96,6 @@ data DisplayType
|
||||||
= AddrDisplay
|
= AddrDisplay
|
||||||
| MsgDisplay
|
| MsgDisplay
|
||||||
| PhraseDisplay
|
| PhraseDisplay
|
||||||
| TxDisplay
|
|
||||||
| BlankDisplay
|
| BlankDisplay
|
||||||
|
|
||||||
data State = State
|
data State = State
|
||||||
|
@ -111,7 +103,7 @@ data State = State
|
||||||
, _wallets :: !(L.List Name (Entity ZcashWallet))
|
, _wallets :: !(L.List Name (Entity ZcashWallet))
|
||||||
, _accounts :: !(L.List Name (Entity ZcashAccount))
|
, _accounts :: !(L.List Name (Entity ZcashAccount))
|
||||||
, _addresses :: !(L.List Name (Entity WalletAddress))
|
, _addresses :: !(L.List Name (Entity WalletAddress))
|
||||||
, _transactions :: !(L.List Name (Entity UserTx))
|
, _transactions :: !(L.List Name String)
|
||||||
, _msg :: !String
|
, _msg :: !String
|
||||||
, _helpBox :: !Bool
|
, _helpBox :: !Bool
|
||||||
, _dialogBox :: !DialogType
|
, _dialogBox :: !DialogType
|
||||||
|
@ -121,8 +113,6 @@ data State = State
|
||||||
, _startBlock :: !Int
|
, _startBlock :: !Int
|
||||||
, _dbPath :: !T.Text
|
, _dbPath :: !T.Text
|
||||||
, _displayBox :: !DisplayType
|
, _displayBox :: !DisplayType
|
||||||
, _syncBlock :: !Int
|
|
||||||
, _balance :: !Integer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
makeLenses ''State
|
makeLenses ''State
|
||||||
|
@ -152,16 +142,8 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
|
||||||
"(None)"
|
"(None)"
|
||||||
(\(_, a) -> zcashAccountName $ entityVal a)
|
(\(_, a) -> zcashAccountName $ entityVal a)
|
||||||
(L.listSelectedElement (st ^. accounts))))) <=>
|
(L.listSelectedElement (st ^. accounts))))) <=>
|
||||||
C.hCenter
|
|
||||||
(str
|
|
||||||
("Balance: " ++
|
|
||||||
if st ^. network == MainNet
|
|
||||||
then displayZec (st ^. balance)
|
|
||||||
else displayTaz (st ^. balance))) <=>
|
|
||||||
listAddressBox "Addresses" (st ^. addresses) <+>
|
listAddressBox "Addresses" (st ^. addresses) <+>
|
||||||
B.vBorder <+>
|
B.vBorder <+> C.center (listBox "Transactions" (st ^. transactions))) <=>
|
||||||
(C.hCenter (str ("Last block seen: " ++ show (st ^. syncBlock))) <=>
|
|
||||||
listTxBox "Transactions" (st ^. transactions))) <=>
|
|
||||||
C.hCenter
|
C.hCenter
|
||||||
(hBox
|
(hBox
|
||||||
[ capCommand "W" "allets"
|
[ capCommand "W" "allets"
|
||||||
|
@ -203,16 +185,6 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
|
||||||
, str " "
|
, str " "
|
||||||
, C.hCenter $ str "Use arrows to select"
|
, C.hCenter $ str "Use arrows to select"
|
||||||
]
|
]
|
||||||
listTxBox :: String -> L.List Name (Entity UserTx) -> Widget Name
|
|
||||||
listTxBox titleLabel tx =
|
|
||||||
C.vCenter $
|
|
||||||
vBox
|
|
||||||
[ C.hCenter
|
|
||||||
(B.borderWithLabel (str titleLabel) $
|
|
||||||
hLimit 40 $ vLimit 15 $ L.renderList listDrawTx True tx)
|
|
||||||
, str " "
|
|
||||||
, C.hCenter $ str "Use arrows to select"
|
|
||||||
]
|
|
||||||
helpDialog :: State -> Widget Name
|
helpDialog :: State -> Widget Name
|
||||||
helpDialog st =
|
helpDialog st =
|
||||||
if st ^. helpBox
|
if st ^. helpBox
|
||||||
|
@ -282,7 +254,7 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
|
||||||
titleAttr
|
titleAttr
|
||||||
(str
|
(str
|
||||||
" _____ _ _ _ \n|__ /___ _ __ (_) |_| |__\n / // _ \\ '_ \\| | __| '_ \\\n / /| __/ | | | | |_| | | |\n/____\\___|_| |_|_|\\__|_| |_|") <=>
|
" _____ _ _ _ \n|__ /___ _ __ (_) |_| |__\n / // _ \\ '_ \\| | __| '_ \\\n / /| __/ | | | | |_| | | |\n/____\\___|_| |_|_|\\__|_| |_|") <=>
|
||||||
C.hCenter (withAttr titleAttr (str "Zcash Wallet v0.4.6.0")) <=>
|
C.hCenter (withAttr titleAttr (str "Zcash Wallet v0.4.4.0")) <=>
|
||||||
C.hCenter (withAttr blinkAttr $ str "Press any key..."))
|
C.hCenter (withAttr blinkAttr $ str "Press any key..."))
|
||||||
else emptyWidget
|
else emptyWidget
|
||||||
capCommand :: String -> String -> Widget Name
|
capCommand :: String -> String -> Widget Name
|
||||||
|
@ -308,15 +280,13 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
|
||||||
getUA $ walletAddressUAddress $ entityVal a) <=>
|
getUA $ walletAddressUAddress $ entityVal a) <=>
|
||||||
B.borderWithLabel
|
B.borderWithLabel
|
||||||
(str "Legacy Shielded")
|
(str "Legacy Shielded")
|
||||||
(txtWrapWith (WrapSettings False True NoFill FillAfterFirst) $
|
(txtWrapWith
|
||||||
fromMaybe "None" $
|
(WrapSettings False True NoFill FillAfterFirst)
|
||||||
(getSaplingFromUA .
|
"Pending") <=>
|
||||||
E.encodeUtf8 . getUA . walletAddressUAddress)
|
|
||||||
(entityVal a)) <=>
|
|
||||||
B.borderWithLabel
|
B.borderWithLabel
|
||||||
(str "Transparent")
|
(str "Transparent")
|
||||||
(txtWrapWith (WrapSettings False True NoFill FillAfterFirst) $
|
(txtWrapWith (WrapSettings False True NoFill FillAfterFirst) $
|
||||||
maybe "None" (encodeTransparentReceiver (st ^. network)) $
|
maybe "Pending" (encodeTransparent (st ^. network)) $
|
||||||
t_rec =<<
|
t_rec =<<
|
||||||
(isValidUnifiedAddress .
|
(isValidUnifiedAddress .
|
||||||
E.encodeUtf8 . getUA . walletAddressUAddress)
|
E.encodeUtf8 . getUA . walletAddressUAddress)
|
||||||
|
@ -338,35 +308,6 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s]
|
||||||
D.renderDialog
|
D.renderDialog
|
||||||
(D.dialog (Just $ txt "Message") Nothing 50)
|
(D.dialog (Just $ txt "Message") Nothing 50)
|
||||||
(padAll 1 $ strWrap $ st ^. msg)
|
(padAll 1 $ strWrap $ st ^. msg)
|
||||||
TxDisplay ->
|
|
||||||
case L.listSelectedElement $ st ^. transactions of
|
|
||||||
Nothing -> emptyWidget
|
|
||||||
Just (_, tx) ->
|
|
||||||
withBorderStyle unicodeBold $
|
|
||||||
D.renderDialog
|
|
||||||
(D.dialog (Just $ txt "Transaction") Nothing 50)
|
|
||||||
(padAll
|
|
||||||
1
|
|
||||||
(str
|
|
||||||
("Date: " ++
|
|
||||||
show
|
|
||||||
(posixSecondsToUTCTime
|
|
||||||
(fromIntegral (userTxTime $ entityVal tx)))) <=>
|
|
||||||
(str "Tx ID: " <+>
|
|
||||||
strWrapWith
|
|
||||||
(WrapSettings False True NoFill FillAfterFirst)
|
|
||||||
(show (userTxHex $ entityVal tx))) <=>
|
|
||||||
str
|
|
||||||
("Amount: " ++
|
|
||||||
if st ^. network == MainNet
|
|
||||||
then displayZec
|
|
||||||
(fromIntegral $ userTxAmount $ entityVal tx)
|
|
||||||
else displayTaz
|
|
||||||
(fromIntegral $ userTxAmount $ entityVal tx)) <=>
|
|
||||||
(txt "Memo: " <+>
|
|
||||||
txtWrapWith
|
|
||||||
(WrapSettings False True NoFill FillAfterFirst)
|
|
||||||
(userTxMemo (entityVal tx)))))
|
|
||||||
BlankDisplay -> emptyWidget
|
BlankDisplay -> emptyWidget
|
||||||
|
|
||||||
mkInputForm :: DialogInput -> Form DialogInput e Name
|
mkInputForm :: DialogInput -> Form DialogInput e Name
|
||||||
|
@ -412,23 +353,6 @@ listDrawAddress sel w =
|
||||||
walletAddressName (entityVal w) <>
|
walletAddressName (entityVal w) <>
|
||||||
": " <> showAddress (walletAddressUAddress (entityVal w))
|
": " <> showAddress (walletAddressUAddress (entityVal w))
|
||||||
|
|
||||||
listDrawTx :: Bool -> Entity UserTx -> Widget Name
|
|
||||||
listDrawTx sel tx =
|
|
||||||
selStr $
|
|
||||||
T.pack
|
|
||||||
(show $ posixSecondsToUTCTime (fromIntegral (userTxTime $ entityVal tx))) <>
|
|
||||||
" " <> fmtAmt
|
|
||||||
where
|
|
||||||
amt = fromIntegral (userTxAmount $ entityVal tx) / 100000000
|
|
||||||
fmtAmt =
|
|
||||||
if amt > 0
|
|
||||||
then "↘" <> T.pack (show amt) <> " "
|
|
||||||
else " " <> T.pack (show amt) <> "↗"
|
|
||||||
selStr s =
|
|
||||||
if sel
|
|
||||||
then withAttr customAttr (txt $ "> " <> s)
|
|
||||||
else txt $ " " <> s
|
|
||||||
|
|
||||||
customAttr :: A.AttrName
|
customAttr :: A.AttrName
|
||||||
customAttr = L.listSelectedAttr <> A.attrName "custom"
|
customAttr = L.listSelectedAttr <> A.attrName "custom"
|
||||||
|
|
||||||
|
@ -455,7 +379,6 @@ appEvent (BT.VtyEvent e) = do
|
||||||
AddrDisplay -> BT.modify $ set displayBox BlankDisplay
|
AddrDisplay -> BT.modify $ set displayBox BlankDisplay
|
||||||
MsgDisplay -> BT.modify $ set displayBox BlankDisplay
|
MsgDisplay -> BT.modify $ set displayBox BlankDisplay
|
||||||
PhraseDisplay -> BT.modify $ set displayBox BlankDisplay
|
PhraseDisplay -> BT.modify $ set displayBox BlankDisplay
|
||||||
TxDisplay -> BT.modify $ set displayBox BlankDisplay
|
|
||||||
BlankDisplay -> do
|
BlankDisplay -> do
|
||||||
case s ^. dialogBox of
|
case s ^. dialogBox of
|
||||||
WName -> do
|
WName -> do
|
||||||
|
@ -542,9 +465,6 @@ appEvent (BT.VtyEvent e) = do
|
||||||
Blank -> do
|
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.KEnter [] -> do
|
|
||||||
ns <- liftIO $ refreshTxs s
|
|
||||||
BT.put ns
|
|
||||||
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 'n') [] ->
|
V.EvKey (V.KChar 'n') [] ->
|
||||||
|
@ -553,8 +473,6 @@ appEvent (BT.VtyEvent e) = do
|
||||||
BT.modify $ set displayBox AddrDisplay
|
BT.modify $ set displayBox AddrDisplay
|
||||||
V.EvKey (V.KChar 'w') [] ->
|
V.EvKey (V.KChar 'w') [] ->
|
||||||
BT.modify $ set dialogBox WSelect
|
BT.modify $ set dialogBox WSelect
|
||||||
V.EvKey (V.KChar 't') [] ->
|
|
||||||
BT.modify $ set displayBox TxDisplay
|
|
||||||
V.EvKey (V.KChar 'a') [] ->
|
V.EvKey (V.KChar 'a') [] ->
|
||||||
BT.modify $ set dialogBox ASelect
|
BT.modify $ set dialogBox ASelect
|
||||||
ev ->
|
ev ->
|
||||||
|
@ -593,11 +511,8 @@ theApp =
|
||||||
, M.appAttrMap = const theMap
|
, M.appAttrMap = const theMap
|
||||||
}
|
}
|
||||||
|
|
||||||
runZenithCLI :: Config -> IO ()
|
runZenithCLI :: T.Text -> Int -> T.Text -> IO ()
|
||||||
runZenithCLI config = do
|
runZenithCLI host port dbFilePath = do
|
||||||
let host = c_zebraHost config
|
|
||||||
let port = c_zebraPort config
|
|
||||||
let dbFilePath = c_dbPath config
|
|
||||||
w <- try $ checkZebra host port :: IO (Either IOError ZebraGetInfo)
|
w <- try $ checkZebra host port :: IO (Either IOError ZebraGetInfo)
|
||||||
case w of
|
case w of
|
||||||
Right zebra -> do
|
Right zebra -> do
|
||||||
|
@ -617,18 +532,6 @@ runZenithCLI config = do
|
||||||
if not (null accList)
|
if not (null accList)
|
||||||
then getAddresses dbFilePath $ entityKey $ head accList
|
then getAddresses dbFilePath $ entityKey $ head accList
|
||||||
else return []
|
else return []
|
||||||
txList <-
|
|
||||||
if not (null addrList)
|
|
||||||
then getUserTx dbFilePath $ entityKey $ head addrList
|
|
||||||
else return []
|
|
||||||
let block =
|
|
||||||
if not (null walList)
|
|
||||||
then zcashWalletLastSync $ entityVal $ head walList
|
|
||||||
else 0
|
|
||||||
bal <-
|
|
||||||
if not (null accList)
|
|
||||||
then getBalance dbFilePath $ entityKey $ head accList
|
|
||||||
else return 0
|
|
||||||
void $
|
void $
|
||||||
M.defaultMain theApp $
|
M.defaultMain theApp $
|
||||||
State
|
State
|
||||||
|
@ -636,7 +539,7 @@ runZenithCLI config = do
|
||||||
(L.list WList (Vec.fromList walList) 1)
|
(L.list WList (Vec.fromList walList) 1)
|
||||||
(L.list AcList (Vec.fromList accList) 0)
|
(L.list AcList (Vec.fromList accList) 0)
|
||||||
(L.list AList (Vec.fromList addrList) 1)
|
(L.list AList (Vec.fromList addrList) 1)
|
||||||
(L.list TList (Vec.fromList txList) 1)
|
(L.list TList (Vec.fromList ["tx1", "tx2", "tx3"]) 1)
|
||||||
("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
|
||||||
|
@ -649,8 +552,6 @@ runZenithCLI config = do
|
||||||
(zgb_blocks chainInfo)
|
(zgb_blocks chainInfo)
|
||||||
dbFilePath
|
dbFilePath
|
||||||
MsgDisplay
|
MsgDisplay
|
||||||
block
|
|
||||||
bal
|
|
||||||
Left e -> do
|
Left e -> do
|
||||||
print $
|
print $
|
||||||
"No Zebra node available on port " <>
|
"No Zebra node available on port " <>
|
||||||
|
@ -668,29 +569,14 @@ refreshWallet s = do
|
||||||
Just (_j, w1) -> return w1
|
Just (_j, w1) -> return w1
|
||||||
Just (_k, w) -> return w
|
Just (_k, w) -> return w
|
||||||
aL <- getAccounts (s ^. dbPath) $ entityKey selWallet
|
aL <- getAccounts (s ^. dbPath) $ entityKey selWallet
|
||||||
let bl = zcashWalletLastSync $ entityVal selWallet
|
|
||||||
addrL <-
|
addrL <-
|
||||||
if not (null aL)
|
if not (null aL)
|
||||||
then getAddresses (s ^. dbPath) $ entityKey $ head aL
|
then getAddresses (s ^. dbPath) $ entityKey $ head aL
|
||||||
else return []
|
else return []
|
||||||
bal <-
|
|
||||||
if not (null aL)
|
|
||||||
then getBalance (s ^. dbPath) $ entityKey $ head aL
|
|
||||||
else return 0
|
|
||||||
txL <-
|
|
||||||
if not (null addrL)
|
|
||||||
then getUserTx (s ^. dbPath) $ entityKey $ head addrL
|
|
||||||
else return []
|
|
||||||
let aL' = L.listReplace (Vec.fromList aL) (Just 0) (s ^. accounts)
|
let aL' = L.listReplace (Vec.fromList aL) (Just 0) (s ^. accounts)
|
||||||
let addrL' = L.listReplace (Vec.fromList addrL) (Just 0) (s ^. addresses)
|
let addrL' = L.listReplace (Vec.fromList addrL) (Just 0) (s ^. addresses)
|
||||||
let txL' = L.listReplace (Vec.fromList txL) (Just 0) (s ^. transactions)
|
|
||||||
return $
|
return $
|
||||||
(s & accounts .~ aL') & syncBlock .~ bl & balance .~ bal & addresses .~
|
(s & accounts .~ aL') & addresses .~ addrL' & msg .~ "Switched to wallet: " ++
|
||||||
addrL' &
|
|
||||||
transactions .~
|
|
||||||
txL' &
|
|
||||||
msg .~
|
|
||||||
"Switched to wallet: " ++
|
|
||||||
T.unpack (zcashWalletName $ entityVal selWallet)
|
T.unpack (zcashWalletName $ entityVal selWallet)
|
||||||
|
|
||||||
addNewWallet :: T.Text -> State -> IO State
|
addNewWallet :: T.Text -> State -> IO State
|
||||||
|
@ -700,7 +586,7 @@ addNewWallet n s = do
|
||||||
let netName = s ^. network
|
let netName = s ^. network
|
||||||
r <-
|
r <-
|
||||||
saveWallet (s ^. dbPath) $
|
saveWallet (s ^. dbPath) $
|
||||||
ZcashWallet n (ZcashNetDB netName) (PhraseDB sP) bH 0
|
ZcashWallet n (ZcashNetDB netName) (PhraseDB sP) bH
|
||||||
case r of
|
case r of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
return $ s & msg .~ ("Wallet already exists: " ++ T.unpack n)
|
return $ s & msg .~ ("Wallet already exists: " ++ T.unpack n)
|
||||||
|
@ -753,42 +639,10 @@ refreshAccount s = do
|
||||||
Just (_j, w1) -> return w1
|
Just (_j, w1) -> return w1
|
||||||
Just (_k, w) -> return w
|
Just (_k, w) -> return w
|
||||||
aL <- getAddresses (s ^. dbPath) $ entityKey selAccount
|
aL <- getAddresses (s ^. dbPath) $ entityKey selAccount
|
||||||
bal <- getBalance (s ^. dbPath) $ entityKey selAccount
|
|
||||||
let aL' = L.listReplace (Vec.fromList aL) (Just 0) (s ^. addresses)
|
let aL' = L.listReplace (Vec.fromList aL) (Just 0) (s ^. addresses)
|
||||||
selAddress <-
|
return $
|
||||||
do case L.listSelectedElement aL' of
|
s & addresses .~ aL' & msg .~ "Switched to account: " ++
|
||||||
Nothing -> do
|
T.unpack (zcashAccountName $ entityVal selAccount)
|
||||||
let fAdd = L.listSelectedElement $ L.listMoveToBeginning aL'
|
|
||||||
return fAdd
|
|
||||||
Just a2 -> return $ Just a2
|
|
||||||
case selAddress of
|
|
||||||
Nothing ->
|
|
||||||
return $
|
|
||||||
s & balance .~ bal & addresses .~ aL' & msg .~ "Switched to account: " ++
|
|
||||||
T.unpack (zcashAccountName $ entityVal selAccount)
|
|
||||||
Just (_i, a) -> do
|
|
||||||
tList <- getUserTx (s ^. dbPath) $ entityKey a
|
|
||||||
let tL' = L.listReplace (Vec.fromList tList) (Just 0) (s ^. transactions)
|
|
||||||
return $
|
|
||||||
s & balance .~ bal & addresses .~ aL' & transactions .~ tL' & msg .~
|
|
||||||
"Switched to account: " ++
|
|
||||||
T.unpack (zcashAccountName $ entityVal selAccount)
|
|
||||||
|
|
||||||
refreshTxs :: State -> IO State
|
|
||||||
refreshTxs s = do
|
|
||||||
selAddress <-
|
|
||||||
do case L.listSelectedElement $ s ^. addresses of
|
|
||||||
Nothing -> do
|
|
||||||
let fAdd =
|
|
||||||
L.listSelectedElement $ L.listMoveToBeginning $ s ^. addresses
|
|
||||||
return fAdd
|
|
||||||
Just a2 -> return $ Just a2
|
|
||||||
case selAddress of
|
|
||||||
Nothing -> return s
|
|
||||||
Just (_i, a) -> do
|
|
||||||
tList <- getUserTx (s ^. dbPath) $ entityKey a
|
|
||||||
let tL' = L.listReplace (Vec.fromList tList) (Just 0) (s ^. transactions)
|
|
||||||
return $ s & transactions .~ tL'
|
|
||||||
|
|
||||||
addNewAddress :: T.Text -> Scope -> State -> IO State
|
addNewAddress :: T.Text -> Scope -> State -> IO State
|
||||||
addNewAddress n scope s = do
|
addNewAddress n scope s = do
|
||||||
|
|
|
@ -3,49 +3,35 @@
|
||||||
-- | Core wallet functionality for Zenith
|
-- | Core wallet functionality for Zenith
|
||||||
module Zenith.Core where
|
module Zenith.Core where
|
||||||
|
|
||||||
import Control.Exception (throwIO, try)
|
import Control.Exception (throwIO)
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.HexString (hexString)
|
import Data.HexString (hexString)
|
||||||
import Data.Maybe (fromJust)
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Database.Persist.Sqlite
|
|
||||||
import Network.HTTP.Client
|
import Network.HTTP.Client
|
||||||
import ZcashHaskell.Keys
|
import ZcashHaskell.Keys
|
||||||
import ZcashHaskell.Orchard
|
import ZcashHaskell.Orchard
|
||||||
( decryptOrchardActionSK
|
( encodeUnifiedAddress
|
||||||
, encodeUnifiedAddress
|
|
||||||
, genOrchardReceiver
|
, genOrchardReceiver
|
||||||
, genOrchardSpendingKey
|
, genOrchardSpendingKey
|
||||||
, getOrchardNotePosition
|
|
||||||
, getOrchardWitness
|
|
||||||
, updateOrchardCommitmentTree
|
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Sapling
|
import ZcashHaskell.Sapling
|
||||||
( decodeSaplingOutputEsk
|
( genSaplingInternalAddress
|
||||||
, genSaplingInternalAddress
|
|
||||||
, genSaplingPaymentAddress
|
, genSaplingPaymentAddress
|
||||||
, genSaplingSpendingKey
|
, genSaplingSpendingKey
|
||||||
, getSaplingNotePosition
|
|
||||||
, getSaplingWitness
|
|
||||||
, updateSaplingCommitmentTree
|
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Transparent (genTransparentPrvKey, genTransparentReceiver)
|
import ZcashHaskell.Transparent (genTransparentPrvKey, genTransparentReceiver)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
import ZcashHaskell.Utils
|
import ZcashHaskell.Utils
|
||||||
import Zenith.DB
|
import Zenith.DB
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
( Config(..)
|
( OrchardSpendingKeyDB(..)
|
||||||
, HexStringDB(..)
|
|
||||||
, OrchardSpendingKeyDB(..)
|
|
||||||
, PhraseDB(..)
|
, PhraseDB(..)
|
||||||
, SaplingSpendingKeyDB(..)
|
, SaplingSpendingKeyDB(..)
|
||||||
, ScopeDB(..)
|
, ScopeDB(..)
|
||||||
, TransparentSpendingKeyDB(..)
|
, TransparentSpendingKeyDB(..)
|
||||||
, UnifiedAddressDB(..)
|
, UnifiedAddressDB(..)
|
||||||
, ZcashNetDB(..)
|
, ZcashNetDB(..)
|
||||||
, ZebraTreeInfo(..)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
-- * Zebra Node interaction
|
-- * Zebra Node interaction
|
||||||
|
@ -71,23 +57,6 @@ checkBlockChain nodeHost nodePort = do
|
||||||
Left e -> throwIO $ userError e
|
Left e -> throwIO $ userError e
|
||||||
Right bci -> return bci
|
Right bci -> return bci
|
||||||
|
|
||||||
-- | Get commitment trees from Zebra
|
|
||||||
getCommitmentTrees ::
|
|
||||||
T.Text -- ^ Host where `zebrad` is avaiable
|
|
||||||
-> Int -- ^ Port where `zebrad` is available
|
|
||||||
-> Int -- ^ Block height
|
|
||||||
-> IO ZebraTreeInfo
|
|
||||||
getCommitmentTrees nodeHost nodePort block = do
|
|
||||||
r <-
|
|
||||||
makeZebraCall
|
|
||||||
nodeHost
|
|
||||||
nodePort
|
|
||||||
"z_gettreestate"
|
|
||||||
[Data.Aeson.String $ T.pack $ show block]
|
|
||||||
case r of
|
|
||||||
Left e -> throwIO $ userError e
|
|
||||||
Right zti -> return zti
|
|
||||||
|
|
||||||
-- * Spending Keys
|
-- * Spending Keys
|
||||||
-- | Create an Orchard Spending Key for the given wallet and account index
|
-- | Create an Orchard Spending Key for the given wallet and account index
|
||||||
createOrchardSpendingKey :: ZcashWallet -> Int -> IO OrchardSpendingKey
|
createOrchardSpendingKey :: ZcashWallet -> Int -> IO OrchardSpendingKey
|
||||||
|
@ -190,233 +159,9 @@ createWalletAddress n i zNet scope za = do
|
||||||
(ScopeDB scope)
|
(ScopeDB scope)
|
||||||
|
|
||||||
-- * Wallet
|
-- * Wallet
|
||||||
-- | Find the Sapling notes that match the given spending key
|
|
||||||
findSaplingOutputs ::
|
|
||||||
Config -- ^ the configuration parameters
|
|
||||||
-> Int -- ^ the starting block
|
|
||||||
-> ZcashNetDB -- ^ The network
|
|
||||||
-> Entity ZcashAccount -- ^ The account to use
|
|
||||||
-> IO ()
|
|
||||||
findSaplingOutputs config b znet za = do
|
|
||||||
let dbPath = c_dbPath config
|
|
||||||
let zebraHost = c_zebraHost config
|
|
||||||
let zebraPort = c_zebraPort config
|
|
||||||
let zn = getNet znet
|
|
||||||
tList <- getShieldedOutputs dbPath b
|
|
||||||
trees <- getCommitmentTrees zebraHost zebraPort (b - 1)
|
|
||||||
let sT = SaplingCommitmentTree $ ztiSapling trees
|
|
||||||
decryptNotes sT zn tList
|
|
||||||
sapNotes <- getWalletSapNotes dbPath (entityKey za)
|
|
||||||
findSapSpends dbPath (entityKey za) sapNotes
|
|
||||||
where
|
|
||||||
sk :: SaplingSpendingKeyDB
|
|
||||||
sk = zcashAccountSapSpendKey $ entityVal za
|
|
||||||
decryptNotes ::
|
|
||||||
SaplingCommitmentTree
|
|
||||||
-> ZcashNet
|
|
||||||
-> [(Entity ZcashTransaction, Entity ShieldOutput)]
|
|
||||||
-> IO ()
|
|
||||||
decryptNotes _ _ [] = return ()
|
|
||||||
decryptNotes st n ((zt, o):txs) = do
|
|
||||||
let updatedTree =
|
|
||||||
updateSaplingCommitmentTree
|
|
||||||
st
|
|
||||||
(getHex $ shieldOutputCmu $ entityVal o)
|
|
||||||
case updatedTree of
|
|
||||||
Nothing -> throwIO $ userError "Failed to update commitment tree"
|
|
||||||
Just uT -> do
|
|
||||||
let noteWitness = getSaplingWitness uT
|
|
||||||
let notePos = getSaplingNotePosition <$> noteWitness
|
|
||||||
case notePos of
|
|
||||||
Nothing -> throwIO $ userError "Failed to obtain note position"
|
|
||||||
Just nP -> do
|
|
||||||
case decodeShOut External n nP o of
|
|
||||||
Nothing -> do
|
|
||||||
case decodeShOut Internal n nP o of
|
|
||||||
Nothing -> do
|
|
||||||
decryptNotes uT n txs
|
|
||||||
Just dn1 -> do
|
|
||||||
print dn1
|
|
||||||
wId <-
|
|
||||||
saveWalletTransaction
|
|
||||||
(c_dbPath config)
|
|
||||||
(entityKey za)
|
|
||||||
zt
|
|
||||||
saveWalletSapNote
|
|
||||||
(c_dbPath config)
|
|
||||||
wId
|
|
||||||
nP
|
|
||||||
(fromJust noteWitness)
|
|
||||||
True
|
|
||||||
(entityKey za)
|
|
||||||
dn1
|
|
||||||
decryptNotes uT n txs
|
|
||||||
Just dn0 -> do
|
|
||||||
print dn0
|
|
||||||
wId <-
|
|
||||||
saveWalletTransaction (c_dbPath config) (entityKey za) zt
|
|
||||||
saveWalletSapNote
|
|
||||||
(c_dbPath config)
|
|
||||||
wId
|
|
||||||
nP
|
|
||||||
(fromJust noteWitness)
|
|
||||||
False
|
|
||||||
(entityKey za)
|
|
||||||
dn0
|
|
||||||
decryptNotes uT n txs
|
|
||||||
decodeShOut ::
|
|
||||||
Scope
|
|
||||||
-> ZcashNet
|
|
||||||
-> Integer
|
|
||||||
-> Entity ShieldOutput
|
|
||||||
-> Maybe DecodedNote
|
|
||||||
decodeShOut scope n pos s = do
|
|
||||||
decodeSaplingOutputEsk
|
|
||||||
(getSapSK sk)
|
|
||||||
(ShieldedOutput
|
|
||||||
(getHex $ shieldOutputCv $ entityVal s)
|
|
||||||
(getHex $ shieldOutputCmu $ entityVal s)
|
|
||||||
(getHex $ shieldOutputEphKey $ entityVal s)
|
|
||||||
(getHex $ shieldOutputEncCipher $ entityVal s)
|
|
||||||
(getHex $ shieldOutputOutCipher $ entityVal s)
|
|
||||||
(getHex $ shieldOutputProof $ entityVal s))
|
|
||||||
n
|
|
||||||
scope
|
|
||||||
pos
|
|
||||||
|
|
||||||
-- | Get Orchard actions
|
|
||||||
findOrchardActions ::
|
|
||||||
Config -- ^ the configuration parameters
|
|
||||||
-> Int -- ^ the starting block
|
|
||||||
-> ZcashNetDB -- ^ The network
|
|
||||||
-> Entity ZcashAccount -- ^ The account to use
|
|
||||||
-> IO ()
|
|
||||||
findOrchardActions config b znet za = do
|
|
||||||
let dbPath = c_dbPath config
|
|
||||||
let zebraHost = c_zebraHost config
|
|
||||||
let zebraPort = c_zebraPort config
|
|
||||||
let zn = getNet znet
|
|
||||||
tList <- getOrchardActions dbPath b
|
|
||||||
trees <- getCommitmentTrees zebraHost zebraPort (b - 1)
|
|
||||||
let sT = OrchardCommitmentTree $ ztiOrchard trees
|
|
||||||
decryptNotes sT zn tList
|
|
||||||
orchNotes <- getWalletOrchNotes dbPath (entityKey za)
|
|
||||||
findOrchSpends dbPath (entityKey za) orchNotes
|
|
||||||
where
|
|
||||||
decryptNotes ::
|
|
||||||
OrchardCommitmentTree
|
|
||||||
-> ZcashNet
|
|
||||||
-> [(Entity ZcashTransaction, Entity OrchAction)]
|
|
||||||
-> IO ()
|
|
||||||
decryptNotes _ _ [] = return ()
|
|
||||||
decryptNotes ot n ((zt, o):txs) = do
|
|
||||||
let updatedTree =
|
|
||||||
updateOrchardCommitmentTree
|
|
||||||
ot
|
|
||||||
(getHex $ orchActionCmx $ entityVal o)
|
|
||||||
case updatedTree of
|
|
||||||
Nothing -> throwIO $ userError "Failed to update commitment tree"
|
|
||||||
Just uT -> do
|
|
||||||
let noteWitness = getOrchardWitness uT
|
|
||||||
let notePos = getOrchardNotePosition <$> noteWitness
|
|
||||||
case notePos of
|
|
||||||
Nothing -> throwIO $ userError "Failed to obtain note position"
|
|
||||||
Just nP ->
|
|
||||||
case decodeOrchAction External nP o of
|
|
||||||
Nothing ->
|
|
||||||
case decodeOrchAction Internal nP o of
|
|
||||||
Nothing -> decryptNotes uT n txs
|
|
||||||
Just dn1 -> do
|
|
||||||
print dn1
|
|
||||||
wId <-
|
|
||||||
saveWalletTransaction
|
|
||||||
(c_dbPath config)
|
|
||||||
(entityKey za)
|
|
||||||
zt
|
|
||||||
saveWalletOrchNote
|
|
||||||
(c_dbPath config)
|
|
||||||
wId
|
|
||||||
nP
|
|
||||||
(fromJust noteWitness)
|
|
||||||
True
|
|
||||||
(entityKey za)
|
|
||||||
dn1
|
|
||||||
decryptNotes uT n txs
|
|
||||||
Just dn -> do
|
|
||||||
print dn
|
|
||||||
wId <-
|
|
||||||
saveWalletTransaction (c_dbPath config) (entityKey za) zt
|
|
||||||
saveWalletOrchNote
|
|
||||||
(c_dbPath config)
|
|
||||||
wId
|
|
||||||
nP
|
|
||||||
(fromJust noteWitness)
|
|
||||||
False
|
|
||||||
(entityKey za)
|
|
||||||
dn
|
|
||||||
decryptNotes uT n txs
|
|
||||||
sk :: OrchardSpendingKeyDB
|
|
||||||
sk = zcashAccountOrchSpendKey $ entityVal za
|
|
||||||
decodeOrchAction ::
|
|
||||||
Scope -> Integer -> Entity OrchAction -> Maybe DecodedNote
|
|
||||||
decodeOrchAction scope pos o =
|
|
||||||
decryptOrchardActionSK (getOrchSK sk) scope $
|
|
||||||
OrchardAction
|
|
||||||
(getHex $ orchActionNf $ entityVal o)
|
|
||||||
(getHex $ orchActionRk $ entityVal o)
|
|
||||||
(getHex $ orchActionCmx $ entityVal o)
|
|
||||||
(getHex $ orchActionEphKey $ entityVal o)
|
|
||||||
(getHex $ orchActionEncCipher $ entityVal o)
|
|
||||||
(getHex $ orchActionOutCipher $ entityVal o)
|
|
||||||
(getHex $ orchActionCv $ entityVal o)
|
|
||||||
(getHex $ orchActionAuth $ entityVal o)
|
|
||||||
|
|
||||||
-- | Sync the wallet with the data store
|
-- | Sync the wallet with the data store
|
||||||
syncWallet ::
|
syncWallet ::
|
||||||
Config -- ^ configuration parameters
|
T.Text -- ^ The database path
|
||||||
-> Entity ZcashWallet
|
-> Entity ZcashWallet
|
||||||
-> IO String
|
-> IO ()
|
||||||
syncWallet config w = do
|
syncWallet walletDb w = undefined
|
||||||
let walletDb = c_dbPath config
|
|
||||||
accs <- getAccounts walletDb $ entityKey w
|
|
||||||
addrs <- concat <$> mapM (getAddresses walletDb . entityKey) accs
|
|
||||||
intAddrs <- concat <$> mapM (getInternalAddresses walletDb . entityKey) accs
|
|
||||||
chainTip <- getMaxBlock walletDb
|
|
||||||
let lastBlock = zcashWalletLastSync $ entityVal w
|
|
||||||
let startBlock =
|
|
||||||
if lastBlock > 0
|
|
||||||
then lastBlock
|
|
||||||
else zcashWalletBirthdayHeight $ entityVal w
|
|
||||||
mapM_ (findTransparentNotes walletDb startBlock) addrs
|
|
||||||
mapM_ (findTransparentNotes walletDb startBlock) intAddrs
|
|
||||||
mapM_ (findTransparentSpends walletDb . entityKey) accs
|
|
||||||
sapNotes <-
|
|
||||||
mapM
|
|
||||||
(findSaplingOutputs config startBlock (zcashWalletNetwork $ entityVal w))
|
|
||||||
accs
|
|
||||||
orchNotes <-
|
|
||||||
mapM
|
|
||||||
(findOrchardActions config startBlock (zcashWalletNetwork $ entityVal w))
|
|
||||||
accs
|
|
||||||
updateWalletSync walletDb chainTip (entityKey w)
|
|
||||||
mapM_ (getWalletTransactions walletDb) addrs
|
|
||||||
return "Testing"
|
|
||||||
|
|
||||||
testSync :: Config -> IO ()
|
|
||||||
testSync config = do
|
|
||||||
let dbPath = c_dbPath config
|
|
||||||
_ <- initDb dbPath
|
|
||||||
w <- getWallets dbPath TestNet
|
|
||||||
r <- mapM (syncWallet config) w
|
|
||||||
print r
|
|
||||||
|
|
||||||
clearSync :: Config -> IO ()
|
|
||||||
clearSync config = do
|
|
||||||
let dbPath = c_dbPath config
|
|
||||||
_ <- initDb dbPath
|
|
||||||
_ <- clearWalletTransactions dbPath
|
|
||||||
w <- getWallets dbPath TestNet
|
|
||||||
mapM_ (updateWalletSync dbPath 0 . entityKey) w
|
|
||||||
w' <- getWallets dbPath TestNet
|
|
||||||
r <- mapM (syncWallet config) w'
|
|
||||||
print r
|
|
||||||
|
|
923
src/Zenith/DB.hs
923
src/Zenith/DB.hs
File diff suppressed because it is too large
Load diff
|
@ -44,10 +44,7 @@ scanZebra b host port dbFilePath = do
|
||||||
if sb > zgb_blocks bStatus || sb < 1
|
if sb > zgb_blocks bStatus || sb < 1
|
||||||
then throwIO $ userError "Invalid starting block for scan"
|
then throwIO $ userError "Invalid starting block for scan"
|
||||||
else do
|
else do
|
||||||
print $
|
let bList = [sb .. (zgb_blocks bStatus)]
|
||||||
"Scanning from " ++
|
|
||||||
show (sb + 1) ++ " to " ++ show (zgb_blocks bStatus)
|
|
||||||
let bList = [(sb + 1) .. (zgb_blocks bStatus)]
|
|
||||||
displayConsoleRegions $ do
|
displayConsoleRegions $ do
|
||||||
pg <- newProgressBar def {pgTotal = fromIntegral $ length bList}
|
pg <- newProgressBar def {pgTotal = fromIntegral $ length bList}
|
||||||
txList <-
|
txList <-
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
module Zenith.Types where
|
module Zenith.Types where
|
||||||
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
|
import Data.Aeson.Types (prependFailure, typeMismatch)
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.Base64 as B64
|
import qualified Data.ByteString.Base64 as B64
|
||||||
import qualified Data.ByteString.Char8 as C
|
import qualified Data.ByteString.Char8 as C
|
||||||
|
@ -29,7 +30,6 @@ import ZcashHaskell.Types
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
)
|
)
|
||||||
|
|
||||||
-- * UI
|
|
||||||
-- * Database field type wrappers
|
-- * Database field type wrappers
|
||||||
newtype HexStringDB = HexStringDB
|
newtype HexStringDB = HexStringDB
|
||||||
{ getHex :: HexString
|
{ getHex :: HexString
|
||||||
|
@ -80,36 +80,6 @@ newtype TransparentSpendingKeyDB = TransparentSpendingKeyDB
|
||||||
derivePersistField "TransparentSpendingKeyDB"
|
derivePersistField "TransparentSpendingKeyDB"
|
||||||
|
|
||||||
-- * RPC
|
-- * RPC
|
||||||
-- | Type for Configuration parameters
|
|
||||||
data Config = Config
|
|
||||||
{ c_dbPath :: !T.Text
|
|
||||||
, c_zebraHost :: !T.Text
|
|
||||||
, c_zebraPort :: !Int
|
|
||||||
} deriving (Eq, Prelude.Show)
|
|
||||||
|
|
||||||
-- ** `zebrad`
|
|
||||||
-- | Type for modeling the tree state response
|
|
||||||
data ZebraTreeInfo = ZebraTreeInfo
|
|
||||||
{ ztiHeight :: !Int
|
|
||||||
, ztiTime :: !Int
|
|
||||||
, ztiSapling :: !HexString
|
|
||||||
, ztiOrchard :: !HexString
|
|
||||||
} deriving (Eq, Show, Read)
|
|
||||||
|
|
||||||
instance FromJSON ZebraTreeInfo where
|
|
||||||
parseJSON =
|
|
||||||
withObject "ZebraTreeInfo" $ \obj -> do
|
|
||||||
h <- obj .: "height"
|
|
||||||
t <- obj .: "time"
|
|
||||||
s <- obj .: "sapling"
|
|
||||||
o <- obj .: "orchard"
|
|
||||||
sc <- s .: "commitments"
|
|
||||||
oc <- o .: "commitments"
|
|
||||||
sf <- sc .: "finalState"
|
|
||||||
ocf <- oc .: "finalState"
|
|
||||||
pure $ ZebraTreeInfo h t sf ocf
|
|
||||||
|
|
||||||
-- ** `zcashd`
|
|
||||||
-- | Type for modelling the different address sources for `zcashd` 5.0.0
|
-- | Type for modelling the different address sources for `zcashd` 5.0.0
|
||||||
data AddressSource
|
data AddressSource
|
||||||
= LegacyRandom
|
= LegacyRandom
|
||||||
|
|
|
@ -31,14 +31,6 @@ displayZec s
|
||||||
| s < 100000000 = show (fromIntegral s / 100000) ++ " mZEC "
|
| s < 100000000 = show (fromIntegral s / 100000) ++ " mZEC "
|
||||||
| otherwise = show (fromIntegral s / 100000000) ++ " ZEC "
|
| otherwise = show (fromIntegral s / 100000000) ++ " ZEC "
|
||||||
|
|
||||||
-- | Helper function to display small amounts of ZEC
|
|
||||||
displayTaz :: Integer -> String
|
|
||||||
displayTaz s
|
|
||||||
| s < 100 = show s ++ " tazs "
|
|
||||||
| s < 100000 = show (fromIntegral s / 100) ++ " μTAZ "
|
|
||||||
| s < 100000000 = show (fromIntegral s / 100000) ++ " mTAZ "
|
|
||||||
| otherwise = show (fromIntegral s / 100000000) ++ " TAZ "
|
|
||||||
|
|
||||||
-- | Helper function to display abbreviated Unified Address
|
-- | Helper function to display abbreviated Unified Address
|
||||||
showAddress :: UnifiedAddressDB -> T.Text
|
showAddress :: UnifiedAddressDB -> T.Text
|
||||||
showAddress u = T.take 20 t <> "..."
|
showAddress u = T.take 20 t <> "..."
|
||||||
|
|
64
test/Spec.hs
64
test/Spec.hs
|
@ -1,27 +1,16 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
import Control.Monad (when)
|
import Control.Monad (when)
|
||||||
import Data.HexString
|
|
||||||
import Database.Persist
|
import Database.Persist
|
||||||
import Database.Persist.Sqlite
|
import Database.Persist.Sqlite
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import Test.HUnit
|
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import ZcashHaskell.Orchard (isValidUnifiedAddress)
|
import ZcashHaskell.Orchard (isValidUnifiedAddress)
|
||||||
import ZcashHaskell.Sapling
|
|
||||||
( decodeSaplingOutputEsk
|
|
||||||
, getSaplingNotePosition
|
|
||||||
, getSaplingWitness
|
|
||||||
, updateSaplingCommitmentTree
|
|
||||||
)
|
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( DecodedNote(..)
|
( OrchardSpendingKey(..)
|
||||||
, OrchardSpendingKey(..)
|
|
||||||
, Phrase(..)
|
, Phrase(..)
|
||||||
, SaplingCommitmentTree(..)
|
|
||||||
, SaplingSpendingKey(..)
|
, SaplingSpendingKey(..)
|
||||||
, Scope(..)
|
, Scope(..)
|
||||||
, ShieldedOutput(..)
|
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
)
|
)
|
||||||
import Zenith.Core
|
import Zenith.Core
|
||||||
|
@ -49,7 +38,6 @@ main = do
|
||||||
Phrase
|
Phrase
|
||||||
"one two three four five six seven eight nine ten eleven twelve")
|
"one two three four five six seven eight nine ten eleven twelve")
|
||||||
2000000
|
2000000
|
||||||
0
|
|
||||||
fromSqlKey s `shouldBe` 1
|
fromSqlKey s `shouldBe` 1
|
||||||
it "read wallet record" $ do
|
it "read wallet record" $ do
|
||||||
s <-
|
s <-
|
||||||
|
@ -81,7 +69,6 @@ main = do
|
||||||
Phrase
|
Phrase
|
||||||
"cloth swing left trap random tornado have great onion element until make shy dad success art tuition canvas thunder apple decade elegant struggle invest")
|
"cloth swing left trap random tornado have great onion element until make shy dad success art tuition canvas thunder apple decade elegant struggle invest")
|
||||||
2200000
|
2200000
|
||||||
0
|
|
||||||
zw `shouldNotBe` Nothing
|
zw `shouldNotBe` Nothing
|
||||||
it "Save Account:" $ do
|
it "Save Account:" $ do
|
||||||
s <-
|
s <-
|
||||||
|
@ -111,52 +98,3 @@ main = do
|
||||||
let ua =
|
let ua =
|
||||||
"utest1mvlny48qd4x94w8vz5u2lrxx0enuquajt72yekgq24p6pjaky3czk6m7x358h7g900ex6gzvdehaekl96qnakjzw8yaasp8y0u3j5jnlfd33trduznh6k3fcn5ek9qc857fgz8ehm37etx94sj58nrkc0k5hurxnuxpcpms3j8uy2t8kt2vy6vetvsfxxdhtjq0yqulqprvh7mf2u3x"
|
"utest1mvlny48qd4x94w8vz5u2lrxx0enuquajt72yekgq24p6pjaky3czk6m7x358h7g900ex6gzvdehaekl96qnakjzw8yaasp8y0u3j5jnlfd33trduznh6k3fcn5ek9qc857fgz8ehm37etx94sj58nrkc0k5hurxnuxpcpms3j8uy2t8kt2vy6vetvsfxxdhtjq0yqulqprvh7mf2u3x"
|
||||||
isValidUnifiedAddress ua `shouldNotBe` Nothing
|
isValidUnifiedAddress ua `shouldNotBe` Nothing
|
||||||
describe "Function tests" $ do
|
|
||||||
describe "Sapling Decoding" $ do
|
|
||||||
let sk =
|
|
||||||
SaplingSpendingKey
|
|
||||||
"\ETX}\195.\SUB\NUL\NUL\NUL\128\NUL\203\"\229IL\CANJ*\209\EM\145\228m\172\&4\SYNNl\DC3\161\147\SO\157\238H\192\147eQ\143L\201\216\163\180\147\145\156Zs+\146>8\176`ta\161\223\SO\140\177\b;\161\SO\236\151W\148<\STX\171|\DC2\172U\195(I\140\146\214\182\137\211\228\159\128~bV\STXy{m'\224\175\221\219\180!\ENQ_\161\132\240?\255\236\"6\133\181\170t\181\139\143\207\170\211\ENQ\167a\184\163\243\246\140\158t\155\133\138X\a\241\200\140\EMT\GS~\175\249&z\250\214\231\239mi\223\206\STX\t\EM<{V~J\253FB"
|
|
||||||
let tree =
|
|
||||||
SaplingCommitmentTree $
|
|
||||||
hexString
|
|
||||||
"01818f2bd58b1e392334d0565181cc7843ae09e3533b2a50a8f1131af657340a5c001001161f962245812ba5e1804fd0a336bc78fa4ee4441a8e0f1525ca5da1b285d35101120f45afa700b8c1854aa8b9c8fe8ed92118ef790584bfcb926078812a10c83a00000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
|
|
||||||
let nextTree =
|
|
||||||
SaplingCommitmentTree $
|
|
||||||
hexString
|
|
||||||
"01bd8a3f3cfc964332a2ada8c09a0da9dfc24174befb938abb086b9be5ca049e4900100000019f0d7efb00169bb2202152d3266059d208ab17d14642c3339f9075e997160657000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
|
|
||||||
it "Sapling is decoded correctly" $ do
|
|
||||||
so <-
|
|
||||||
runSqlite "zenith.db" $
|
|
||||||
selectList [ShieldOutputTx ==. toSqlKey 38318] []
|
|
||||||
let cmus = map (getHex . shieldOutputCmu . entityVal) so
|
|
||||||
let pos =
|
|
||||||
getSaplingNotePosition <$>
|
|
||||||
(getSaplingWitness =<<
|
|
||||||
updateSaplingCommitmentTree tree (head cmus))
|
|
||||||
let pos1 = getSaplingNotePosition <$> getSaplingWitness tree
|
|
||||||
let pos2 = getSaplingNotePosition <$> getSaplingWitness nextTree
|
|
||||||
case pos of
|
|
||||||
Nothing -> assertFailure "couldn't get note position"
|
|
||||||
Just p -> do
|
|
||||||
print p
|
|
||||||
print pos1
|
|
||||||
print pos2
|
|
||||||
let dn =
|
|
||||||
decodeSaplingOutputEsk
|
|
||||||
sk
|
|
||||||
(ShieldedOutput
|
|
||||||
(getHex $ shieldOutputCv $ entityVal $ head so)
|
|
||||||
(getHex $ shieldOutputCmu $ entityVal $ head so)
|
|
||||||
(getHex $ shieldOutputEphKey $ entityVal $ head so)
|
|
||||||
(getHex $ shieldOutputEncCipher $ entityVal $ head so)
|
|
||||||
(getHex $ shieldOutputOutCipher $ entityVal $ head so)
|
|
||||||
(getHex $ shieldOutputProof $ entityVal $ head so))
|
|
||||||
TestNet
|
|
||||||
External
|
|
||||||
p
|
|
||||||
case dn of
|
|
||||||
Nothing -> assertFailure "couldn't decode Sap output"
|
|
||||||
Just d ->
|
|
||||||
a_nullifier d `shouldBe`
|
|
||||||
hexString
|
|
||||||
"6c5d1413c63a9a88db71c3f41dc12cd60197ee742fc75b217215e7144db48bd3"
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 00400c433dd8a584ef19af58fcab7fdd108d4110
|
Subproject commit 938ccb4b9730fd8615513eb27bdbffacd62e29cc
|
|
@ -1,6 +1,6 @@
|
||||||
cabal-version: 3.0
|
cabal-version: 3.0
|
||||||
name: zenith
|
name: zenith
|
||||||
version: 0.4.6.0
|
version: 0.4.4.3
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Rene Vergara
|
author: Rene Vergara
|
||||||
|
@ -39,12 +39,10 @@ library
|
||||||
Clipboard
|
Clipboard
|
||||||
, aeson
|
, aeson
|
||||||
, array
|
, array
|
||||||
, ascii-progress
|
|
||||||
, base >=4.12 && <5
|
, base >=4.12 && <5
|
||||||
, base64-bytestring
|
, base64-bytestring
|
||||||
, brick
|
, brick
|
||||||
, bytestring
|
, bytestring
|
||||||
, esqueleto
|
|
||||||
, ghc
|
, ghc
|
||||||
, haskoin-core
|
, haskoin-core
|
||||||
, hexstring
|
, hexstring
|
||||||
|
@ -64,10 +62,10 @@ library
|
||||||
, regex-posix
|
, regex-posix
|
||||||
, scientific
|
, scientific
|
||||||
, text
|
, text
|
||||||
, time
|
|
||||||
, vector
|
, vector
|
||||||
, vty
|
, vty
|
||||||
, word-wrap
|
, word-wrap
|
||||||
|
, ascii-progress
|
||||||
, zcash-haskell
|
, zcash-haskell
|
||||||
--pkgconfig-depends: rustzcash_wrapper
|
--pkgconfig-depends: rustzcash_wrapper
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
@ -121,8 +119,6 @@ test-suite zenith-tests
|
||||||
, persistent
|
, persistent
|
||||||
, persistent-sqlite
|
, persistent-sqlite
|
||||||
, hspec
|
, hspec
|
||||||
, hexstring
|
|
||||||
, HUnit
|
|
||||||
, directory
|
, directory
|
||||||
, zcash-haskell
|
, zcash-haskell
|
||||||
, zenith
|
, zenith
|
||||||
|
|
Loading…
Reference in a new issue