Compare commits
No commits in common. "master" and "0.5.2.0-beta" have entirely different histories.
master
...
0.5.2.0-be
47 changed files with 1170 additions and 14959 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,11 +1,3 @@
|
||||||
.stack-work/
|
.stack-work/
|
||||||
*~
|
*~
|
||||||
dist-newstyle/
|
dist-newstyle/
|
||||||
zenith.db
|
|
||||||
zenith.log
|
|
||||||
zenith.db-shm
|
|
||||||
zenith.db-wal
|
|
||||||
test.db
|
|
||||||
test.db-shm
|
|
||||||
test.db-wal
|
|
||||||
|
|
||||||
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -1,4 +1,4 @@
|
||||||
[submodule "zcash-haskell"]
|
[submodule "zcash-haskell"]
|
||||||
path = zcash-haskell
|
path = zcash-haskell
|
||||||
url = https://code.vergara.tech/Vergara_Tech/zcash-haskell
|
url = https://git.vergara.tech/Vergara_Tech/zcash-haskell.git
|
||||||
branch = master
|
branch = milestone2
|
||||||
|
|
146
CHANGELOG.md
146
CHANGELOG.md
|
@ -5,152 +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.9.1.0-beta]
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- RPC imports
|
|
||||||
|
|
||||||
## [0.9.0.0-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- RPC
|
|
||||||
- `importvk`
|
|
||||||
- TUI
|
|
||||||
- Import viewing keys
|
|
||||||
- Import seed phrase
|
|
||||||
- GUI
|
|
||||||
- Import viewing keys
|
|
||||||
- Import seed phrase
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Database schema for wallets and accounts
|
|
||||||
- RPC:
|
|
||||||
- New field in wallet schema
|
|
||||||
- New field in account schema
|
|
||||||
|
|
||||||
## [0.8.0.0-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- TUI:
|
|
||||||
- Generate payment URI
|
|
||||||
- Read a payment URI
|
|
||||||
- Generate a Full Viewing Key
|
|
||||||
- Generate an Incoming Viewing Key
|
|
||||||
|
|
||||||
- GUI:
|
|
||||||
- Generate payment URI and QR code
|
|
||||||
- Read a payment URI and QR code
|
|
||||||
- Generate a Full Viewing Key
|
|
||||||
- Generate an Incoming Viewing Key
|
|
||||||
|
|
||||||
- RPC methods:
|
|
||||||
- `shieldnotes`
|
|
||||||
- `deshieldfunds`
|
|
||||||
- `getfullvk`
|
|
||||||
- `getincomingvk`
|
|
||||||
|
|
||||||
## [0.7.2.0-beta]
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Creation of change addresses during account creation in GUI ([#111](https://code.vergara.tech/Vergara_Tech/zenith/issues/111))
|
|
||||||
|
|
||||||
## [0.7.1.0-beta]
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Removed workaround to obtain block time
|
|
||||||
|
|
||||||
## [0.7.0.0-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- RPC module
|
|
||||||
- OpenRPC specification
|
|
||||||
- `listwallets` RPC method
|
|
||||||
- `listaccounts` RPC method
|
|
||||||
- `listaddresses` RPC method
|
|
||||||
- `listreceived` RPC method
|
|
||||||
- `getbalance` RPC method
|
|
||||||
- `getnewwallet` RPC method
|
|
||||||
- `getnewaccount` RPC method
|
|
||||||
- `getnewaddress` RPC method
|
|
||||||
- `getoperationstatus` RPC method
|
|
||||||
- `sendmany` RPC method
|
|
||||||
- Function `prepareTxV2` implementing `PrivacyPolicy`
|
|
||||||
- Support for TEX addresses
|
|
||||||
- Functionality to shield transparent balance
|
|
||||||
- Functionality to de-shield shielded notes
|
|
||||||
- Native commitment trees
|
|
||||||
- Batch append to trees in O(log n)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Detection of changes in database schema for automatic re-scan
|
|
||||||
- Block tracking for chain re-org detection
|
|
||||||
- Refactored `ZcashPool`
|
|
||||||
- Preventing write operations to occur during wallet sync
|
|
||||||
|
|
||||||
|
|
||||||
## [0.6.0.0-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- GUI module
|
|
||||||
- Address list
|
|
||||||
- Transaction list
|
|
||||||
- Balance display
|
|
||||||
- Account selector
|
|
||||||
- Menu for new addresses, accounts, wallets
|
|
||||||
- Dialog to display and copy seed phrase
|
|
||||||
- Dialog to add new address
|
|
||||||
- Dialog to add new account
|
|
||||||
- Dialog to add new wallet
|
|
||||||
- Dialog to display transaction details and copy TX ID
|
|
||||||
- Dialog to send a new transaction
|
|
||||||
- Dialog to display Tx ID after successful broadcast
|
|
||||||
- Unconfirmed balance display on TUI and GUI
|
|
||||||
- Tracking of unconfirmed notes
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Upgraded to GHC 9.6.5
|
|
||||||
- Implemented config and data folder
|
|
||||||
- Improved the `configure` script for installation
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Validation of input of amount for sending in TUI
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
|
|
||||||
- Legacy interface to `zcashd`
|
|
||||||
|
|
||||||
## [0.5.3.1-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Docker image
|
|
||||||
|
|
||||||
## [0.5.3.0-beta]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Address Book functionality. Allows users to store frequently used zcash addresses and
|
|
||||||
generate transactions using them.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Improved formatting of sync progress
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Wallet sync when no new block has been detected on-chain.
|
|
||||||
|
|
||||||
## [0.5.2.0-beta]
|
## [0.5.2.0-beta]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -21,7 +21,6 @@ Zenith is a wallet for the [Zebra](https://zfnd.org/zebra/) Zcash node . It has
|
||||||
- Listing transactions for specific addresses, decoding memos for easy reading.
|
- Listing transactions for specific addresses, decoding memos for easy reading.
|
||||||
- Copying addresses to the clipboard.
|
- Copying addresses to the clipboard.
|
||||||
- Sending transactions with shielded memo support.
|
- Sending transactions with shielded memo support.
|
||||||
- Address Book for storing frequently used zcash addresses
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
45
app/Main.hs
45
app/Main.hs
|
@ -11,20 +11,18 @@ import Data.Sort
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.IO as TIO
|
import qualified Data.Text.IO as TIO
|
||||||
import Data.Time.Clock.POSIX
|
import Data.Time.Clock.POSIX
|
||||||
|
import System.Console.StructuredCLI
|
||||||
{-import System.Console.StructuredCLI-}
|
|
||||||
import System.Environment (getArgs)
|
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 ZcashHaskell.Types
|
||||||
import Zenith.CLI
|
import Zenith.CLI
|
||||||
import Zenith.GUI (runZenithGUI)
|
import Zenith.Core (clearSync, testSync)
|
||||||
import Zenith.Scanner (clearSync, rescanZebra)
|
|
||||||
import Zenith.Types (Config(..), ZcashAddress(..), ZcashPool(..), ZcashTx(..))
|
import Zenith.Types (Config(..), ZcashAddress(..), ZcashPool(..), ZcashTx(..))
|
||||||
import Zenith.Utils
|
import Zenith.Utils
|
||||||
import Zenith.Zcashd
|
import Zenith.Zcashd
|
||||||
{-
|
|
||||||
prompt :: String -> IO String
|
prompt :: String -> IO String
|
||||||
prompt text = do
|
prompt text = do
|
||||||
putStr text
|
putStr text
|
||||||
|
@ -198,34 +196,21 @@ processUri user pwd =
|
||||||
_ -> False
|
_ -> False
|
||||||
_ <- liftIO $ sendWithUri user pwd (addList !! (idx - 1)) u repTo
|
_ <- liftIO $ sendWithUri user pwd (addList !! (idx - 1)) u repTo
|
||||||
return NoAction
|
return NoAction
|
||||||
-}
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
config <- load ["$(HOME)/Zenith/zenith.cfg"]
|
config <- load ["zenith.cfg"]
|
||||||
args <- getArgs
|
args <- getArgs
|
||||||
dbFileName <- require config "dbFileName"
|
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"
|
||||||
zebraHost <- require config "zebraHost"
|
zebraHost <- require config "zebraHost"
|
||||||
nodePort <- require config "nodePort"
|
let myConfig = Config dbFilePath zebraHost zebraPort
|
||||||
currencyCode <- require config "currencyCode"
|
|
||||||
dbFP <- getZenithPath
|
|
||||||
let dbFilePath = T.pack $ dbFP ++ dbFileName
|
|
||||||
let myConfig =
|
|
||||||
Config
|
|
||||||
dbFilePath
|
|
||||||
zebraHost
|
|
||||||
zebraPort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
nodePort
|
|
||||||
currencyCode
|
|
||||||
if not (null args)
|
if not (null args)
|
||||||
then do
|
then do
|
||||||
case head args
|
case head args of
|
||||||
{-"legacy" -> do
|
"legacy" -> do
|
||||||
checkServer nodeUser nodePwd
|
checkServer nodeUser nodePwd
|
||||||
void $
|
void $
|
||||||
runCLI
|
runCLI
|
||||||
|
@ -234,12 +219,9 @@ main = do
|
||||||
{ getBanner =
|
{ getBanner =
|
||||||
" ______ _ _ _ \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)
|
||||||
of
|
"cli" -> runZenithCLI myConfig
|
||||||
"gui" -> runZenithGUI myConfig
|
"rescan" -> clearSync myConfig
|
||||||
"tui" -> runZenithTUI myConfig
|
|
||||||
"rescan" -> rescanZebra zebraHost zebraPort dbFilePath
|
|
||||||
"resync" -> clearSync myConfig
|
|
||||||
_ -> printUsage
|
_ -> printUsage
|
||||||
else printUsage
|
else printUsage
|
||||||
|
|
||||||
|
@ -247,7 +229,6 @@ printUsage :: IO ()
|
||||||
printUsage = do
|
printUsage = do
|
||||||
putStrLn "zenith [command] [parameters]\n"
|
putStrLn "zenith [command] [parameters]\n"
|
||||||
putStrLn "Available commands:"
|
putStrLn "Available commands:"
|
||||||
{-putStrLn "legacy\tLegacy CLI for zcashd"-}
|
putStrLn "legacy\tLegacy CLI for zcashd"
|
||||||
putStrLn "tui\tTUI for zebrad"
|
putStrLn "cli\tCLI for zebrad"
|
||||||
putStrLn "gui\tGUI for zebrad"
|
|
||||||
putStrLn "rescan\tRescan the existing wallet(s)"
|
putStrLn "rescan\tRescan the existing wallet(s)"
|
||||||
|
|
101
app/Server.hs
101
app/Server.hs
|
@ -1,101 +0,0 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module Server where
|
|
||||||
|
|
||||||
import Control.Concurrent (forkIO, threadDelay)
|
|
||||||
import Control.Exception (throwIO, throwTo, try)
|
|
||||||
import Control.Monad (forever, when)
|
|
||||||
import Control.Monad.Logger (runNoLoggingT, runStderrLoggingT)
|
|
||||||
import Data.Configurator
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import Network.Wai.Handler.Warp (run)
|
|
||||||
import Servant
|
|
||||||
import System.Exit
|
|
||||||
import System.Posix.Signals
|
|
||||||
import ZcashHaskell.Types (ZebraGetBlockChainInfo(..), ZebraGetInfo(..))
|
|
||||||
import Zenith.Core (checkBlockChain, checkZebra)
|
|
||||||
import Zenith.DB (getWallets, initDb, initPool, upgradeAccountTable)
|
|
||||||
import Zenith.RPC
|
|
||||||
( State(..)
|
|
||||||
, ZenithRPC(..)
|
|
||||||
, authenticate
|
|
||||||
, scanZebra
|
|
||||||
, zenithServer
|
|
||||||
)
|
|
||||||
import Zenith.Scanner (rescanZebra)
|
|
||||||
import Zenith.Types (Config(..))
|
|
||||||
import Zenith.Utils (getZenithPath)
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = do
|
|
||||||
config <- load ["$(HOME)/Zenith/zenith.cfg"]
|
|
||||||
dbFileName <- require config "dbFileName"
|
|
||||||
nodeUser <- require config "nodeUser"
|
|
||||||
nodePwd <- require config "nodePwd"
|
|
||||||
zebraPort <- require config "zebraPort"
|
|
||||||
zebraHost <- require config "zebraHost"
|
|
||||||
nodePort <- require config "nodePort"
|
|
||||||
currencyCode <- require config "currencyCode"
|
|
||||||
dbFP <- getZenithPath
|
|
||||||
let dbFilePath = T.pack $ dbFP ++ dbFileName
|
|
||||||
let myConfig =
|
|
||||||
Config
|
|
||||||
dbFilePath
|
|
||||||
zebraHost
|
|
||||||
zebraPort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
nodePort
|
|
||||||
currencyCode
|
|
||||||
let ctx = authenticate myConfig :. EmptyContext
|
|
||||||
w <- try $ checkZebra zebraHost zebraPort :: IO (Either IOError ZebraGetInfo)
|
|
||||||
case w of
|
|
||||||
Right zebra -> do
|
|
||||||
bc <-
|
|
||||||
try $ checkBlockChain zebraHost zebraPort :: IO
|
|
||||||
(Either IOError ZebraGetBlockChainInfo)
|
|
||||||
case bc of
|
|
||||||
Left e1 -> throwIO e1
|
|
||||||
Right chainInfo -> do
|
|
||||||
x <- runNoLoggingT $ initDb dbFilePath
|
|
||||||
case x of
|
|
||||||
Left e2 -> throwIO $ userError e2
|
|
||||||
Right x' -> do
|
|
||||||
when x' $ rescanZebra zebraHost zebraPort dbFilePath
|
|
||||||
pool <- runNoLoggingT $ initPool dbFilePath
|
|
||||||
_ <- runNoLoggingT $ upgradeAccountTable pool
|
|
||||||
walList <- getWallets pool $ zgb_net chainInfo
|
|
||||||
if not (null walList)
|
|
||||||
then do
|
|
||||||
scanThread <-
|
|
||||||
forkIO $
|
|
||||||
forever $ do
|
|
||||||
_ <-
|
|
||||||
scanZebra
|
|
||||||
dbFilePath
|
|
||||||
zebraHost
|
|
||||||
zebraPort
|
|
||||||
(zgb_net chainInfo)
|
|
||||||
threadDelay 90000000
|
|
||||||
putStrLn "Zenith RPC Server 0.9.1.0-beta"
|
|
||||||
putStrLn "------------------------------"
|
|
||||||
putStrLn $
|
|
||||||
"Connected to " ++
|
|
||||||
show (zgb_net chainInfo) ++
|
|
||||||
" Zebra " ++
|
|
||||||
T.unpack (zgi_build zebra) ++ " on port " ++ show zebraPort
|
|
||||||
let myState =
|
|
||||||
State
|
|
||||||
(zgb_net chainInfo)
|
|
||||||
zebraHost
|
|
||||||
zebraPort
|
|
||||||
dbFilePath
|
|
||||||
(zgi_build zebra)
|
|
||||||
(zgb_blocks chainInfo)
|
|
||||||
run nodePort $
|
|
||||||
serveWithContext
|
|
||||||
(Proxy :: Proxy ZenithRPC)
|
|
||||||
ctx
|
|
||||||
(zenithServer myState)
|
|
||||||
else putStrLn
|
|
||||||
"No wallets available. Please start Zenith interactively to create a wallet"
|
|
|
@ -4,7 +4,7 @@ module ZenScan where
|
||||||
|
|
||||||
import Control.Monad.Logger (runNoLoggingT)
|
import Control.Monad.Logger (runNoLoggingT)
|
||||||
import Data.Configurator
|
import Data.Configurator
|
||||||
import Zenith.Scanner (rescanZebra)
|
import Zenith.Scanner (scanZebra)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
BIN
assets/1F993.png
BIN
assets/1F993.png
Binary file not shown.
Before Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
@ -2,19 +2,14 @@ packages:
|
||||||
./*.cabal
|
./*.cabal
|
||||||
zcash-haskell/zcash-haskell.cabal
|
zcash-haskell/zcash-haskell.cabal
|
||||||
|
|
||||||
with-compiler: ghc-9.6.5
|
with-compiler: ghc-9.4.8
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://code.vergara.tech/Vergara_Tech/haskell-hexstring.git
|
location: https://git.vergara.tech/Vergara_Tech/haskell-hexstring.git
|
||||||
tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7
|
tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://code.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
|
location: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
|
||||||
tag: 335e804454cd30da2c526457be37e477f71e4665
|
tag: 335e804454cd30da2c526457be37e477f71e4665
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://code.vergara.tech/Vergara_Tech/persistent-sqlite.git
|
|
||||||
tag: 85093ef51cb2bd245ac9a85925770fdb55afce9e
|
|
||||||
|
|
|
@ -1,372 +0,0 @@
|
||||||
active-repositories: hackage.haskell.org:merge
|
|
||||||
constraints: any.Cabal ==3.10.3.0,
|
|
||||||
any.Cabal-syntax ==3.10.3.0,
|
|
||||||
any.Clipboard ==2.3.2.0,
|
|
||||||
any.HUnit ==1.6.2.0,
|
|
||||||
any.Hclip ==3.0.0.4,
|
|
||||||
any.JuicyPixels ==3.3.9,
|
|
||||||
JuicyPixels -mmap,
|
|
||||||
any.OneTuple ==0.4.2,
|
|
||||||
any.OpenGLRaw ==3.3.4.1,
|
|
||||||
OpenGLRaw -osandroid +usegles2 +useglxgetprocaddress +usenativewindowslibraries,
|
|
||||||
any.QuickCheck ==2.15.0.1,
|
|
||||||
QuickCheck -old-random +templatehaskell,
|
|
||||||
any.RSA ==2.4.1,
|
|
||||||
any.SHA ==1.6.4.4,
|
|
||||||
SHA -exe,
|
|
||||||
any.StateVar ==1.2.2,
|
|
||||||
any.X11 ==1.9.2,
|
|
||||||
any.adjunctions ==4.4.2,
|
|
||||||
any.aeson ==2.2.3.0,
|
|
||||||
aeson +ordered-keymap,
|
|
||||||
any.alex ==3.5.1.0,
|
|
||||||
any.ansi-terminal ==1.1.2,
|
|
||||||
ansi-terminal -example,
|
|
||||||
any.ansi-terminal-types ==1.1,
|
|
||||||
any.appar ==0.1.8,
|
|
||||||
any.array ==0.5.6.0,
|
|
||||||
any.ascii-progress ==0.3.3.0,
|
|
||||||
ascii-progress -examples,
|
|
||||||
any.asn1-encoding ==0.9.6,
|
|
||||||
any.asn1-parse ==0.9.5,
|
|
||||||
any.asn1-types ==0.3.4,
|
|
||||||
any.assoc ==1.1.1,
|
|
||||||
assoc -tagged,
|
|
||||||
any.async ==2.2.5,
|
|
||||||
async -bench,
|
|
||||||
any.attoparsec ==0.14.4,
|
|
||||||
attoparsec -developer,
|
|
||||||
any.attoparsec-aeson ==2.2.2.0,
|
|
||||||
any.authenticate-oauth ==1.7,
|
|
||||||
any.auto-update ==0.2.4,
|
|
||||||
any.base ==4.18.2.1,
|
|
||||||
any.base-compat ==0.14.1,
|
|
||||||
any.base-compat-batteries ==0.14.1,
|
|
||||||
any.base-orphans ==0.9.3,
|
|
||||||
any.base16 ==1.0,
|
|
||||||
any.base16-bytestring ==1.0.2.0,
|
|
||||||
any.base58-bytestring ==0.1.0,
|
|
||||||
any.base64-bytestring ==1.2.1.0,
|
|
||||||
any.basement ==0.0.16,
|
|
||||||
any.bifunctors ==5.6.2,
|
|
||||||
bifunctors +tagged,
|
|
||||||
any.bimap ==0.5.0,
|
|
||||||
any.binary ==0.8.9.1,
|
|
||||||
any.binary-orphans ==1.0.5,
|
|
||||||
any.bitvec ==1.1.5.0,
|
|
||||||
bitvec +simd,
|
|
||||||
any.blaze-builder ==0.4.2.3,
|
|
||||||
any.blaze-html ==0.9.2.0,
|
|
||||||
any.blaze-markup ==0.8.3.0,
|
|
||||||
any.boring ==0.2.2,
|
|
||||||
boring +tagged,
|
|
||||||
any.borsh ==0.3.0,
|
|
||||||
any.brick ==2.6,
|
|
||||||
brick -demos,
|
|
||||||
any.bsb-http-chunked ==0.0.0.4,
|
|
||||||
any.byteorder ==1.0.4,
|
|
||||||
any.bytes ==0.17.4,
|
|
||||||
any.bytestring ==0.11.5.3,
|
|
||||||
any.bytestring-to-vector ==0.3.0.1,
|
|
||||||
any.c2hs ==0.28.8,
|
|
||||||
c2hs +base3 -regression,
|
|
||||||
any.cabal-doctest ==1.0.11,
|
|
||||||
any.call-stack ==0.4.0,
|
|
||||||
any.case-insensitive ==1.2.1.0,
|
|
||||||
any.cborg ==0.2.10.0,
|
|
||||||
cborg +optimize-gmp,
|
|
||||||
any.cereal ==0.5.8.3,
|
|
||||||
cereal -bytestring-builder,
|
|
||||||
any.character-ps ==0.1,
|
|
||||||
any.clock ==0.8.4,
|
|
||||||
clock -llvm,
|
|
||||||
any.colour ==2.3.6,
|
|
||||||
any.comonad ==5.0.9,
|
|
||||||
comonad +containers +distributive +indexed-traversable,
|
|
||||||
any.concurrent-output ==1.10.21,
|
|
||||||
any.conduit ==1.3.6,
|
|
||||||
any.conduit-extra ==1.3.6,
|
|
||||||
any.config-ini ==0.2.7.0,
|
|
||||||
config-ini -enable-doctests,
|
|
||||||
any.configurator ==0.3.0.0,
|
|
||||||
configurator -developer,
|
|
||||||
any.constraints ==0.14.2,
|
|
||||||
any.containers ==0.6.7,
|
|
||||||
any.contravariant ==1.5.5,
|
|
||||||
contravariant +semigroups +statevar +tagged,
|
|
||||||
any.cookie ==0.5.0,
|
|
||||||
any.crypto-api ==0.13.3,
|
|
||||||
crypto-api -all_cpolys,
|
|
||||||
any.crypto-pubkey-types ==0.4.3,
|
|
||||||
any.cryptohash-md5 ==0.11.101.0,
|
|
||||||
any.cryptohash-sha1 ==0.11.101.0,
|
|
||||||
any.crypton ==1.0.1,
|
|
||||||
crypton -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq +support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
|
|
||||||
any.crypton-connection ==0.4.3,
|
|
||||||
any.crypton-x509 ==1.7.7,
|
|
||||||
any.crypton-x509-store ==1.6.9,
|
|
||||||
any.crypton-x509-system ==1.6.7,
|
|
||||||
any.crypton-x509-validation ==1.6.13,
|
|
||||||
any.cryptonite ==0.30,
|
|
||||||
cryptonite -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq -support_pclmuldq +support_rdrand -support_sse +use_target_attributes,
|
|
||||||
any.data-clist ==0.2,
|
|
||||||
any.data-default ==0.8.0.0,
|
|
||||||
any.data-default-class ==0.2.0.0,
|
|
||||||
any.data-fix ==0.3.4,
|
|
||||||
any.dec ==0.0.6,
|
|
||||||
any.deepseq ==1.4.8.1,
|
|
||||||
any.directory ==1.3.8.4,
|
|
||||||
any.distributive ==0.6.2.1,
|
|
||||||
distributive +semigroups +tagged,
|
|
||||||
any.dlist ==1.0,
|
|
||||||
dlist -werror,
|
|
||||||
any.double-conversion ==2.0.5.0,
|
|
||||||
double-conversion -developer +embedded_double_conversion,
|
|
||||||
any.easy-file ==0.2.5,
|
|
||||||
any.entropy ==0.4.1.10,
|
|
||||||
entropy -donotgetentropy,
|
|
||||||
any.envy ==2.1.4.0,
|
|
||||||
any.esqueleto ==3.5.13.1,
|
|
||||||
any.exceptions ==0.10.7,
|
|
||||||
any.extra ==1.8,
|
|
||||||
any.fast-logger ==3.2.5,
|
|
||||||
any.file-embed ==0.0.16.0,
|
|
||||||
any.filepath ==1.4.300.1,
|
|
||||||
any.fixed ==0.3,
|
|
||||||
any.foreign-rust ==0.1.0,
|
|
||||||
any.foreign-store ==0.2.1,
|
|
||||||
any.formatting ==7.2.0,
|
|
||||||
formatting -no-double-conversion,
|
|
||||||
any.free ==5.2,
|
|
||||||
any.generically ==0.1.1,
|
|
||||||
any.generics-sop ==0.5.1.4,
|
|
||||||
any.ghc ==9.6.5,
|
|
||||||
any.ghc-bignum ==1.3,
|
|
||||||
any.ghc-boot ==9.6.5,
|
|
||||||
any.ghc-boot-th ==9.6.5,
|
|
||||||
any.ghc-heap ==9.6.5,
|
|
||||||
any.ghc-prim ==0.10.0,
|
|
||||||
any.ghci ==9.6.5,
|
|
||||||
any.half ==0.3.2,
|
|
||||||
any.happy ==2.1.3,
|
|
||||||
any.happy-lib ==2.1.3,
|
|
||||||
any.hashable ==1.4.7.0,
|
|
||||||
hashable -arch-native +integer-gmp -random-initial-seed,
|
|
||||||
any.haskell-lexer ==1.1.2,
|
|
||||||
any.haskoin-core ==1.1.0,
|
|
||||||
any.hexstring ==0.12.1.0,
|
|
||||||
any.hourglass ==0.2.12,
|
|
||||||
any.hpc ==0.6.2.0,
|
|
||||||
any.hsc2hs ==0.68.10,
|
|
||||||
hsc2hs -in-ghc-tree,
|
|
||||||
any.hspec ==2.11.10,
|
|
||||||
any.hspec-core ==2.11.10,
|
|
||||||
any.hspec-discover ==2.11.10,
|
|
||||||
any.hspec-expectations ==0.8.4,
|
|
||||||
any.http-api-data ==0.6.1,
|
|
||||||
http-api-data -use-text-show,
|
|
||||||
any.http-client ==0.7.17,
|
|
||||||
http-client +network-uri,
|
|
||||||
any.http-client-tls ==0.3.6.4,
|
|
||||||
any.http-conduit ==2.3.9.1,
|
|
||||||
http-conduit +aeson,
|
|
||||||
any.http-date ==0.0.11,
|
|
||||||
any.http-media ==0.8.1.1,
|
|
||||||
any.http-semantics ==0.3.0,
|
|
||||||
any.http-types ==0.12.4,
|
|
||||||
any.http2 ==5.3.9,
|
|
||||||
http2 -devel -h2spec,
|
|
||||||
any.indexed-traversable ==0.1.4,
|
|
||||||
any.indexed-traversable-instances ==0.1.2,
|
|
||||||
any.integer-conversion ==0.1.1,
|
|
||||||
any.integer-gmp ==1.1,
|
|
||||||
any.integer-logarithms ==1.0.3.1,
|
|
||||||
integer-logarithms -check-bounds +integer-gmp,
|
|
||||||
any.invariant ==0.6.4,
|
|
||||||
any.iproute ==1.7.15,
|
|
||||||
any.kan-extensions ==5.2.6,
|
|
||||||
any.language-c ==0.10.0,
|
|
||||||
language-c +iecfpextension +usebytestrings,
|
|
||||||
any.lens ==5.3.2,
|
|
||||||
lens -benchmark-uniplate -dump-splices +inlining -j +test-hunit +test-properties +test-templates +trustworthy,
|
|
||||||
any.lens-aeson ==1.2.3,
|
|
||||||
any.lift-type ==0.1.2.0,
|
|
||||||
any.lifted-base ==0.2.3.12,
|
|
||||||
any.linear ==1.22,
|
|
||||||
linear -herbie +template-haskell,
|
|
||||||
any.megaparsec ==9.7.0,
|
|
||||||
megaparsec -dev,
|
|
||||||
any.memory ==0.18.0,
|
|
||||||
memory +support_bytestring +support_deepseq,
|
|
||||||
any.microlens ==0.4.13.1,
|
|
||||||
any.microlens-mtl ==0.2.0.3,
|
|
||||||
any.microlens-th ==0.4.3.15,
|
|
||||||
any.mime-types ==0.1.2.0,
|
|
||||||
any.mmorph ==1.2.0,
|
|
||||||
any.monad-control ==1.0.3.1,
|
|
||||||
any.monad-logger ==0.3.40,
|
|
||||||
monad-logger +template_haskell,
|
|
||||||
any.monad-loops ==0.4.3,
|
|
||||||
monad-loops +base4,
|
|
||||||
any.mono-traversable ==1.0.21.0,
|
|
||||||
any.monomer ==1.6.0.1,
|
|
||||||
monomer -examples,
|
|
||||||
any.mtl ==2.3.1,
|
|
||||||
any.murmur3 ==1.0.5,
|
|
||||||
any.nanovg ==0.8.1.0,
|
|
||||||
nanovg -examples -gl2 -gles3 -stb_truetype,
|
|
||||||
any.network ==3.2.7.0,
|
|
||||||
network -devel,
|
|
||||||
any.network-byte-order ==0.1.7,
|
|
||||||
any.network-control ==0.1.3,
|
|
||||||
any.network-info ==0.2.1,
|
|
||||||
any.network-uri ==2.6.4.2,
|
|
||||||
any.old-locale ==1.0.0.7,
|
|
||||||
any.old-time ==1.1.0.4,
|
|
||||||
any.optparse-applicative ==0.18.1.0,
|
|
||||||
optparse-applicative +process,
|
|
||||||
any.os-string ==2.0.7,
|
|
||||||
any.parallel ==3.2.2.0,
|
|
||||||
any.parsec ==3.1.16.1,
|
|
||||||
any.parser-combinators ==1.3.0,
|
|
||||||
parser-combinators -dev,
|
|
||||||
any.path-pieces ==0.2.1,
|
|
||||||
any.pem ==0.2.4,
|
|
||||||
any.persistent ==2.14.6.3,
|
|
||||||
any.persistent-sqlite ==2.13.3.0,
|
|
||||||
persistent-sqlite -build-sanity-exe +full-text-search +have-usleep +json1 -systemlib +uri-filenames -use-pkgconfig -use-stat3 +use-stat4,
|
|
||||||
any.persistent-template ==2.12.0.0,
|
|
||||||
any.pretty ==1.1.3.6,
|
|
||||||
any.prettyprinter ==1.7.1,
|
|
||||||
prettyprinter -buildreadme +text,
|
|
||||||
any.prettyprinter-ansi-terminal ==1.1.3,
|
|
||||||
any.primitive ==0.9.0.0,
|
|
||||||
any.process ==1.6.19.0,
|
|
||||||
any.profunctors ==5.6.2,
|
|
||||||
any.psqueues ==0.2.8.0,
|
|
||||||
any.pureMD5 ==2.1.4,
|
|
||||||
pureMD5 -test,
|
|
||||||
any.qrcode-core ==0.9.10,
|
|
||||||
any.qrcode-juicypixels ==0.8.6,
|
|
||||||
any.quickcheck-io ==0.2.0,
|
|
||||||
any.quickcheck-transformer ==0.3.1.2,
|
|
||||||
any.random ==1.2.1.2,
|
|
||||||
any.recv ==0.1.0,
|
|
||||||
any.reflection ==2.1.9,
|
|
||||||
reflection -slow +template-haskell,
|
|
||||||
any.regex-base ==0.94.0.2,
|
|
||||||
any.regex-compat ==0.95.2.1,
|
|
||||||
any.regex-posix ==0.96.0.1,
|
|
||||||
regex-posix -_regex-posix-clib,
|
|
||||||
any.resource-pool ==0.4.0.0,
|
|
||||||
any.resourcet ==1.3.0,
|
|
||||||
any.rts ==1.0.2,
|
|
||||||
any.safe ==0.3.21,
|
|
||||||
any.safe-exceptions ==0.1.7.4,
|
|
||||||
any.scientific ==0.3.8.0,
|
|
||||||
scientific -integer-simple,
|
|
||||||
any.sdl2 ==2.5.5.0,
|
|
||||||
sdl2 -examples -no-linear -opengl-example +pkgconfig +recent-ish,
|
|
||||||
any.secp256k1-haskell ==1.4.2,
|
|
||||||
any.semialign ==1.3.1,
|
|
||||||
semialign +semigroupoids,
|
|
||||||
any.semigroupoids ==6.0.1,
|
|
||||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
|
||||||
any.semigroups ==0.20,
|
|
||||||
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
|
||||||
any.serialise ==0.2.6.1,
|
|
||||||
serialise +newtime15,
|
|
||||||
any.servant ==0.20.2,
|
|
||||||
any.servant-server ==0.20.2,
|
|
||||||
any.silently ==1.2.5.4,
|
|
||||||
any.simple-sendfile ==0.2.32,
|
|
||||||
simple-sendfile +allow-bsd -fallback,
|
|
||||||
any.singleton-bool ==0.1.8,
|
|
||||||
any.socks ==0.6.1,
|
|
||||||
any.some ==1.0.6,
|
|
||||||
some +newtype-unsafe,
|
|
||||||
any.sop-core ==0.5.0.2,
|
|
||||||
any.sort ==1.0.0.0,
|
|
||||||
any.split ==0.2.5,
|
|
||||||
any.splitmix ==0.1.0.5,
|
|
||||||
splitmix -optimised-mixer,
|
|
||||||
any.stm ==2.5.1.0,
|
|
||||||
any.stm-chans ==3.0.0.9,
|
|
||||||
any.streaming-commons ==0.2.2.6,
|
|
||||||
streaming-commons -use-bytestring-builder,
|
|
||||||
any.strict ==0.5.1,
|
|
||||||
any.string-conversions ==0.4.0.1,
|
|
||||||
any.system-cxx-std-lib ==1.0,
|
|
||||||
any.tagged ==0.8.9,
|
|
||||||
tagged +deepseq +transformers,
|
|
||||||
any.tasty ==1.5.2,
|
|
||||||
tasty +unix,
|
|
||||||
any.template-haskell ==2.20.0.0,
|
|
||||||
any.terminal-size ==0.3.4,
|
|
||||||
any.terminfo ==0.4.1.6,
|
|
||||||
any.text ==2.0.2,
|
|
||||||
any.text-iso8601 ==0.1.1,
|
|
||||||
any.text-short ==0.1.6,
|
|
||||||
text-short -asserts,
|
|
||||||
any.text-show ==3.11,
|
|
||||||
text-show +integer-gmp,
|
|
||||||
any.text-zipper ==0.13,
|
|
||||||
any.tf-random ==0.5,
|
|
||||||
any.th-abstraction ==0.7.1.0,
|
|
||||||
any.th-compat ==0.1.6,
|
|
||||||
any.th-lift ==0.8.6,
|
|
||||||
any.th-lift-instances ==0.1.20,
|
|
||||||
any.these ==1.2.1,
|
|
||||||
any.time ==1.12.2,
|
|
||||||
any.time-compat ==1.9.7,
|
|
||||||
any.time-locale-compat ==0.1.1.5,
|
|
||||||
time-locale-compat -old-locale,
|
|
||||||
any.time-manager ==0.2.1,
|
|
||||||
any.tls ==2.1.5,
|
|
||||||
tls -devel,
|
|
||||||
any.transformers ==0.6.1.0,
|
|
||||||
any.transformers-base ==0.4.6,
|
|
||||||
transformers-base +orphaninstances,
|
|
||||||
any.transformers-compat ==0.7.2,
|
|
||||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
|
||||||
any.typed-process ==0.2.12.0,
|
|
||||||
any.unix ==2.8.4.0,
|
|
||||||
any.unix-compat ==0.7.3,
|
|
||||||
any.unix-time ==0.4.16,
|
|
||||||
any.unliftio ==0.2.25.0,
|
|
||||||
any.unliftio-core ==0.2.1.0,
|
|
||||||
any.unordered-containers ==0.2.20,
|
|
||||||
unordered-containers -debug,
|
|
||||||
any.utf8-string ==1.0.2,
|
|
||||||
any.uuid ==1.3.16,
|
|
||||||
any.uuid-types ==1.0.6,
|
|
||||||
any.vault ==0.3.1.5,
|
|
||||||
vault +useghc,
|
|
||||||
any.vector ==0.13.2.0,
|
|
||||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
|
||||||
any.vector-algorithms ==0.9.0.3,
|
|
||||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
|
||||||
any.vector-stream ==0.1.0.1,
|
|
||||||
any.void ==0.7.3,
|
|
||||||
void -safe,
|
|
||||||
any.vty ==6.2,
|
|
||||||
any.vty-crossplatform ==0.4.0.0,
|
|
||||||
vty-crossplatform -demos,
|
|
||||||
any.vty-unix ==0.2.0.0,
|
|
||||||
any.wai ==3.2.4,
|
|
||||||
any.wai-app-static ==3.1.9,
|
|
||||||
wai-app-static +crypton -print,
|
|
||||||
any.wai-extra ==3.1.17,
|
|
||||||
wai-extra -build-example,
|
|
||||||
any.wai-logger ==2.5.0,
|
|
||||||
any.warp ==3.4.7,
|
|
||||||
warp +allow-sendfilefd -network-bytestring -warp-debug +x509,
|
|
||||||
any.wide-word ==0.1.6.0,
|
|
||||||
any.witherable ==0.5,
|
|
||||||
any.word-wrap ==0.5,
|
|
||||||
any.word8 ==0.1.3,
|
|
||||||
any.wreq ==0.5.4.3,
|
|
||||||
wreq -aws -developer +doctest -httpbin,
|
|
||||||
any.zlib ==0.7.1.0,
|
|
||||||
zlib -bundled-c-zlib +non-blocking-ffi +pkg-config
|
|
||||||
index-state: hackage.haskell.org 2024-12-14T09:52:48Z
|
|
17
configure
vendored
17
configure
vendored
|
@ -1,17 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
echo "Configuring Zenith...."
|
|
||||||
if grep -q "local/share/zcash-haskell" "$HOME/.bashrc"; then
|
echo "export PKG_CONFIG_PATH=$HOME/.local/share/zcash-haskell:\$PKG_CONFIG_PATH" | tee -a ~/.bashrc
|
||||||
echo "... Paths already exist"
|
echo "export LD_LIBRARY_PATH=$HOME/.local/share/zcash-haskell:\$LD_LIBRARY_PATH" | tee -a ~/.bashrc
|
||||||
else
|
|
||||||
# Set Paths
|
|
||||||
echo "... Adding new zenith paths to local configuration"
|
|
||||||
echo "export PKG_CONFIG_PATH=$HOME/.local/share/zcash-haskell:\$PKG_CONFIG_PATH" | tee -a ~/.bashrc
|
|
||||||
echo "export LD_LIBRARY_PATH=$HOME/.local/share/zcash-haskell:\$LD_LIBRARY_PATH" | tee -a ~/.bashrc
|
|
||||||
fi
|
|
||||||
echo "... Reloading paths"
|
|
||||||
source ~/.bashrc
|
source ~/.bashrc
|
||||||
echo "... building zcash-haskell"
|
|
||||||
cd zcash-haskell && cabal build
|
cd zcash-haskell && cabal build
|
||||||
echo
|
|
||||||
echo "Done"
|
|
||||||
echo
|
|
||||||
|
|
5
install
5
install
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo "Deploying Zenith executable..."
|
|
||||||
ln -s ${PWD}/dist-newstyle/build/x86_64-linux/ghc-9.6.5/zenith-0.6.0.0/build/zenith/zenith ~/.local/bin/zenith
|
|
||||||
echo "Done."
|
|
BIN
sapling-output.params
Normal file
BIN
sapling-output.params
Normal file
Binary file not shown.
BIN
sapling-spend.params
Normal file
BIN
sapling-spend.params
Normal file
Binary file not shown.
2138
src/Zenith/CLI.hs
2138
src/Zenith/CLI.hs
File diff suppressed because it is too large
Load diff
1972
src/Zenith/Core.hs
1972
src/Zenith/Core.hs
File diff suppressed because it is too large
Load diff
2166
src/Zenith/DB.hs
2166
src/Zenith/DB.hs
File diff suppressed because it is too large
Load diff
2976
src/Zenith/GUI.hs
2976
src/Zenith/GUI.hs
File diff suppressed because it is too large
Load diff
|
@ -1,343 +0,0 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
module Zenith.GUI.Theme
|
|
||||||
( zenithTheme
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Data.Default
|
|
||||||
import Lens.Micro ((&), (+~), (.~), (?~), (^.), at, set)
|
|
||||||
import Monomer
|
|
||||||
import Monomer.Core.Themes.BaseTheme
|
|
||||||
import Monomer.Core.Themes.SampleThemes
|
|
||||||
import Monomer.Graphics (rgbHex, transparent)
|
|
||||||
import Monomer.Graphics.ColorTable
|
|
||||||
import qualified Monomer.Lens as L
|
|
||||||
|
|
||||||
baseTextStyle :: TextStyle
|
|
||||||
baseTextStyle = def & L.fontSize ?~ FontSize 10 & L.fontColor ?~ black
|
|
||||||
|
|
||||||
hiliteTextStyle :: TextStyle
|
|
||||||
hiliteTextStyle = def & L.fontSize ?~ FontSize 10 & L.fontColor ?~ white
|
|
||||||
|
|
||||||
zenithTheme :: Theme
|
|
||||||
zenithTheme =
|
|
||||||
baseTheme zgoThemeColors & L.basic . L.labelStyle . L.text ?~ baseTextStyle &
|
|
||||||
L.hover .
|
|
||||||
L.tooltipStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.hover .
|
|
||||||
L.labelStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.basic .
|
|
||||||
L.dialogTitleStyle . L.text ?~
|
|
||||||
(baseTextStyle & L.fontSize ?~ FontSize 12 & L.font ?~ "Bold") &
|
|
||||||
L.hover .
|
|
||||||
L.dialogTitleStyle . L.text ?~
|
|
||||||
(baseTextStyle & L.fontSize ?~ FontSize 12 & L.font ?~ "Bold") &
|
|
||||||
L.basic .
|
|
||||||
L.btnStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.hover .
|
|
||||||
L.btnStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focus .
|
|
||||||
L.btnStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focusHover .
|
|
||||||
L.btnStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.active .
|
|
||||||
L.btnStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.disabled .
|
|
||||||
L.btnStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.basic .
|
|
||||||
L.btnMainStyle . L.text ?~
|
|
||||||
hiliteTextStyle &
|
|
||||||
L.hover .
|
|
||||||
L.btnMainStyle . L.text ?~
|
|
||||||
hiliteTextStyle &
|
|
||||||
L.focus .
|
|
||||||
L.btnMainStyle . L.text ?~
|
|
||||||
hiliteTextStyle &
|
|
||||||
L.focusHover .
|
|
||||||
L.btnMainStyle . L.text ?~
|
|
||||||
hiliteTextStyle &
|
|
||||||
L.active .
|
|
||||||
L.btnMainStyle . L.text ?~
|
|
||||||
hiliteTextStyle &
|
|
||||||
L.disabled .
|
|
||||||
L.btnMainStyle . L.text ?~
|
|
||||||
hiliteTextStyle &
|
|
||||||
L.disabled .
|
|
||||||
L.btnMainStyle . L.bgColor ?~
|
|
||||||
gray07c &
|
|
||||||
L.basic .
|
|
||||||
L.textFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.hover .
|
|
||||||
L.textFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focus .
|
|
||||||
L.textFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.active .
|
|
||||||
L.textFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focusHover .
|
|
||||||
L.textFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.basic .
|
|
||||||
L.numericFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.hover .
|
|
||||||
L.numericFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focus .
|
|
||||||
L.numericFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.active .
|
|
||||||
L.numericFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focusHover .
|
|
||||||
L.numericFieldStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.basic .
|
|
||||||
L.textAreaStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.hover .
|
|
||||||
L.textAreaStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focus .
|
|
||||||
L.textAreaStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.active .
|
|
||||||
L.textAreaStyle . L.text ?~
|
|
||||||
baseTextStyle &
|
|
||||||
L.focusHover .
|
|
||||||
L.textAreaStyle . L.text ?~
|
|
||||||
baseTextStyle
|
|
||||||
|
|
||||||
zenithThemeColors :: BaseThemeColors
|
|
||||||
zenithThemeColors =
|
|
||||||
BaseThemeColors
|
|
||||||
{ clearColor = gray01
|
|
||||||
, sectionColor = gray01
|
|
||||||
, btnFocusBorder = blue09
|
|
||||||
, btnBgBasic = gray07b
|
|
||||||
, btnBgHover = gray08
|
|
||||||
, btnBgFocus = gray07c
|
|
||||||
, btnBgActive = gray06
|
|
||||||
, btnBgDisabled = gray05
|
|
||||||
, btnText = gray02
|
|
||||||
, btnTextDisabled = gray01
|
|
||||||
, btnMainFocusBorder = blue08
|
|
||||||
, btnMainBgBasic = btnColor
|
|
||||||
, btnMainBgHover = btnHiLite
|
|
||||||
, btnMainBgFocus = btnColor
|
|
||||||
, btnMainBgActive = btnHiLite
|
|
||||||
, btnMainBgDisabled = blue04
|
|
||||||
, btnMainText = white
|
|
||||||
, btnMainTextDisabled = gray08
|
|
||||||
, dialogBg = gray01
|
|
||||||
, dialogBorder = gray01
|
|
||||||
, dialogText = white
|
|
||||||
, dialogTitleText = white
|
|
||||||
, emptyOverlay = gray05 & L.a .~ 0.8
|
|
||||||
, shadow = gray00 & L.a .~ 0.33
|
|
||||||
, externalLinkBasic = blue07
|
|
||||||
, externalLinkHover = blue08
|
|
||||||
, externalLinkFocus = blue07
|
|
||||||
, externalLinkActive = blue06
|
|
||||||
, externalLinkDisabled = gray06
|
|
||||||
, iconBg = gray08
|
|
||||||
, iconFg = gray01
|
|
||||||
, inputIconFg = black
|
|
||||||
, inputBorder = gray02
|
|
||||||
, inputFocusBorder = blue08
|
|
||||||
, inputBgBasic = gray04
|
|
||||||
, inputBgHover = gray06
|
|
||||||
, inputBgFocus = gray05
|
|
||||||
, inputBgActive = gray03
|
|
||||||
, inputBgDisabled = gray07
|
|
||||||
, inputFgBasic = gray06
|
|
||||||
, inputFgHover = blue08
|
|
||||||
, inputFgFocus = blue08
|
|
||||||
, inputFgActive = blue07
|
|
||||||
, inputFgDisabled = gray07
|
|
||||||
, inputSndBasic = gray05
|
|
||||||
, inputSndHover = gray06
|
|
||||||
, inputSndFocus = gray05
|
|
||||||
, inputSndActive = gray05
|
|
||||||
, inputSndDisabled = gray03
|
|
||||||
, inputHlBasic = gray07
|
|
||||||
, inputHlHover = blue08
|
|
||||||
, inputHlFocus = blue08
|
|
||||||
, inputHlActive = blue08
|
|
||||||
, inputHlDisabled = gray08
|
|
||||||
, inputSelBasic = gray06
|
|
||||||
, inputSelFocus = blue06
|
|
||||||
, inputText = white
|
|
||||||
, inputTextDisabled = gray02
|
|
||||||
, labelText = white
|
|
||||||
, scrollBarBasic = gray01 & L.a .~ 0.2
|
|
||||||
, scrollThumbBasic = gray07 & L.a .~ 0.6
|
|
||||||
, scrollBarHover = gray01 & L.a .~ 0.4
|
|
||||||
, scrollThumbHover = gray07 & L.a .~ 0.8
|
|
||||||
, slMainBg = gray00
|
|
||||||
, slNormalBgBasic = transparent
|
|
||||||
, slNormalBgHover = gray05
|
|
||||||
, slNormalText = white
|
|
||||||
, slNormalFocusBorder = blue08
|
|
||||||
, slSelectedBgBasic = gray04
|
|
||||||
, slSelectedBgHover = gray05
|
|
||||||
, slSelectedText = white
|
|
||||||
, slSelectedFocusBorder = blue08
|
|
||||||
, tooltipBorder = gray05
|
|
||||||
, tooltipBg = rgbHex "#1D212B"
|
|
||||||
, tooltipText = white
|
|
||||||
}
|
|
||||||
|
|
||||||
zgoThemeColors =
|
|
||||||
BaseThemeColors
|
|
||||||
{ clearColor = gray10 -- gray12,
|
|
||||||
, sectionColor = gray09 -- gray11,
|
|
||||||
, btnFocusBorder = blue08
|
|
||||||
, btnBgBasic = gray07
|
|
||||||
, btnBgHover = gray07c
|
|
||||||
, btnBgFocus = gray07b
|
|
||||||
, btnBgActive = gray06
|
|
||||||
, btnBgDisabled = gray05
|
|
||||||
, btnText = gray02
|
|
||||||
, btnTextDisabled = gray02
|
|
||||||
, btnMainFocusBorder = blue09
|
|
||||||
, btnMainBgBasic = btnColor
|
|
||||||
, btnMainBgHover = btnHiLite
|
|
||||||
, btnMainBgFocus = btnColor
|
|
||||||
, btnMainBgActive = btnHiLite
|
|
||||||
, btnMainBgDisabled = blue04
|
|
||||||
, btnMainText = white
|
|
||||||
, btnMainTextDisabled = white
|
|
||||||
, dialogBg = white
|
|
||||||
, dialogBorder = white
|
|
||||||
, dialogText = black
|
|
||||||
, dialogTitleText = black
|
|
||||||
, emptyOverlay = gray07 & L.a .~ 0.8
|
|
||||||
, shadow = gray00 & L.a .~ 0.2
|
|
||||||
, externalLinkBasic = blue07
|
|
||||||
, externalLinkHover = blue08
|
|
||||||
, externalLinkFocus = blue07
|
|
||||||
, externalLinkActive = blue06
|
|
||||||
, externalLinkDisabled = gray06
|
|
||||||
, iconBg = gray07
|
|
||||||
, iconFg = gray01
|
|
||||||
, inputIconFg = black
|
|
||||||
, inputBorder = gray06
|
|
||||||
, inputFocusBorder = blue07
|
|
||||||
, inputBgBasic = gray10
|
|
||||||
, inputBgHover = white
|
|
||||||
, inputBgFocus = white
|
|
||||||
, inputBgActive = gray09
|
|
||||||
, inputBgDisabled = gray05
|
|
||||||
, inputFgBasic = gray05
|
|
||||||
, inputFgHover = blue07
|
|
||||||
, inputFgFocus = blue07
|
|
||||||
, inputFgActive = blue06
|
|
||||||
, inputFgDisabled = gray04
|
|
||||||
, inputSndBasic = gray04
|
|
||||||
, inputSndHover = gray05
|
|
||||||
, inputSndFocus = gray05
|
|
||||||
, inputSndActive = gray04
|
|
||||||
, inputSndDisabled = gray03
|
|
||||||
, inputHlBasic = gray06
|
|
||||||
, inputHlHover = blue07
|
|
||||||
, inputHlFocus = blue07
|
|
||||||
, inputHlActive = blue06
|
|
||||||
, inputHlDisabled = gray05
|
|
||||||
, inputSelBasic = gray07
|
|
||||||
, inputSelFocus = blue08
|
|
||||||
, inputText = black
|
|
||||||
, inputTextDisabled = gray02
|
|
||||||
, labelText = black
|
|
||||||
, scrollBarBasic = gray03 & L.a .~ 0.2
|
|
||||||
, scrollThumbBasic = gray01 & L.a .~ 0.2
|
|
||||||
, scrollBarHover = gray07 & L.a .~ 0.8
|
|
||||||
, scrollThumbHover = gray05 & L.a .~ 0.8
|
|
||||||
, slMainBg = white
|
|
||||||
, slNormalBgBasic = transparent
|
|
||||||
, slNormalBgHover = gray09
|
|
||||||
, slNormalText = black
|
|
||||||
, slNormalFocusBorder = blue07
|
|
||||||
, slSelectedBgBasic = gray08
|
|
||||||
, slSelectedBgHover = gray09
|
|
||||||
, slSelectedText = black
|
|
||||||
, slSelectedFocusBorder = blue07
|
|
||||||
, tooltipBorder = gray08
|
|
||||||
, tooltipBg = gray07
|
|
||||||
, tooltipText = black
|
|
||||||
}
|
|
||||||
|
|
||||||
--black = rgbHex "#000000"
|
|
||||||
{-white = rgbHex "#FFFFFF"-}
|
|
||||||
btnColor = rgbHex "#ff5722" --rgbHex "#1818B2"
|
|
||||||
|
|
||||||
btnHiLite = rgbHex "#207DE8"
|
|
||||||
|
|
||||||
blue01 = rgbHex "#002159"
|
|
||||||
|
|
||||||
blue02 = rgbHex "#01337D"
|
|
||||||
|
|
||||||
blue03 = rgbHex "#03449E"
|
|
||||||
|
|
||||||
blue04 = rgbHex "#0552B5"
|
|
||||||
|
|
||||||
blue05 = rgbHex "#0967D2"
|
|
||||||
|
|
||||||
blue05b = rgbHex "#0F6BD7"
|
|
||||||
|
|
||||||
blue05c = rgbHex "#1673DE"
|
|
||||||
|
|
||||||
blue06 = rgbHex "#2186EB"
|
|
||||||
|
|
||||||
blue06b = rgbHex "#2489EE"
|
|
||||||
|
|
||||||
blue06c = rgbHex "#2B8FF6"
|
|
||||||
|
|
||||||
blue07 = rgbHex "#47A3F3"
|
|
||||||
|
|
||||||
blue07b = rgbHex "#50A6F6"
|
|
||||||
|
|
||||||
blue07c = rgbHex "#57ACFC"
|
|
||||||
|
|
||||||
blue08 = rgbHex "#7CC4FA"
|
|
||||||
|
|
||||||
blue09 = rgbHex "#BAE3FF"
|
|
||||||
|
|
||||||
blue10 = rgbHex "#E6F6FF"
|
|
||||||
|
|
||||||
gray00 = rgbHex "#111111"
|
|
||||||
|
|
||||||
gray01 = rgbHex "#2E2E2E"
|
|
||||||
|
|
||||||
gray02 = rgbHex "#393939"
|
|
||||||
|
|
||||||
gray03 = rgbHex "#515151"
|
|
||||||
|
|
||||||
gray04 = rgbHex "#626262"
|
|
||||||
|
|
||||||
gray05 = rgbHex "#7E7E7E"
|
|
||||||
|
|
||||||
gray06 = rgbHex "#9E9E9E"
|
|
||||||
|
|
||||||
gray07 = rgbHex "#B1B1B1"
|
|
||||||
|
|
||||||
gray07b = rgbHex "#B4B4B4"
|
|
||||||
|
|
||||||
gray07c = rgbHex "#BBBBBB"
|
|
||||||
|
|
||||||
gray08 = rgbHex "#CFCFCF"
|
|
||||||
|
|
||||||
gray09 = rgbHex "#E1E1E1"
|
|
||||||
|
|
||||||
gray10 = rgbHex "#F7F7F7"
|
|
1267
src/Zenith/RPC.hs
1267
src/Zenith/RPC.hs
File diff suppressed because it is too large
Load diff
|
@ -2,28 +2,29 @@
|
||||||
|
|
||||||
module Zenith.Scanner where
|
module Zenith.Scanner where
|
||||||
|
|
||||||
import Control.Concurrent.Async (concurrently_, withAsync)
|
|
||||||
import Control.Exception (throwIO, try)
|
import Control.Exception (throwIO, try)
|
||||||
import Control.Monad (when)
|
import qualified Control.Monad.Catch as CM (try)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Control.Monad.Logger
|
import Control.Monad.Logger
|
||||||
( NoLoggingT
|
( LoggingT
|
||||||
|
, NoLoggingT
|
||||||
, logErrorN
|
, logErrorN
|
||||||
, logInfoN
|
, logInfoN
|
||||||
, runNoLoggingT
|
, runNoLoggingT
|
||||||
, runStderrLoggingT
|
|
||||||
)
|
)
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.HexString
|
import Data.HexString
|
||||||
|
import Data.Maybe
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Time (getCurrentTime)
|
import Data.Time (getCurrentTime)
|
||||||
import Database.Persist.Sqlite
|
import Database.Persist.Sqlite
|
||||||
|
import GHC.Utils.Monad (concatMapM)
|
||||||
|
import Lens.Micro ((&), (.~), (^.), set)
|
||||||
import System.Console.AsciiProgress
|
import System.Console.AsciiProgress
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( BlockResponse(..)
|
( BlockResponse(..)
|
||||||
, RawZebraTx(..)
|
, RawZebraTx(..)
|
||||||
, Transaction(..)
|
, Transaction(..)
|
||||||
, ZcashNet(..)
|
|
||||||
, ZebraGetBlockChainInfo(..)
|
, ZebraGetBlockChainInfo(..)
|
||||||
, ZebraTxResponse(..)
|
, ZebraTxResponse(..)
|
||||||
, fromRawOBundle
|
, fromRawOBundle
|
||||||
|
@ -31,86 +32,53 @@ import ZcashHaskell.Types
|
||||||
, fromRawTBundle
|
, fromRawTBundle
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Utils (getBlockTime, makeZebraCall, readZebraTransaction)
|
import ZcashHaskell.Utils (getBlockTime, makeZebraCall, readZebraTransaction)
|
||||||
import Zenith.Core (checkBlockChain, syncWallet, updateCommitmentTrees)
|
import Zenith.Core (checkBlockChain)
|
||||||
import Zenith.DB
|
import Zenith.DB (getMaxBlock, initDb, saveTransaction)
|
||||||
( ZcashBlock(..)
|
|
||||||
, ZcashBlockId
|
|
||||||
, clearWalletData
|
|
||||||
, clearWalletTransactions
|
|
||||||
, completeSync
|
|
||||||
, getBlock
|
|
||||||
, getMaxBlock
|
|
||||||
, getMinBirthdayHeight
|
|
||||||
, getUnconfirmedBlocks
|
|
||||||
, getWallets
|
|
||||||
, initDb
|
|
||||||
, initPool
|
|
||||||
, saveBlock
|
|
||||||
, saveConfs
|
|
||||||
, saveTransaction
|
|
||||||
, startSync
|
|
||||||
, updateWalletSync
|
|
||||||
, upgradeAccountTable
|
|
||||||
, upgradeQrTable
|
|
||||||
)
|
|
||||||
import Zenith.Types
|
|
||||||
( Config(..)
|
|
||||||
, HexStringDB(..)
|
|
||||||
, ZcashNetDB(..)
|
|
||||||
, ZenithStatus(..)
|
|
||||||
)
|
|
||||||
import Zenith.Utils (jsonNumber)
|
import Zenith.Utils (jsonNumber)
|
||||||
|
|
||||||
-- | Function to scan the Zcash blockchain through the Zebra node and populate the Zenith database
|
-- | Function to scan the Zcash blockchain through the Zebra node and populate the Zenith database
|
||||||
rescanZebra ::
|
scanZebra ::
|
||||||
T.Text -- ^ Host
|
Int -- ^ Starting block
|
||||||
|
-> T.Text -- ^ Host
|
||||||
-> Int -- ^ Port
|
-> Int -- ^ Port
|
||||||
-> T.Text -- ^ Path to database file
|
-> T.Text -- ^ Path to database file
|
||||||
-> IO ()
|
-> NoLoggingT IO ()
|
||||||
rescanZebra host port dbFilePath = do
|
scanZebra b host port dbFilePath = do
|
||||||
|
_ <- liftIO $ initDb dbFilePath
|
||||||
|
startTime <- liftIO getCurrentTime
|
||||||
|
logInfoN $ "Started sync: " <> T.pack (show startTime)
|
||||||
bc <-
|
bc <-
|
||||||
try $ checkBlockChain host port :: IO
|
liftIO $ try $ checkBlockChain host port :: NoLoggingT
|
||||||
|
IO
|
||||||
(Either IOError ZebraGetBlockChainInfo)
|
(Either IOError ZebraGetBlockChainInfo)
|
||||||
case bc of
|
case bc of
|
||||||
Left e -> print e
|
Left e -> logErrorN $ T.pack (show e)
|
||||||
Right bStatus -> do
|
Right bStatus -> do
|
||||||
let znet = ZcashNetDB $ zgb_net bStatus
|
let dbInfo =
|
||||||
pool1 <- runNoLoggingT $ initPool dbFilePath
|
mkSqliteConnectionInfo dbFilePath & extraPragmas .~
|
||||||
{-pool2 <- runNoLoggingT $ initPool dbFilePath-}
|
["read_uncommited = true"]
|
||||||
{-pool3 <- runNoLoggingT $ initPool dbFilePath-}
|
pool <- createSqlitePoolFromInfo dbInfo 5
|
||||||
_ <- runNoLoggingT $ initDb dbFilePath
|
dbBlock <- getMaxBlock pool
|
||||||
upgradeQrTable pool1
|
|
||||||
clearWalletTransactions pool1
|
|
||||||
clearWalletData pool1
|
|
||||||
_ <- startSync pool1
|
|
||||||
dbBlock <- getMaxBlock pool1 znet
|
|
||||||
b <- liftIO $ getMinBirthdayHeight pool1 znet
|
|
||||||
let sb = max dbBlock b
|
let sb = max dbBlock b
|
||||||
if sb > zgb_blocks bStatus || sb < 1
|
if sb > zgb_blocks bStatus || sb < 1
|
||||||
then liftIO $ throwIO $ userError "Invalid starting block for scan"
|
then liftIO $ throwIO $ userError "Invalid starting block for scan"
|
||||||
else do
|
else do
|
||||||
print $
|
liftIO $
|
||||||
"Scanning from " ++ show sb ++ " to " ++ show (zgb_blocks bStatus)
|
print $
|
||||||
let bList = [sb .. (zgb_blocks bStatus)]
|
"Scanning from " ++
|
||||||
{-
|
show (sb + 1) ++ " to " ++ show (zgb_blocks bStatus)
|
||||||
let batch = length bList `div` 3
|
let bList = [(sb + 1) .. (zgb_blocks bStatus)]
|
||||||
let bl1 = take batch bList
|
displayConsoleRegions $ do
|
||||||
let bl2 = take batch $ drop batch bList
|
pg <-
|
||||||
let bl3 = drop (2 * batch) bList
|
liftIO $
|
||||||
-}
|
newProgressBar def {pgTotal = fromIntegral $ length bList}
|
||||||
_ <-
|
txList <-
|
||||||
displayConsoleRegions $ do
|
CM.try $ mapM_ (processBlock host port pool pg) bList :: NoLoggingT
|
||||||
pg1 <- newProgressBar def {pgTotal = fromIntegral $ length bList}
|
IO
|
||||||
{-pg2 <- newProgressBar def {pgTotal = fromIntegral $ length bl2}-}
|
(Either IOError ())
|
||||||
{-pg3 <- newProgressBar def {pgTotal = fromIntegral $ length bl3}-}
|
case txList of
|
||||||
mapM_ (processBlock host port pool1 pg1 znet) bList
|
Left e1 -> logErrorN $ T.pack (show e1)
|
||||||
{-`concurrently_`-}
|
Right txList' -> logInfoN "Finished scan"
|
||||||
{-mapM_ (processBlock host port pool2 pg2 znet) bl2 `concurrently_`-}
|
|
||||||
{-mapM_ (processBlock host port pool3 pg3 znet) bl3-}
|
|
||||||
print "Please wait..."
|
|
||||||
_ <- completeSync pool1 Successful
|
|
||||||
_ <- runNoLoggingT $ updateCommitmentTrees pool1 host port znet
|
|
||||||
print "Rescan complete"
|
|
||||||
|
|
||||||
-- | Function to process a raw block and extract the transaction information
|
-- | Function to process a raw block and extract the transaction information
|
||||||
processBlock ::
|
processBlock ::
|
||||||
|
@ -118,10 +86,9 @@ processBlock ::
|
||||||
-> Int -- ^ Port for `zebrad`
|
-> Int -- ^ Port for `zebrad`
|
||||||
-> ConnectionPool -- ^ DB file path
|
-> ConnectionPool -- ^ DB file path
|
||||||
-> ProgressBar -- ^ Progress bar
|
-> ProgressBar -- ^ Progress bar
|
||||||
-> ZcashNetDB -- ^ the network
|
|
||||||
-> Int -- ^ The block number to process
|
-> Int -- ^ The block number to process
|
||||||
-> IO ()
|
-> NoLoggingT IO ()
|
||||||
processBlock host port pool pg net b = do
|
processBlock host port pool pg b = do
|
||||||
r <-
|
r <-
|
||||||
liftIO $
|
liftIO $
|
||||||
makeZebraCall
|
makeZebraCall
|
||||||
|
@ -130,29 +97,39 @@ processBlock host port pool pg net b = do
|
||||||
"getblock"
|
"getblock"
|
||||||
[Data.Aeson.String $ T.pack $ show b, jsonNumber 1]
|
[Data.Aeson.String $ T.pack $ show b, jsonNumber 1]
|
||||||
case r of
|
case r of
|
||||||
Left e -> do
|
Left e -> liftIO $ throwIO $ userError e
|
||||||
_ <- completeSync pool Failed
|
|
||||||
liftIO $ throwIO $ userError e
|
|
||||||
Right blk -> do
|
Right blk -> do
|
||||||
bi <-
|
r2 <-
|
||||||
saveBlock pool $
|
liftIO $
|
||||||
ZcashBlock
|
makeZebraCall
|
||||||
(fromIntegral $ bl_height blk)
|
host
|
||||||
(HexStringDB $ bl_hash blk)
|
port
|
||||||
(fromIntegral $ bl_confirmations blk)
|
"getblock"
|
||||||
(fromIntegral $ bl_time blk)
|
[Data.Aeson.String $ T.pack $ show b, jsonNumber 0]
|
||||||
net
|
case r2 of
|
||||||
mapM_ (processTx host port bi pool) $ bl_txs blk
|
Left e2 -> liftIO $ throwIO $ userError e2
|
||||||
liftIO $ tick pg
|
Right hb -> do
|
||||||
|
let blockTime = getBlockTime hb
|
||||||
|
mapM_ (processTx host port blockTime pool) $
|
||||||
|
bl_txs $ addTime blk blockTime
|
||||||
|
liftIO $ tick pg
|
||||||
|
where
|
||||||
|
addTime :: BlockResponse -> Int -> BlockResponse
|
||||||
|
addTime bl t =
|
||||||
|
BlockResponse
|
||||||
|
(bl_confirmations bl)
|
||||||
|
(bl_height bl)
|
||||||
|
(fromIntegral t)
|
||||||
|
(bl_txs bl)
|
||||||
|
|
||||||
-- | Function to process a raw transaction
|
-- | Function to process a raw transaction
|
||||||
processTx ::
|
processTx ::
|
||||||
T.Text -- ^ Host name for `zebrad`
|
T.Text -- ^ Host name for `zebrad`
|
||||||
-> Int -- ^ Port for `zebrad`
|
-> Int -- ^ Port for `zebrad`
|
||||||
-> ZcashBlockId -- ^ Block ID
|
-> Int -- ^ Block time
|
||||||
-> ConnectionPool -- ^ DB file path
|
-> ConnectionPool -- ^ DB file path
|
||||||
-> HexString -- ^ transaction id
|
-> HexString -- ^ transaction id
|
||||||
-> IO ()
|
-> NoLoggingT IO ()
|
||||||
processTx host port bt pool t = do
|
processTx host port bt pool t = do
|
||||||
r <-
|
r <-
|
||||||
liftIO $
|
liftIO $
|
||||||
|
@ -162,15 +139,12 @@ processTx host port bt pool t = do
|
||||||
"getrawtransaction"
|
"getrawtransaction"
|
||||||
[Data.Aeson.String $ toText t, jsonNumber 1]
|
[Data.Aeson.String $ toText t, jsonNumber 1]
|
||||||
case r of
|
case r of
|
||||||
Left e -> do
|
Left e -> liftIO $ throwIO $ userError e
|
||||||
_ <- completeSync pool Failed
|
|
||||||
liftIO $ throwIO $ userError e
|
|
||||||
Right rawTx -> do
|
Right rawTx -> do
|
||||||
case readZebraTransaction (ztr_hex rawTx) of
|
case readZebraTransaction (ztr_hex rawTx) of
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
Just rzt -> do
|
Just rzt -> do
|
||||||
_ <-
|
_ <-
|
||||||
runNoLoggingT $
|
|
||||||
saveTransaction pool bt $
|
saveTransaction pool bt $
|
||||||
Transaction
|
Transaction
|
||||||
t
|
t
|
||||||
|
@ -181,83 +155,3 @@ processTx host port bt pool t = do
|
||||||
(fromRawSBundle $ zt_sBundle rzt)
|
(fromRawSBundle $ zt_sBundle rzt)
|
||||||
(fromRawOBundle $ zt_oBundle rzt)
|
(fromRawOBundle $ zt_oBundle rzt)
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
-- | Function to update unconfirmed transactions
|
|
||||||
updateConfs ::
|
|
||||||
T.Text -- ^ Host name for `zebrad`
|
|
||||||
-> Int -- ^ Port for `zebrad`
|
|
||||||
-> ConnectionPool
|
|
||||||
-> IO ()
|
|
||||||
updateConfs host port pool = do
|
|
||||||
targetBlocks <- getUnconfirmedBlocks pool
|
|
||||||
mapM_ updateTx targetBlocks
|
|
||||||
where
|
|
||||||
updateTx :: Int -> IO ()
|
|
||||||
updateTx b = do
|
|
||||||
r <-
|
|
||||||
makeZebraCall
|
|
||||||
host
|
|
||||||
port
|
|
||||||
"getblock"
|
|
||||||
[Data.Aeson.String $ T.pack $ show b, jsonNumber 1]
|
|
||||||
case r of
|
|
||||||
Left e -> throwIO $ userError e
|
|
||||||
Right blk -> do
|
|
||||||
saveConfs pool b $ fromInteger $ bl_confirmations blk
|
|
||||||
|
|
||||||
clearSync :: Config -> IO ()
|
|
||||||
clearSync config = do
|
|
||||||
let zHost = c_zebraHost config
|
|
||||||
let zPort = c_zebraPort config
|
|
||||||
let dbPath = c_dbPath config
|
|
||||||
pool <- runNoLoggingT $ initPool dbPath
|
|
||||||
bc <-
|
|
||||||
try $ checkBlockChain zHost zPort :: IO
|
|
||||||
(Either IOError ZebraGetBlockChainInfo)
|
|
||||||
case bc of
|
|
||||||
Left e1 -> throwIO e1
|
|
||||||
Right chainInfo -> do
|
|
||||||
x <- runNoLoggingT $ initDb dbPath
|
|
||||||
_ <- upgradeQrTable pool
|
|
||||||
_ <- runNoLoggingT $ upgradeAccountTable pool
|
|
||||||
case x of
|
|
||||||
Left e2 -> throwIO $ userError e2
|
|
||||||
Right x' -> do
|
|
||||||
when x' $ rescanZebra zHost zPort dbPath
|
|
||||||
_ <- clearWalletTransactions pool
|
|
||||||
w <- getWallets pool $ zgb_net chainInfo
|
|
||||||
liftIO $ mapM_ (updateWalletSync pool 0 . entityKey) w
|
|
||||||
w' <- liftIO $ getWallets pool $ zgb_net chainInfo
|
|
||||||
r <- runNoLoggingT $ mapM (syncWallet config) w'
|
|
||||||
liftIO $ print r
|
|
||||||
|
|
||||||
-- | Detect chain re-orgs
|
|
||||||
checkIntegrity ::
|
|
||||||
T.Text -- ^ Database path
|
|
||||||
-> T.Text -- ^ Zebra host
|
|
||||||
-> Int -- ^ Zebra port
|
|
||||||
-> ZcashNet -- ^ the network to scan
|
|
||||||
-> Int -- ^ The block to start the check
|
|
||||||
-> Int -- ^ depth
|
|
||||||
-> IO Int
|
|
||||||
checkIntegrity dbP zHost zPort znet b d =
|
|
||||||
if b < 1
|
|
||||||
then return 1
|
|
||||||
else do
|
|
||||||
r <-
|
|
||||||
makeZebraCall
|
|
||||||
zHost
|
|
||||||
zPort
|
|
||||||
"getblock"
|
|
||||||
[Data.Aeson.String $ T.pack $ show b, jsonNumber 1]
|
|
||||||
case r of
|
|
||||||
Left e -> throwIO $ userError e
|
|
||||||
Right blk -> do
|
|
||||||
pool <- runNoLoggingT $ initPool dbP
|
|
||||||
dbBlk <- getBlock pool b $ ZcashNetDB znet
|
|
||||||
case dbBlk of
|
|
||||||
Nothing -> return 1
|
|
||||||
Just dbBlk' ->
|
|
||||||
if bl_hash blk == getHex (zcashBlockHash $ entityVal dbBlk')
|
|
||||||
then return b
|
|
||||||
else checkIntegrity dbP zHost zPort znet (b - 5 * d) (d + 1)
|
|
||||||
|
|
|
@ -1,400 +0,0 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
|
||||||
{-# LANGUAGE DeriveAnyClass #-}
|
|
||||||
{-# LANGUAGE DerivingVia #-}
|
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
|
||||||
|
|
||||||
module Zenith.Tree where
|
|
||||||
|
|
||||||
import Codec.Borsh
|
|
||||||
import Control.Monad.Logger (NoLoggingT, logDebugN)
|
|
||||||
import Data.HexString
|
|
||||||
import Data.Int (Int32, Int64, Int8)
|
|
||||||
import Data.Maybe (fromJust, isNothing)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified GHC.Generics as GHC
|
|
||||||
import qualified Generics.SOP as SOP
|
|
||||||
import ZcashHaskell.Orchard (combineOrchardNodes, getOrchardNodeValue)
|
|
||||||
import ZcashHaskell.Sapling (combineSaplingNodes, getSaplingNodeValue)
|
|
||||||
import ZcashHaskell.Types (MerklePath(..), OrchardTree(..), SaplingTree(..))
|
|
||||||
|
|
||||||
type Level = Int8
|
|
||||||
|
|
||||||
maxLevel :: Level
|
|
||||||
maxLevel = 32
|
|
||||||
|
|
||||||
type Position = Int32
|
|
||||||
|
|
||||||
class Monoid v =>
|
|
||||||
Measured a v
|
|
||||||
where
|
|
||||||
measure :: a -> Position -> Int64 -> v
|
|
||||||
|
|
||||||
class Node v where
|
|
||||||
getLevel :: v -> Level
|
|
||||||
getHash :: v -> HexString
|
|
||||||
getPosition :: v -> Position
|
|
||||||
getIndex :: v -> Int64
|
|
||||||
isFull :: v -> Bool
|
|
||||||
isMarked :: v -> Bool
|
|
||||||
mkNode :: Level -> Position -> HexString -> v
|
|
||||||
|
|
||||||
type OrchardCommitment = HexString
|
|
||||||
|
|
||||||
instance Measured OrchardCommitment OrchardNode where
|
|
||||||
measure oc p i =
|
|
||||||
case getOrchardNodeValue (hexBytes oc) of
|
|
||||||
Nothing -> OrchardNode 0 (hexString "00") 0 True 0 False
|
|
||||||
Just val -> OrchardNode p val 0 True i False
|
|
||||||
|
|
||||||
type SaplingCommitment = HexString
|
|
||||||
|
|
||||||
instance Measured SaplingCommitment SaplingNode where
|
|
||||||
measure sc p i =
|
|
||||||
case getSaplingNodeValue (hexBytes sc) of
|
|
||||||
Nothing -> SaplingNode 0 (hexString "00") 0 True 0 False
|
|
||||||
Just val -> SaplingNode p val 0 True i False
|
|
||||||
|
|
||||||
data Tree v
|
|
||||||
= EmptyLeaf
|
|
||||||
| Leaf !v
|
|
||||||
| PrunedBranch !v
|
|
||||||
| Branch !v !(Tree v) !(Tree v)
|
|
||||||
| InvalidTree
|
|
||||||
deriving stock (Eq, GHC.Generic)
|
|
||||||
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsEnum (Tree v)
|
|
||||||
|
|
||||||
instance (Node v, Show v) => Show (Tree v) where
|
|
||||||
show EmptyLeaf = "()"
|
|
||||||
show (Leaf v) = "(" ++ show v ++ ")"
|
|
||||||
show (PrunedBranch v) = "{" ++ show v ++ "}"
|
|
||||||
show (Branch s x y) =
|
|
||||||
"<" ++ show (getHash s) ++ ">\n" ++ show x ++ "\n" ++ show y
|
|
||||||
show InvalidTree = "InvalidTree"
|
|
||||||
|
|
||||||
instance (Monoid v, Node v) => Semigroup (Tree v) where
|
|
||||||
(<>) InvalidTree _ = InvalidTree
|
|
||||||
(<>) _ InvalidTree = InvalidTree
|
|
||||||
(<>) EmptyLeaf EmptyLeaf = PrunedBranch $ value $ branch EmptyLeaf EmptyLeaf
|
|
||||||
(<>) EmptyLeaf x = x
|
|
||||||
(<>) (Leaf x) EmptyLeaf = branch (Leaf x) EmptyLeaf
|
|
||||||
(<>) (Leaf x) (Leaf y) = branch (Leaf x) (Leaf y)
|
|
||||||
(<>) (Leaf _) Branch {} = InvalidTree
|
|
||||||
(<>) (Leaf _) (PrunedBranch _) = InvalidTree
|
|
||||||
(<>) (PrunedBranch x) EmptyLeaf = PrunedBranch $ x <> x
|
|
||||||
(<>) (PrunedBranch x) (Leaf y) =
|
|
||||||
if isFull x
|
|
||||||
then InvalidTree
|
|
||||||
else mkSubTree (getLevel x) (Leaf y)
|
|
||||||
(<>) (PrunedBranch x) (Branch s t u) =
|
|
||||||
if getLevel x == getLevel s
|
|
||||||
then branch (PrunedBranch x) (Branch s t u)
|
|
||||||
else InvalidTree
|
|
||||||
(<>) (PrunedBranch x) (PrunedBranch y) = PrunedBranch $ x <> y
|
|
||||||
(<>) (Branch s x y) EmptyLeaf =
|
|
||||||
branch (Branch s x y) $ getEmptyRoot (getLevel s)
|
|
||||||
(<>) (Branch s x y) (PrunedBranch w)
|
|
||||||
| getLevel s == getLevel w = branch (Branch s x y) (PrunedBranch w)
|
|
||||||
| otherwise = InvalidTree
|
|
||||||
(<>) (Branch s x y) (Leaf w)
|
|
||||||
| isFull s = InvalidTree
|
|
||||||
| isFull (value x) = branch x (y <> Leaf w)
|
|
||||||
| otherwise = branch (x <> Leaf w) y
|
|
||||||
(<>) (Branch s x y) (Branch s1 x1 y1)
|
|
||||||
| getLevel s == getLevel s1 = branch (Branch s x y) (Branch s1 x1 y1)
|
|
||||||
| otherwise = InvalidTree
|
|
||||||
|
|
||||||
value :: Monoid v => Tree v -> v
|
|
||||||
value EmptyLeaf = mempty
|
|
||||||
value (Leaf v) = v
|
|
||||||
value (PrunedBranch v) = v
|
|
||||||
value (Branch v _ _) = v
|
|
||||||
value InvalidTree = mempty
|
|
||||||
|
|
||||||
branch :: Monoid v => Tree v -> Tree v -> Tree v
|
|
||||||
branch x y = Branch (value x <> value y) x y
|
|
||||||
|
|
||||||
leaf :: Measured a v => a -> Int32 -> Int64 -> Tree v
|
|
||||||
leaf a p i = Leaf (measure a p i)
|
|
||||||
|
|
||||||
prunedBranch :: Monoid v => Node v => Level -> Position -> HexString -> Tree v
|
|
||||||
prunedBranch level pos val = PrunedBranch $ mkNode level pos val
|
|
||||||
|
|
||||||
root :: Monoid v => Node v => Tree v -> Tree v
|
|
||||||
root tree =
|
|
||||||
if getLevel (value tree) == maxLevel
|
|
||||||
then tree
|
|
||||||
else mkSubTree maxLevel tree
|
|
||||||
|
|
||||||
getEmptyRoot :: Monoid v => Node v => Level -> Tree v
|
|
||||||
getEmptyRoot level = iterate (\x -> x <> x) EmptyLeaf !! fromIntegral level
|
|
||||||
|
|
||||||
append :: Monoid v => Measured a v => Node v => Tree v -> (a, Int64) -> Tree v
|
|
||||||
append tree (n, i) = tree <> leaf n p i
|
|
||||||
where
|
|
||||||
p = 1 + getPosition (value tree)
|
|
||||||
|
|
||||||
mkSubTree :: Node v => Monoid v => Level -> Tree v -> Tree v
|
|
||||||
mkSubTree level t =
|
|
||||||
if getLevel (value subtree) == level
|
|
||||||
then subtree
|
|
||||||
else mkSubTree level subtree
|
|
||||||
where
|
|
||||||
subtree = t <> EmptyLeaf
|
|
||||||
|
|
||||||
path :: Monoid v => Node v => Position -> Tree v -> Maybe MerklePath
|
|
||||||
path pos (Branch s x y) =
|
|
||||||
if length (collectPath (Branch s x y)) /= 32
|
|
||||||
then Nothing
|
|
||||||
else Just $ MerklePath pos $ collectPath (Branch s x y)
|
|
||||||
where
|
|
||||||
collectPath :: Monoid v => Node v => Tree v -> [HexString]
|
|
||||||
collectPath EmptyLeaf = []
|
|
||||||
collectPath Leaf {} = []
|
|
||||||
collectPath PrunedBranch {} = []
|
|
||||||
collectPath InvalidTree = []
|
|
||||||
collectPath (Branch _ j k)
|
|
||||||
| getPosition (value k) /= 0 && getPosition (value k) < pos = []
|
|
||||||
| getPosition (value j) < pos = collectPath k <> [getHash (value j)]
|
|
||||||
| getPosition (value j) >= pos = collectPath j <> [getHash (value k)]
|
|
||||||
| otherwise = []
|
|
||||||
path _ _ = Nothing
|
|
||||||
|
|
||||||
nullPath :: MerklePath
|
|
||||||
nullPath = MerklePath 0 []
|
|
||||||
|
|
||||||
getNotePosition :: Monoid v => Node v => Tree v -> Int64 -> Maybe Position
|
|
||||||
getNotePosition (Leaf x) i
|
|
||||||
| getIndex x == i = Just $ getPosition x
|
|
||||||
| otherwise = Nothing
|
|
||||||
getNotePosition (Branch _ x y) i
|
|
||||||
| getIndex (value x) >= i = getNotePosition x i
|
|
||||||
| getIndex (value y) >= i = getNotePosition y i
|
|
||||||
| otherwise = Nothing
|
|
||||||
getNotePosition _ _ = Nothing
|
|
||||||
|
|
||||||
truncateTree :: Monoid v => Node v => Tree v -> Int64 -> NoLoggingT IO (Tree v)
|
|
||||||
truncateTree (Branch s x y) i
|
|
||||||
| getLevel s == 1 && getIndex (value x) == i = do
|
|
||||||
logDebugN $ T.pack $ show (getLevel s) ++ " Trunc to left leaf"
|
|
||||||
return $ branch x EmptyLeaf
|
|
||||||
| getLevel s == 1 && getIndex (value y) == i = do
|
|
||||||
logDebugN $ T.pack $ show (getLevel s) ++ " Trunc to right leaf"
|
|
||||||
return $ branch x y
|
|
||||||
| getIndex (value x) >= i = do
|
|
||||||
logDebugN $
|
|
||||||
T.pack $
|
|
||||||
show (getLevel s) ++
|
|
||||||
": " ++ show i ++ " left i: " ++ show (getIndex (value x))
|
|
||||||
l <- truncateTree x i
|
|
||||||
return $ branch (l) (getEmptyRoot (getLevel (value x)))
|
|
||||||
| getIndex (value y) /= 0 && getIndex (value y) >= i = do
|
|
||||||
logDebugN $
|
|
||||||
T.pack $
|
|
||||||
show (getLevel s) ++
|
|
||||||
": " ++ show i ++ " right i: " ++ show (getIndex (value y))
|
|
||||||
r <- truncateTree y i
|
|
||||||
return $ branch x (r)
|
|
||||||
| otherwise = do
|
|
||||||
logDebugN $
|
|
||||||
T.pack $
|
|
||||||
show (getLevel s) ++
|
|
||||||
": " ++
|
|
||||||
show (getIndex (value x)) ++ " catchall " ++ show (getIndex (value y))
|
|
||||||
return InvalidTree
|
|
||||||
truncateTree x _ = return x
|
|
||||||
|
|
||||||
countLeaves :: Node v => Tree v -> Int64
|
|
||||||
countLeaves (Branch s x y) =
|
|
||||||
if isFull s
|
|
||||||
then 2 ^ getLevel s
|
|
||||||
else countLeaves x + countLeaves y
|
|
||||||
countLeaves (PrunedBranch x) =
|
|
||||||
if isFull x
|
|
||||||
then 2 ^ getLevel x
|
|
||||||
else 0
|
|
||||||
countLeaves (Leaf _) = 1
|
|
||||||
countLeaves EmptyLeaf = 0
|
|
||||||
countLeaves InvalidTree = 0
|
|
||||||
|
|
||||||
batchAppend ::
|
|
||||||
Measured a v
|
|
||||||
=> Node v => Monoid v => Tree v -> [(Int32, (a, Int64))] -> Tree v
|
|
||||||
batchAppend x [] = x
|
|
||||||
batchAppend (Branch s x y) notes
|
|
||||||
| isFull s = InvalidTree
|
|
||||||
| isFull (value x) = branch x (batchAppend y notes)
|
|
||||||
| otherwise =
|
|
||||||
branch
|
|
||||||
(batchAppend x (take leftSide notes))
|
|
||||||
(batchAppend y (drop leftSide notes))
|
|
||||||
where
|
|
||||||
leftSide = fromIntegral $ 2 ^ getLevel (value x) - countLeaves x
|
|
||||||
batchAppend (PrunedBranch k) notes
|
|
||||||
| isFull k = InvalidTree
|
|
||||||
| otherwise =
|
|
||||||
branch
|
|
||||||
(batchAppend (getEmptyRoot (getLevel k - 1)) (take leftSide notes))
|
|
||||||
(batchAppend (getEmptyRoot (getLevel k - 1)) (drop leftSide notes))
|
|
||||||
where
|
|
||||||
leftSide = fromIntegral $ 2 ^ (getLevel k - 1)
|
|
||||||
batchAppend EmptyLeaf notes
|
|
||||||
| length notes == 1 =
|
|
||||||
leaf (fst $ snd $ head notes) (fst $ head notes) (snd $ snd $ head notes)
|
|
||||||
| otherwise = InvalidTree
|
|
||||||
batchAppend _ notes = InvalidTree
|
|
||||||
|
|
||||||
data SaplingNode = SaplingNode
|
|
||||||
{ sn_position :: !Position
|
|
||||||
, sn_value :: !HexString
|
|
||||||
, sn_level :: !Level
|
|
||||||
, sn_full :: !Bool
|
|
||||||
, sn_index :: !Int64
|
|
||||||
, sn_mark :: !Bool
|
|
||||||
} deriving stock (Eq, GHC.Generic)
|
|
||||||
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct SaplingNode
|
|
||||||
|
|
||||||
instance Semigroup SaplingNode where
|
|
||||||
(<>) x y =
|
|
||||||
case combineSaplingNodes (sn_level x) (sn_value x) (sn_value y) of
|
|
||||||
Nothing -> x
|
|
||||||
Just newHash ->
|
|
||||||
SaplingNode
|
|
||||||
(max (sn_position x) (sn_position y))
|
|
||||||
newHash
|
|
||||||
(1 + sn_level x)
|
|
||||||
(sn_full x && sn_full y)
|
|
||||||
(max (sn_index x) (sn_index y))
|
|
||||||
(sn_mark x || sn_mark y)
|
|
||||||
|
|
||||||
instance Monoid SaplingNode where
|
|
||||||
mempty = SaplingNode 0 (hexString "00") 0 False 0 False
|
|
||||||
mappend = (<>)
|
|
||||||
|
|
||||||
instance Node SaplingNode where
|
|
||||||
getLevel = sn_level
|
|
||||||
getHash = sn_value
|
|
||||||
getPosition = sn_position
|
|
||||||
getIndex = sn_index
|
|
||||||
isFull = sn_full
|
|
||||||
isMarked = sn_mark
|
|
||||||
mkNode l p v = SaplingNode p v l True 0 False
|
|
||||||
|
|
||||||
instance Show SaplingNode where
|
|
||||||
show = show . sn_value
|
|
||||||
|
|
||||||
saplingSize :: SaplingTree -> Int64
|
|
||||||
saplingSize tree =
|
|
||||||
(if isNothing (st_left tree)
|
|
||||||
then 0
|
|
||||||
else 1) +
|
|
||||||
(if isNothing (st_right tree)
|
|
||||||
then 0
|
|
||||||
else 1) +
|
|
||||||
foldl
|
|
||||||
(\x (i, p) ->
|
|
||||||
case p of
|
|
||||||
Nothing -> x + 0
|
|
||||||
Just _ -> x + 2 ^ i)
|
|
||||||
0
|
|
||||||
(zip [1 ..] $ st_parents tree)
|
|
||||||
|
|
||||||
mkSaplingTree :: SaplingTree -> Tree SaplingNode
|
|
||||||
mkSaplingTree tree =
|
|
||||||
foldl
|
|
||||||
(\t (i, n) ->
|
|
||||||
case n of
|
|
||||||
Just n' -> prunedBranch i 0 n' <> t
|
|
||||||
Nothing -> t <> getEmptyRoot i)
|
|
||||||
leafRoot
|
|
||||||
(zip [1 ..] $ st_parents tree)
|
|
||||||
where
|
|
||||||
leafRoot =
|
|
||||||
case st_right tree of
|
|
||||||
Just r' -> leaf (fromJust $ st_left tree) (pos - 1) 0 <> leaf r' pos 0
|
|
||||||
Nothing -> leaf (fromJust $ st_left tree) pos 0 <> EmptyLeaf
|
|
||||||
pos = fromIntegral $ saplingSize tree - 1
|
|
||||||
|
|
||||||
-- | Orchard
|
|
||||||
data OrchardNode = OrchardNode
|
|
||||||
{ on_position :: !Position
|
|
||||||
, on_value :: !HexString
|
|
||||||
, on_level :: !Level
|
|
||||||
, on_full :: !Bool
|
|
||||||
, on_index :: !Int64
|
|
||||||
, on_mark :: !Bool
|
|
||||||
} deriving stock (Eq, GHC.Generic)
|
|
||||||
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardNode
|
|
||||||
|
|
||||||
instance Semigroup OrchardNode where
|
|
||||||
(<>) x y =
|
|
||||||
case combineOrchardNodes
|
|
||||||
(fromIntegral $ on_level x)
|
|
||||||
(on_value x)
|
|
||||||
(on_value y) of
|
|
||||||
Nothing -> x
|
|
||||||
Just newHash ->
|
|
||||||
OrchardNode
|
|
||||||
(max (on_position x) (on_position y))
|
|
||||||
newHash
|
|
||||||
(1 + on_level x)
|
|
||||||
(on_full x && on_full y)
|
|
||||||
(max (on_index x) (on_index y))
|
|
||||||
(on_mark x || on_mark y)
|
|
||||||
|
|
||||||
instance Monoid OrchardNode where
|
|
||||||
mempty = OrchardNode 0 (hexString "00") 0 False 0 False
|
|
||||||
mappend = (<>)
|
|
||||||
|
|
||||||
instance Node OrchardNode where
|
|
||||||
getLevel = on_level
|
|
||||||
getHash = on_value
|
|
||||||
getPosition = on_position
|
|
||||||
getIndex = on_index
|
|
||||||
isFull = on_full
|
|
||||||
isMarked = on_mark
|
|
||||||
mkNode l p v = OrchardNode p v l True 0 False
|
|
||||||
|
|
||||||
instance Show OrchardNode where
|
|
||||||
show = show . on_value
|
|
||||||
|
|
||||||
instance Measured OrchardNode OrchardNode where
|
|
||||||
measure o p i =
|
|
||||||
OrchardNode p (on_value o) (on_level o) (on_full o) i (on_mark o)
|
|
||||||
|
|
||||||
orchardSize :: OrchardTree -> Int64
|
|
||||||
orchardSize tree =
|
|
||||||
(if isNothing (ot_left tree)
|
|
||||||
then 0
|
|
||||||
else 1) +
|
|
||||||
(if isNothing (ot_right tree)
|
|
||||||
then 0
|
|
||||||
else 1) +
|
|
||||||
foldl
|
|
||||||
(\x (i, p) ->
|
|
||||||
case p of
|
|
||||||
Nothing -> x + 0
|
|
||||||
Just _ -> x + 2 ^ i)
|
|
||||||
0
|
|
||||||
(zip [1 ..] $ ot_parents tree)
|
|
||||||
|
|
||||||
mkOrchardTree :: OrchardTree -> Tree OrchardNode
|
|
||||||
mkOrchardTree tree =
|
|
||||||
foldl
|
|
||||||
(\t (i, n) ->
|
|
||||||
case n of
|
|
||||||
Just n' -> prunedBranch i 0 n' <> t
|
|
||||||
Nothing -> t <> getEmptyRoot i)
|
|
||||||
leafRoot
|
|
||||||
(zip [1 ..] $ ot_parents tree)
|
|
||||||
where
|
|
||||||
leafRoot =
|
|
||||||
case ot_right tree of
|
|
||||||
Just r' -> leaf (fromJust $ ot_left tree) (pos - 1) 0 <> leaf r' pos 0
|
|
||||||
Nothing -> leaf (fromJust $ ot_left tree) pos 0 <> EmptyLeaf
|
|
||||||
pos = fromIntegral $ orchardSize tree - 1
|
|
|
@ -10,39 +10,23 @@
|
||||||
module Zenith.Types where
|
module Zenith.Types where
|
||||||
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Aeson.TH (deriveJSON)
|
|
||||||
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
|
||||||
import Data.HexString
|
import Data.HexString
|
||||||
import Data.Int (Int64)
|
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Scientific (Scientific)
|
|
||||||
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.Text.Encoding.Error (lenientDecode)
|
import Data.Text.Encoding.Error (lenientDecode)
|
||||||
import qualified Data.UUID as U
|
|
||||||
import Database.Persist.TH
|
import Database.Persist.TH
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
import ZcashHaskell.Orchard (encodeUnifiedAddress, parseAddress)
|
|
||||||
import ZcashHaskell.Sapling (encodeSaplingAddress)
|
|
||||||
import ZcashHaskell.Transparent
|
|
||||||
( encodeExchangeAddress
|
|
||||||
, encodeTransparentReceiver
|
|
||||||
)
|
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( ExchangeAddress(..)
|
( OrchardSpendingKey(..)
|
||||||
, OrchardSpendingKey(..)
|
|
||||||
, Phrase(..)
|
, Phrase(..)
|
||||||
, Rseed(..)
|
, Rseed(..)
|
||||||
, SaplingAddress(..)
|
|
||||||
, SaplingSpendingKey(..)
|
, SaplingSpendingKey(..)
|
||||||
, Scope(..)
|
, Scope(..)
|
||||||
, TransparentAddress(..)
|
|
||||||
, TransparentSpendingKey
|
, TransparentSpendingKey
|
||||||
, UnifiedFullViewingKey(..)
|
|
||||||
, UnifiedIncomingViewingKey(..)
|
|
||||||
, ValidAddress(..)
|
|
||||||
, ZcashNet(..)
|
, ZcashNet(..)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,9 +42,6 @@ newtype ZcashNetDB = ZcashNetDB
|
||||||
{ getNet :: ZcashNet
|
{ getNet :: ZcashNet
|
||||||
} deriving newtype (Eq, Show, Read)
|
} deriving newtype (Eq, Show, Read)
|
||||||
|
|
||||||
instance ToJSON ZcashNetDB where
|
|
||||||
toJSON (ZcashNetDB z) = toJSON z
|
|
||||||
|
|
||||||
derivePersistField "ZcashNetDB"
|
derivePersistField "ZcashNetDB"
|
||||||
|
|
||||||
newtype UnifiedAddressDB = UnifiedAddressDB
|
newtype UnifiedAddressDB = UnifiedAddressDB
|
||||||
|
@ -105,209 +86,14 @@ newtype RseedDB = RseedDB
|
||||||
|
|
||||||
derivePersistField "RseedDB"
|
derivePersistField "RseedDB"
|
||||||
|
|
||||||
newtype UnifiedFvkDB = UnifiedFvkDB
|
|
||||||
{ getFvk :: UnifiedFullViewingKey
|
|
||||||
} deriving newtype (Eq, Show, Read)
|
|
||||||
|
|
||||||
derivePersistField "UnifiedFvkDB"
|
|
||||||
|
|
||||||
newtype UnifiedIvkDB = UnifiedIvkDB
|
|
||||||
{ getIvk :: UnifiedIncomingViewingKey
|
|
||||||
} deriving newtype (Eq, Show, Read)
|
|
||||||
|
|
||||||
derivePersistField "UnifiedIvkDB"
|
|
||||||
|
|
||||||
data AccountType
|
|
||||||
= Local
|
|
||||||
| FullViewKey
|
|
||||||
| IncomingViewKey
|
|
||||||
deriving (Eq, Show, Read)
|
|
||||||
|
|
||||||
derivePersistField "AccountType"
|
|
||||||
|
|
||||||
instance ToJSON AccountType where
|
|
||||||
toJSON at =
|
|
||||||
case at of
|
|
||||||
Local -> Data.Aeson.String "Local"
|
|
||||||
FullViewKey -> Data.Aeson.String "FullViewKey"
|
|
||||||
IncomingViewKey -> Data.Aeson.String "IncomingViewKey"
|
|
||||||
|
|
||||||
instance FromJSON AccountType where
|
|
||||||
parseJSON =
|
|
||||||
withText "AccountType" $ \case
|
|
||||||
"Local" -> return Local
|
|
||||||
"FullViewKey" -> return FullViewKey
|
|
||||||
"IncomingViewKey" -> return IncomingViewKey
|
|
||||||
_ -> fail "Not a valid Account type"
|
|
||||||
|
|
||||||
-- * RPC
|
-- * RPC
|
||||||
-- | Type for Configuration parameters
|
-- | Type for Configuration parameters
|
||||||
data Config = Config
|
data Config = Config
|
||||||
{ c_dbPath :: !T.Text
|
{ c_dbPath :: !T.Text
|
||||||
, c_zebraHost :: !T.Text
|
, c_zebraHost :: !T.Text
|
||||||
, c_zebraPort :: !Int
|
, c_zebraPort :: !Int
|
||||||
, c_zenithUser :: !BS.ByteString
|
|
||||||
, c_zenithPwd :: !BS.ByteString
|
|
||||||
, c_zenithPort :: !Int
|
|
||||||
, c_currencyCode :: !T.Text
|
|
||||||
} deriving (Eq, Prelude.Show)
|
} deriving (Eq, Prelude.Show)
|
||||||
|
|
||||||
data ZcashPool
|
|
||||||
= TransparentPool
|
|
||||||
| SproutPool
|
|
||||||
| SaplingPool
|
|
||||||
| OrchardPool
|
|
||||||
deriving (Show, Read, Eq)
|
|
||||||
|
|
||||||
derivePersistField "ZcashPool"
|
|
||||||
|
|
||||||
instance ToJSON ZcashPool where
|
|
||||||
toJSON zp =
|
|
||||||
case zp of
|
|
||||||
TransparentPool -> Data.Aeson.String "p2pkh"
|
|
||||||
SproutPool -> Data.Aeson.String "sprout"
|
|
||||||
SaplingPool -> Data.Aeson.String "sapling"
|
|
||||||
OrchardPool -> Data.Aeson.String "orchard"
|
|
||||||
|
|
||||||
instance FromJSON ZcashPool where
|
|
||||||
parseJSON =
|
|
||||||
withText "ZcashPool" $ \case
|
|
||||||
"p2pkh" -> return TransparentPool
|
|
||||||
"sprout" -> return SproutPool
|
|
||||||
"sapling" -> return SaplingPool
|
|
||||||
"orchard" -> return OrchardPool
|
|
||||||
_ -> fail "Not a known Zcash pool"
|
|
||||||
|
|
||||||
newtype ZenithUuid = ZenithUuid
|
|
||||||
{ getUuid :: U.UUID
|
|
||||||
} deriving newtype (Show, Eq, Read, ToJSON, FromJSON)
|
|
||||||
|
|
||||||
derivePersistField "ZenithUuid"
|
|
||||||
|
|
||||||
-- ** API types
|
|
||||||
data ZcashWalletAPI = ZcashWalletAPI
|
|
||||||
{ zw_index :: !Int
|
|
||||||
, zw_name :: !T.Text
|
|
||||||
, zw_network :: !ZcashNet
|
|
||||||
, zw_birthday :: !Int
|
|
||||||
, zw_lastSync :: !Int
|
|
||||||
, zw_local :: !Bool
|
|
||||||
} deriving (Eq, Prelude.Show)
|
|
||||||
|
|
||||||
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashWalletAPI)
|
|
||||||
|
|
||||||
data ZcashAccountAPI = ZcashAccountAPI
|
|
||||||
{ za_index :: !Int
|
|
||||||
, za_wallet :: !Int
|
|
||||||
, za_name :: !T.Text
|
|
||||||
, za_type :: !AccountType
|
|
||||||
} deriving (Eq, Prelude.Show)
|
|
||||||
|
|
||||||
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashAccountAPI)
|
|
||||||
|
|
||||||
data ZcashAddressAPI = ZcashAddressAPI
|
|
||||||
{ zd_index :: !Int
|
|
||||||
, zd_account :: !Int
|
|
||||||
, zd_name :: !T.Text
|
|
||||||
, zd_ua :: !T.Text
|
|
||||||
, zd_legacy :: !(Maybe T.Text)
|
|
||||||
, zd_transparent :: !(Maybe T.Text)
|
|
||||||
} deriving (Eq, Prelude.Show)
|
|
||||||
|
|
||||||
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashAddressAPI)
|
|
||||||
|
|
||||||
data ZcashNoteAPI = ZcashNoteAPI
|
|
||||||
{ zn_txid :: !HexString
|
|
||||||
, zn_pool :: !ZcashPool
|
|
||||||
, zn_amount :: !Float
|
|
||||||
, zn_amountZats :: !Int64
|
|
||||||
, zn_memo :: !T.Text
|
|
||||||
, zn_confirmed :: !Bool
|
|
||||||
, zn_blockheight :: !Int
|
|
||||||
, zn_blocktime :: !Int
|
|
||||||
, zn_outindex :: !Int
|
|
||||||
, zn_change :: !Bool
|
|
||||||
} deriving (Eq, Prelude.Show)
|
|
||||||
|
|
||||||
$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ZcashNoteAPI)
|
|
||||||
|
|
||||||
data AccountBalance = AccountBalance
|
|
||||||
{ acb_transparent :: !Int64
|
|
||||||
, acb_sapling :: !Int64
|
|
||||||
, acb_orchard :: !Int64
|
|
||||||
} deriving (Eq, Prelude.Show)
|
|
||||||
|
|
||||||
$(deriveJSON defaultOptions {fieldLabelModifier = drop 4} ''AccountBalance)
|
|
||||||
|
|
||||||
data ZenithStatus
|
|
||||||
= Processing
|
|
||||||
| Failed
|
|
||||||
| Successful
|
|
||||||
deriving (Eq, Prelude.Show, Read)
|
|
||||||
|
|
||||||
$(deriveJSON defaultOptions ''ZenithStatus)
|
|
||||||
|
|
||||||
derivePersistField "ZenithStatus"
|
|
||||||
|
|
||||||
data PrivacyPolicy
|
|
||||||
= None
|
|
||||||
| Low
|
|
||||||
| Medium
|
|
||||||
| Full
|
|
||||||
deriving (Eq, Show, Read, Ord)
|
|
||||||
|
|
||||||
$(deriveJSON defaultOptions ''PrivacyPolicy)
|
|
||||||
|
|
||||||
newtype ValidAddressAPI = ValidAddressAPI
|
|
||||||
{ getVA :: ValidAddress
|
|
||||||
} deriving newtype (Eq, Show)
|
|
||||||
|
|
||||||
instance ToJSON ValidAddressAPI where
|
|
||||||
toJSON (ValidAddressAPI va) =
|
|
||||||
case va of
|
|
||||||
Unified ua -> Data.Aeson.String $ encodeUnifiedAddress ua
|
|
||||||
Sapling sa ->
|
|
||||||
maybe
|
|
||||||
Data.Aeson.Null
|
|
||||||
Data.Aeson.String
|
|
||||||
(encodeSaplingAddress (net_type sa) (sa_receiver sa))
|
|
||||||
Transparent ta ->
|
|
||||||
Data.Aeson.String $
|
|
||||||
encodeTransparentReceiver (ta_network ta) (ta_receiver ta)
|
|
||||||
Exchange ea ->
|
|
||||||
maybe
|
|
||||||
Data.Aeson.Null
|
|
||||||
Data.Aeson.String
|
|
||||||
(encodeExchangeAddress (ex_network ea) (ex_address ea))
|
|
||||||
|
|
||||||
data ProposedNote = ProposedNote
|
|
||||||
{ pn_addr :: !ValidAddressAPI
|
|
||||||
, pn_amt :: !Scientific
|
|
||||||
, pn_memo :: !(Maybe T.Text)
|
|
||||||
} deriving (Eq, Prelude.Show)
|
|
||||||
|
|
||||||
instance FromJSON ProposedNote where
|
|
||||||
parseJSON =
|
|
||||||
withObject "ProposedNote" $ \obj -> do
|
|
||||||
a <- obj .: "address"
|
|
||||||
n <- obj .: "amount"
|
|
||||||
m <- obj .:? "memo"
|
|
||||||
case parseAddress (E.encodeUtf8 a) of
|
|
||||||
Nothing -> fail "Invalid address"
|
|
||||||
Just a' ->
|
|
||||||
if n > 0 && n < 21000000
|
|
||||||
then pure $ ProposedNote (ValidAddressAPI a') n m
|
|
||||||
else fail "Invalid amount"
|
|
||||||
|
|
||||||
instance ToJSON ProposedNote where
|
|
||||||
toJSON (ProposedNote a n m) =
|
|
||||||
object ["address" .= a, "amount" .= n, "memo" .= m]
|
|
||||||
|
|
||||||
data ShieldDeshieldOp
|
|
||||||
= Shield
|
|
||||||
| Deshield
|
|
||||||
deriving (Eq, Show, Read, Ord)
|
|
||||||
|
|
||||||
-- ** `zebrad`
|
-- ** `zebrad`
|
||||||
-- | Type for modeling the tree state response
|
-- | Type for modeling the tree state response
|
||||||
data ZebraTreeInfo = ZebraTreeInfo
|
data ZebraTreeInfo = ZebraTreeInfo
|
||||||
|
@ -352,6 +138,22 @@ instance FromJSON AddressSource where
|
||||||
"mnemonic_seed" -> return MnemonicSeed
|
"mnemonic_seed" -> return MnemonicSeed
|
||||||
_ -> fail "Not a known address source"
|
_ -> fail "Not a known address source"
|
||||||
|
|
||||||
|
data ZcashPool
|
||||||
|
= Transparent
|
||||||
|
| Sprout
|
||||||
|
| Sapling
|
||||||
|
| Orchard
|
||||||
|
deriving (Show, Eq, Generic, ToJSON)
|
||||||
|
|
||||||
|
instance FromJSON ZcashPool where
|
||||||
|
parseJSON =
|
||||||
|
withText "ZcashPool" $ \case
|
||||||
|
"p2pkh" -> return Transparent
|
||||||
|
"sprout" -> return Sprout
|
||||||
|
"sapling" -> return Sapling
|
||||||
|
"orchard" -> return Orchard
|
||||||
|
_ -> fail "Not a known Zcash pool"
|
||||||
|
|
||||||
data ZcashAddress = ZcashAddress
|
data ZcashAddress = ZcashAddress
|
||||||
{ source :: AddressSource
|
{ source :: AddressSource
|
||||||
, pool :: [ZcashPool]
|
, pool :: [ZcashPool]
|
||||||
|
@ -399,8 +201,7 @@ instance FromJSON AddressGroup where
|
||||||
Nothing -> return []
|
Nothing -> return []
|
||||||
Just x -> do
|
Just x -> do
|
||||||
x' <- x .:? "addresses"
|
x' <- x .:? "addresses"
|
||||||
return $
|
return $ maybe [] (map (ZcashAddress s1 [Transparent] Nothing)) x'
|
||||||
maybe [] (map (ZcashAddress s1 [TransparentPool] Nothing)) x'
|
|
||||||
processSapling k s2 =
|
processSapling k s2 =
|
||||||
case k of
|
case k of
|
||||||
Nothing -> return []
|
Nothing -> return []
|
||||||
|
@ -408,7 +209,7 @@ instance FromJSON AddressGroup where
|
||||||
where processOneSapling sx =
|
where processOneSapling sx =
|
||||||
withObject "Sapling" $ \oS -> do
|
withObject "Sapling" $ \oS -> do
|
||||||
oS' <- oS .: "addresses"
|
oS' <- oS .: "addresses"
|
||||||
return $ map (ZcashAddress sx [SaplingPool] Nothing) oS'
|
return $ map (ZcashAddress sx [Sapling] Nothing) oS'
|
||||||
processUnified u =
|
processUnified u =
|
||||||
case u of
|
case u of
|
||||||
Nothing -> return []
|
Nothing -> return []
|
||||||
|
@ -547,19 +348,3 @@ encodeHexText' t =
|
||||||
if T.length t > 0
|
if T.length t > 0
|
||||||
then C.unpack . B64.encode $ E.encodeUtf8 t
|
then C.unpack . B64.encode $ E.encodeUtf8 t
|
||||||
else C.unpack . B64.encode $ E.encodeUtf8 "Sent from Zenith"
|
else C.unpack . B64.encode $ E.encodeUtf8 "Sent from Zenith"
|
||||||
|
|
||||||
-- | Define a data structure for the parsed components
|
|
||||||
data ZcashPaymentURI = ZcashPaymentURI
|
|
||||||
{ uriAddress :: String
|
|
||||||
, uriAmount :: Maybe Double
|
|
||||||
, uriMemo :: T.Text
|
|
||||||
, uriLabel :: Maybe String
|
|
||||||
, uriMessage :: Maybe String
|
|
||||||
} deriving (Show, Eq)
|
|
||||||
|
|
||||||
-- | Define a data structure for the URI QR image
|
|
||||||
data URIQrCode = URIQrCode
|
|
||||||
{ uriBytes :: BS.ByteString -- Image as ByteString
|
|
||||||
, uriWidth :: Double -- Number of columns in QR Image
|
|
||||||
, uriHeight :: Double -- Number of rows in a QR Image
|
|
||||||
} deriving (Show, Eq)
|
|
||||||
|
|
|
@ -2,61 +2,20 @@
|
||||||
|
|
||||||
module Zenith.Utils where
|
module Zenith.Utils where
|
||||||
|
|
||||||
import Control.Exception (SomeException, try)
|
|
||||||
import Control.Monad (when)
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import qualified Data.Aeson.Key as K
|
|
||||||
import qualified Data.Aeson.KeyMap as KM
|
|
||||||
import Data.Aeson.Types (parseMaybe)
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import qualified Data.ByteString.Base64 as B64
|
|
||||||
import qualified Data.ByteString.Char8 as BC
|
|
||||||
import qualified Data.ByteString.Lazy as B
|
|
||||||
import qualified Data.ByteString.Lazy.Char8 as BL
|
|
||||||
import Data.Char (isAlphaNum, isSpace)
|
|
||||||
import Data.Functor (void)
|
import Data.Functor (void)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Ord (clamp)
|
import Data.Scientific (Scientific(..), scientific)
|
||||||
import Data.Scientific (Scientific(..), Scientific, scientific, toRealFloat)
|
|
||||||
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 qualified Data.Text.Encoding as TE
|
|
||||||
import Network.HTTP.Simple
|
|
||||||
import Network.URI (escapeURIString, isUnreserved)
|
|
||||||
import System.Directory
|
|
||||||
import System.Process (createProcess_, shell)
|
import System.Process (createProcess_, shell)
|
||||||
import Text.Printf (printf)
|
|
||||||
import Text.Read (readMaybe)
|
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
import ZcashHaskell.Orchard
|
import ZcashHaskell.Orchard (encodeUnifiedAddress, isValidUnifiedAddress)
|
||||||
( encodeUnifiedAddress
|
import ZcashHaskell.Sapling (isValidShieldedAddress)
|
||||||
, isValidUnifiedAddress
|
|
||||||
, parseAddress
|
|
||||||
)
|
|
||||||
import ZcashHaskell.Sapling (decodeSaplingAddress, isValidShieldedAddress)
|
|
||||||
import ZcashHaskell.Transparent
|
|
||||||
( decodeExchangeAddress
|
|
||||||
, decodeTransparentAddress
|
|
||||||
)
|
|
||||||
import ZcashHaskell.Types
|
|
||||||
( ExchangeAddress(..)
|
|
||||||
, ExchangeAddress(..)
|
|
||||||
, Phrase(..)
|
|
||||||
, SaplingAddress(..)
|
|
||||||
, TransparentAddress(..)
|
|
||||||
, UnifiedAddress(..)
|
|
||||||
, ValidAddress(..)
|
|
||||||
, ValidAddress(..)
|
|
||||||
, ZcashNet(..)
|
|
||||||
)
|
|
||||||
import ZcashHaskell.Utils (makeZebraCall)
|
|
||||||
import Zenith.Types
|
import Zenith.Types
|
||||||
( AddressGroup(..)
|
( AddressGroup(..)
|
||||||
, PrivacyPolicy(..)
|
|
||||||
, UnifiedAddressDB(..)
|
, UnifiedAddressDB(..)
|
||||||
, ZcashAddress(..)
|
, ZcashAddress(..)
|
||||||
, ZcashPaymentURI(..)
|
|
||||||
, ZcashPool(..)
|
, ZcashPool(..)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,24 +26,18 @@ jsonNumber i = Number $ scientific (fromIntegral i) 0
|
||||||
-- | Helper function to display small amounts of ZEC
|
-- | Helper function to display small amounts of ZEC
|
||||||
displayZec :: Integer -> String
|
displayZec :: Integer -> String
|
||||||
displayZec s
|
displayZec s
|
||||||
| abs s < 100 = show s ++ " zats"
|
| abs s < 100 = show s ++ " zats "
|
||||||
| abs s < 100000 = show (fromIntegral s / 100) ++ " μZEC"
|
| abs s < 100000 = show (fromIntegral s / 100) ++ " μZEC "
|
||||||
| abs s < 100000000 = show (fromIntegral s / 100000) ++ " mZEC"
|
| abs 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 TAZ
|
-- | Helper function to display small amounts of ZEC
|
||||||
displayTaz :: Integer -> String
|
displayTaz :: Integer -> String
|
||||||
displayTaz s
|
displayTaz s
|
||||||
| abs s < 100 = show s ++ " tazs"
|
| abs s < 100 = show s ++ " tazs "
|
||||||
| abs s < 100000 = show (fromIntegral s / 100) ++ " μTAZ"
|
| abs s < 100000 = show (fromIntegral s / 100) ++ " μTAZ "
|
||||||
| abs s < 100000000 = show (fromIntegral s / 100000) ++ " mTAZ"
|
| abs s < 100000000 = show (fromIntegral s / 100000) ++ " mTAZ "
|
||||||
| otherwise = show (fromIntegral s / 100000000) ++ " TAZ"
|
| otherwise = show (fromIntegral s / 100000000) ++ " TAZ "
|
||||||
|
|
||||||
displayAmount :: ZcashNet -> Integer -> T.Text
|
|
||||||
displayAmount n a =
|
|
||||||
if n == MainNet
|
|
||||||
then T.pack $ displayZec a
|
|
||||||
else T.pack $ displayTaz a
|
|
||||||
|
|
||||||
-- | Helper function to display abbreviated Unified Address
|
-- | Helper function to display abbreviated Unified Address
|
||||||
showAddress :: UnifiedAddressDB -> T.Text
|
showAddress :: UnifiedAddressDB -> T.Text
|
||||||
|
@ -99,9 +52,9 @@ getAddresses ag = agtransparent ag <> agsapling ag <> agunified ag
|
||||||
-- | Helper function to validate potential Zcash addresses
|
-- | Helper function to validate potential Zcash addresses
|
||||||
validateAddress :: T.Text -> Maybe ZcashPool
|
validateAddress :: T.Text -> Maybe ZcashPool
|
||||||
validateAddress txt --(tReg || sReg && isJust chk) || (uReg && isJust chk)
|
validateAddress txt --(tReg || sReg && isJust chk) || (uReg && isJust chk)
|
||||||
| tReg = Just TransparentPool
|
| tReg = Just Transparent
|
||||||
| sReg && chkS = Just SaplingPool
|
| sReg && chkS = Just Sapling
|
||||||
| uReg && chk = Just OrchardPool
|
| uReg && chk = Just Orchard
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
where
|
where
|
||||||
transparentRegex = "^t1[a-zA-Z0-9]{33}$" :: String
|
transparentRegex = "^t1[a-zA-Z0-9]{33}$" :: String
|
||||||
|
@ -113,274 +66,9 @@ validateAddress txt --(tReg || sReg && isJust chk) || (uReg && isJust chk)
|
||||||
chk = isJust $ isValidUnifiedAddress $ E.encodeUtf8 txt
|
chk = isJust $ isValidUnifiedAddress $ E.encodeUtf8 txt
|
||||||
chkS = isValidShieldedAddress $ E.encodeUtf8 txt
|
chkS = isValidShieldedAddress $ E.encodeUtf8 txt
|
||||||
|
|
||||||
-- | Return True if Address is valid
|
|
||||||
validateAddressBool :: T.Text -> Bool
|
|
||||||
validateAddressBool a = do
|
|
||||||
case (validateAddress a) of
|
|
||||||
Nothing -> False
|
|
||||||
_ -> True
|
|
||||||
|
|
||||||
-- | Copy an address to the clipboard
|
-- | Copy an address to the clipboard
|
||||||
copyAddress :: ZcashAddress -> IO ()
|
copyAddress :: ZcashAddress -> IO ()
|
||||||
copyAddress a =
|
copyAddress a =
|
||||||
void $
|
void $
|
||||||
createProcess_ "toClipboard" $
|
createProcess_ "toClipboard" $
|
||||||
shell $ "echo " ++ T.unpack (addy a) ++ " | xclip -r -selection clipboard"
|
shell $ "echo " ++ T.unpack (addy a) ++ " | xclip -r -selection clipboard"
|
||||||
|
|
||||||
-- | Get current user and build zenith path
|
|
||||||
getZenithPath :: IO String
|
|
||||||
getZenithPath = do
|
|
||||||
homeDirectory <- getHomeDirectory
|
|
||||||
return (homeDirectory ++ "/Zenith/")
|
|
||||||
|
|
||||||
-- | Bound a value to the 0..1 range, used for progress reporting on UIs
|
|
||||||
validBarValue :: Float -> Float
|
|
||||||
validBarValue = clamp (0, 1)
|
|
||||||
|
|
||||||
isRecipientValid :: T.Text -> Bool
|
|
||||||
isRecipientValid a = do
|
|
||||||
case isValidUnifiedAddress (E.encodeUtf8 a) of
|
|
||||||
Just _a1 -> True
|
|
||||||
Nothing ->
|
|
||||||
isValidShieldedAddress (E.encodeUtf8 a) ||
|
|
||||||
(case decodeTransparentAddress (E.encodeUtf8 a) of
|
|
||||||
Just _a3 -> True
|
|
||||||
Nothing ->
|
|
||||||
case decodeExchangeAddress (E.encodeUtf8 a) of
|
|
||||||
Just _a4 -> True
|
|
||||||
Nothing -> False)
|
|
||||||
|
|
||||||
isUnifiedAddressValid :: T.Text -> Bool
|
|
||||||
isUnifiedAddressValid ua =
|
|
||||||
case isValidUnifiedAddress (E.encodeUtf8 ua) of
|
|
||||||
Just _a1 -> True
|
|
||||||
Nothing -> False
|
|
||||||
|
|
||||||
isSaplingAddressValid :: T.Text -> Bool
|
|
||||||
isSaplingAddressValid sa = isValidShieldedAddress (E.encodeUtf8 sa)
|
|
||||||
|
|
||||||
isTransparentAddressValid :: T.Text -> Bool
|
|
||||||
isTransparentAddressValid ta =
|
|
||||||
case decodeTransparentAddress (E.encodeUtf8 ta) of
|
|
||||||
Just _a3 -> True
|
|
||||||
Nothing -> False
|
|
||||||
|
|
||||||
isExchangeAddressValid :: T.Text -> Bool
|
|
||||||
isExchangeAddressValid xa =
|
|
||||||
case decodeExchangeAddress (E.encodeUtf8 xa) of
|
|
||||||
Just _a4 -> True
|
|
||||||
Nothing -> False
|
|
||||||
|
|
||||||
isRecipientValidGUI :: PrivacyPolicy -> T.Text -> Bool
|
|
||||||
isRecipientValidGUI p a = do
|
|
||||||
let adr = parseAddress (E.encodeUtf8 a)
|
|
||||||
case p of
|
|
||||||
Full ->
|
|
||||||
case adr of
|
|
||||||
Just a ->
|
|
||||||
case a of
|
|
||||||
Unified ua -> True
|
|
||||||
Sapling sa -> True
|
|
||||||
_ -> False
|
|
||||||
Nothing -> False
|
|
||||||
Medium ->
|
|
||||||
case adr of
|
|
||||||
Just a ->
|
|
||||||
case a of
|
|
||||||
Unified ua -> True
|
|
||||||
Sapling sa -> True
|
|
||||||
_ -> False
|
|
||||||
Nothing -> False
|
|
||||||
Low ->
|
|
||||||
case adr of
|
|
||||||
Just a ->
|
|
||||||
case a of
|
|
||||||
Unified ua -> True
|
|
||||||
Sapling sa -> True
|
|
||||||
Transparent ta -> True
|
|
||||||
_ -> False
|
|
||||||
Nothing -> False
|
|
||||||
None ->
|
|
||||||
case adr of
|
|
||||||
Just a ->
|
|
||||||
case a of
|
|
||||||
Transparent ta -> True
|
|
||||||
Exchange ea -> True
|
|
||||||
_ -> False
|
|
||||||
Nothing -> False
|
|
||||||
|
|
||||||
isZecAddressValid :: T.Text -> Bool
|
|
||||||
isZecAddressValid a = do
|
|
||||||
case isValidUnifiedAddress (E.encodeUtf8 a) of
|
|
||||||
Just _a1 -> True
|
|
||||||
Nothing ->
|
|
||||||
isValidShieldedAddress (E.encodeUtf8 a) ||
|
|
||||||
(case decodeTransparentAddress (E.encodeUtf8 a) of
|
|
||||||
Just _a3 -> True
|
|
||||||
Nothing ->
|
|
||||||
case decodeExchangeAddress (E.encodeUtf8 a) of
|
|
||||||
Just _a4 -> True
|
|
||||||
Nothing -> False)
|
|
||||||
|
|
||||||
parseAddressUA :: T.Text -> ZcashNet -> Maybe UnifiedAddress
|
|
||||||
parseAddressUA a znet =
|
|
||||||
case isValidUnifiedAddress (E.encodeUtf8 a) of
|
|
||||||
Just a1 -> Just a1
|
|
||||||
Nothing ->
|
|
||||||
case decodeSaplingAddress (E.encodeUtf8 a) of
|
|
||||||
Just a2 ->
|
|
||||||
Just $ UnifiedAddress znet Nothing (Just $ sa_receiver a2) Nothing
|
|
||||||
Nothing ->
|
|
||||||
case decodeTransparentAddress (E.encodeUtf8 a) of
|
|
||||||
Just a3 ->
|
|
||||||
Just $ UnifiedAddress znet Nothing Nothing (Just $ ta_receiver a3)
|
|
||||||
Nothing -> Nothing
|
|
||||||
|
|
||||||
isValidContent :: String -> Bool
|
|
||||||
isValidContent [] = False -- an empty string is invalid
|
|
||||||
isValidContent (x:xs)
|
|
||||||
| not (isAlphaNum x) = False -- string must start with an alphanumeric character
|
|
||||||
| otherwise = allValidChars xs -- process the rest of the string
|
|
||||||
where
|
|
||||||
allValidChars :: String -> Bool
|
|
||||||
allValidChars [] = True -- if we got here, string is valid
|
|
||||||
allValidChars (y:ys)
|
|
||||||
| isAlphaNum y || isSpace y = allValidChars ys -- char is valid, continue
|
|
||||||
| otherwise = False -- found an invalid character, return false
|
|
||||||
|
|
||||||
isValidString :: T.Text -> Bool
|
|
||||||
isValidString c = do
|
|
||||||
let a = T.unpack c
|
|
||||||
isValidContent a
|
|
||||||
|
|
||||||
padWithZero :: Int -> String -> String
|
|
||||||
padWithZero n s
|
|
||||||
| length s >= n = s
|
|
||||||
| otherwise = padWithZero n ("0" ++ s)
|
|
||||||
|
|
||||||
isEmpty :: [a] -> Bool
|
|
||||||
isEmpty [] = True
|
|
||||||
isEmpty _ = False
|
|
||||||
|
|
||||||
getChainTip :: T.Text -> Int -> IO Int
|
|
||||||
getChainTip zHost zPort = do
|
|
||||||
r <- makeZebraCall zHost zPort "getblockcount" []
|
|
||||||
case r of
|
|
||||||
Left e1 -> pure 0
|
|
||||||
Right i -> pure i
|
|
||||||
|
|
||||||
-- Function to fetch Zcash price from CoinGecko
|
|
||||||
getZcashPrice :: T.Text -> IO (Maybe Double)
|
|
||||||
getZcashPrice currency = do
|
|
||||||
let url =
|
|
||||||
"https://api.coingecko.com/api/v3/simple/price?ids=zcash&vs_currencies=" <>
|
|
||||||
T.unpack currency
|
|
||||||
response <- httpJSONEither (parseRequest_ url)
|
|
||||||
case getResponseBody response of
|
|
||||||
Right (Object obj)
|
|
||||||
-- Extract "zcash" object
|
|
||||||
-> do
|
|
||||||
case KM.lookup "zcash" obj of
|
|
||||||
Just (Object zcashObj)
|
|
||||||
-- Extract the currency price
|
|
||||||
->
|
|
||||||
case KM.lookup (K.fromText (T.toLower currency)) zcashObj of
|
|
||||||
Just (Number price) -> return (Just (toRealFloat price))
|
|
||||||
_ -> return Nothing
|
|
||||||
_ -> return Nothing
|
|
||||||
_ -> return Nothing
|
|
||||||
|
|
||||||
-- Parse memo result to convert it to a ByteString
|
|
||||||
processEither :: Either String BC.ByteString -> BC.ByteString
|
|
||||||
processEither (Right bs) = bs
|
|
||||||
processEither (Left e) = BC.pack e -- Returns the error message
|
|
||||||
|
|
||||||
-- Parse the query string into key-value pairs
|
|
||||||
parseQuery :: String -> [(String, String)]
|
|
||||||
parseQuery query = map (breakOn '=') (splitOn '&' query)
|
|
||||||
where
|
|
||||||
splitOn :: Char -> String -> [String]
|
|
||||||
splitOn _ [] = [""]
|
|
||||||
splitOn delim (c:cs)
|
|
||||||
| c == delim = "" : rest
|
|
||||||
| otherwise = (c : head rest) : tail rest
|
|
||||||
where
|
|
||||||
rest = splitOn delim cs
|
|
||||||
breakOn :: Char -> String -> (String, String)
|
|
||||||
breakOn delim str = (key, drop 1 value)
|
|
||||||
where
|
|
||||||
(key, value) = span (/= delim) str
|
|
||||||
|
|
||||||
-- Parse a ZIP-321 encoded string into a ZcashPayment structure
|
|
||||||
parseZcashPayment :: String -> Either String ZcashPaymentURI
|
|
||||||
parseZcashPayment input
|
|
||||||
| not (T.isPrefixOf "zcash:" (T.pack input)) =
|
|
||||||
Left "Invalid scheme: must start with 'zcash:'"
|
|
||||||
| otherwise =
|
|
||||||
let (addrPart, queryPart) = break (== '?') (drop 6 input)
|
|
||||||
queryParams = parseQuery (drop 1 queryPart)
|
|
||||||
in Right
|
|
||||||
ZcashPaymentURI
|
|
||||||
{ uriAddress = addrPart
|
|
||||||
, uriAmount = lookup "amount" queryParams >>= readMaybe
|
|
||||||
, uriMemo =
|
|
||||||
case lookup "memo" queryParams of
|
|
||||||
Just m ->
|
|
||||||
T.pack
|
|
||||||
(BC.unpack
|
|
||||||
(processEither $ decodeBase64Unpadded (BC.pack m)))
|
|
||||||
_ -> ""
|
|
||||||
, uriLabel = lookup "label" queryParams
|
|
||||||
, uriMessage = lookup "message" queryParams
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Function to pad a base64 string if it's not a multiple of 4
|
|
||||||
padBase64 :: BC.ByteString -> BC.ByteString
|
|
||||||
padBase64 bs = bs <> BC.replicate paddingLength '='
|
|
||||||
where
|
|
||||||
paddingLength = (4 - BC.length bs `mod` 4) `mod` 4
|
|
||||||
|
|
||||||
-- Function to decode a base64 un-padded string
|
|
||||||
decodeBase64Unpadded :: BC.ByteString -> Either String BC.ByteString
|
|
||||||
decodeBase64Unpadded = B64.decode . padBase64
|
|
||||||
|
|
||||||
-- Function to encode memo as un-padded Base64
|
|
||||||
encodeBase64Memo :: String -> String
|
|
||||||
encodeBase64Memo = BC.unpack . BC.takeWhile (/= '=') . B64.encode . BC.pack
|
|
||||||
|
|
||||||
-- Function to drop trailing zeros
|
|
||||||
dropTrailingZeros :: String -> String
|
|
||||||
dropTrailingZeros str =
|
|
||||||
let withoutZeros = reverse (dropWhile (== '0') (reverse str))
|
|
||||||
in if last withoutZeros == '.'
|
|
||||||
then withoutZeros ++ "0" -- Ensure at least one decimal place
|
|
||||||
else withoutZeros
|
|
||||||
|
|
||||||
-- Function to create a ZIP-321 URI
|
|
||||||
createZip321 :: String -> Maybe Double -> Maybe String -> String
|
|
||||||
createZip321 address mAmount mMemo =
|
|
||||||
"zcash:" ++
|
|
||||||
address ++
|
|
||||||
maybe
|
|
||||||
""
|
|
||||||
(\amount -> "?amount=" ++ dropTrailingZeros (printf "%.8f" amount))
|
|
||||||
mAmount ++
|
|
||||||
maybe
|
|
||||||
""
|
|
||||||
(\memo -> "&memo=" ++ escapeURIString isUnreserved (encodeBase64Memo memo))
|
|
||||||
mMemo
|
|
||||||
|
|
||||||
getTransparentFromUA :: UnifiedAddress -> Maybe TransparentAddress
|
|
||||||
getTransparentFromUA ua = TransparentAddress (ua_net ua) <$> t_rec ua
|
|
||||||
|
|
||||||
-- Function to check if Text is non-empty after trimming leading spaces
|
|
||||||
isNotEmptyAfterTrim :: T.Text -> Bool
|
|
||||||
isNotEmptyAfterTrim txt = not (T.null (T.stripStart txt))
|
|
||||||
|
|
||||||
-- Function to convert a Scientific number to Int
|
|
||||||
scientificToInt :: Scientific -> Int
|
|
||||||
scientificToInt sc = fromIntegral $ round $ toRealFloat sc
|
|
||||||
|
|
||||||
-- Convert a ByteString to Phrase
|
|
||||||
toPhrase :: BS.ByteString -> Phrase
|
|
||||||
toPhrase = Phrase
|
|
||||||
|
|
|
@ -123,10 +123,9 @@ sendTx user pwd fromAddy toAddy amount memo = do
|
||||||
if source fromAddy /= ImportedWatchOnly
|
if source fromAddy /= ImportedWatchOnly
|
||||||
then do
|
then do
|
||||||
let privacyPolicy
|
let privacyPolicy
|
||||||
| valAdd == Just TransparentPool = "AllowRevealedRecipients"
|
| valAdd == Just Transparent = "AllowRevealedRecipients"
|
||||||
| isNothing (account fromAddy) &&
|
| isNothing (account fromAddy) &&
|
||||||
elem TransparentPool (pool fromAddy) =
|
elem Transparent (pool fromAddy) = "AllowRevealedSenders"
|
||||||
"AllowRevealedSenders"
|
|
||||||
| otherwise = "AllowRevealedAmounts"
|
| otherwise = "AllowRevealedAmounts"
|
||||||
let pd =
|
let pd =
|
||||||
case memo of
|
case memo of
|
||||||
|
@ -302,7 +301,7 @@ sendWithUri user pwd fromAddy uri repTo = do
|
||||||
let addType = validateAddress $ T.pack parsedAddress
|
let addType = validateAddress $ T.pack parsedAddress
|
||||||
case addType of
|
case addType of
|
||||||
Nothing -> putStrLn " Invalid address"
|
Nothing -> putStrLn " Invalid address"
|
||||||
Just TransparentPool -> do
|
Just Transparent -> do
|
||||||
putStrLn $ " Address is valid: " ++ parsedAddress
|
putStrLn $ " Address is valid: " ++ parsedAddress
|
||||||
case (readMaybe parsedAmount :: Maybe Double) of
|
case (readMaybe parsedAmount :: Maybe Double) of
|
||||||
Nothing -> putStrLn " Invalid amount."
|
Nothing -> putStrLn " Invalid amount."
|
||||||
|
|
|
@ -1,964 +0,0 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
import Control.Concurrent (forkIO, threadDelay)
|
|
||||||
import Control.Exception (SomeException, throwIO, try)
|
|
||||||
import Control.Monad (when)
|
|
||||||
import Control.Monad.Logger (runNoLoggingT)
|
|
||||||
import Data.Aeson
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import Data.Configurator
|
|
||||||
import Data.Maybe (fromJust, fromMaybe)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified Data.Text.Encoding as E
|
|
||||||
import Data.Time.Clock (getCurrentTime)
|
|
||||||
import qualified Data.UUID as U
|
|
||||||
import Network.HTTP.Simple
|
|
||||||
import Network.Wai.Handler.Warp (run)
|
|
||||||
import Servant
|
|
||||||
import System.Directory
|
|
||||||
import Test.HUnit hiding (State)
|
|
||||||
import Test.Hspec
|
|
||||||
import ZcashHaskell.Orchard (isValidUnifiedAddress, parseAddress)
|
|
||||||
import ZcashHaskell.Types
|
|
||||||
( ZcashNet(..)
|
|
||||||
, ZebraGetBlockChainInfo(..)
|
|
||||||
, ZebraGetInfo(..)
|
|
||||||
)
|
|
||||||
import Zenith.Core (checkBlockChain, checkZebra)
|
|
||||||
import Zenith.DB (Operation(..), initDb, initPool, saveOperation)
|
|
||||||
import Zenith.RPC
|
|
||||||
( RpcCall(..)
|
|
||||||
, State(..)
|
|
||||||
, ZenithInfo(..)
|
|
||||||
, ZenithMethod(..)
|
|
||||||
, ZenithParams(..)
|
|
||||||
, ZenithRPC(..)
|
|
||||||
, ZenithResponse(..)
|
|
||||||
, authenticate
|
|
||||||
, zenithServer
|
|
||||||
)
|
|
||||||
import Zenith.Types
|
|
||||||
( AccountType(..)
|
|
||||||
, Config(..)
|
|
||||||
, PrivacyPolicy(..)
|
|
||||||
, ProposedNote(..)
|
|
||||||
, ValidAddressAPI(..)
|
|
||||||
, ZcashAccountAPI(..)
|
|
||||||
, ZcashAddressAPI(..)
|
|
||||||
, ZcashWalletAPI(..)
|
|
||||||
, ZenithStatus(..)
|
|
||||||
, ZenithUuid(..)
|
|
||||||
)
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = do
|
|
||||||
config <- load ["$(HOME)/Zenith/zenith.cfg"]
|
|
||||||
let dbFilePath = "test.db"
|
|
||||||
nodeUser <- require config "nodeUser"
|
|
||||||
nodePwd <- require config "nodePwd"
|
|
||||||
zebraPort <- require config "zebraPort"
|
|
||||||
zebraHost <- require config "zebraHost"
|
|
||||||
nodePort <- require config "nodePort"
|
|
||||||
currencyCode <- require config "currencyCode"
|
|
||||||
let myConfig =
|
|
||||||
Config
|
|
||||||
dbFilePath
|
|
||||||
zebraHost
|
|
||||||
zebraPort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
nodePort
|
|
||||||
currencyCode
|
|
||||||
hspec $ do
|
|
||||||
describe "RPC methods" $ do
|
|
||||||
beforeAll_ (startAPI myConfig) $ do
|
|
||||||
describe "getinfo" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetInfo
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
it "correct credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetInfo
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
InfoResponse "zh" (ZenithInfo "0.8.0.0-beta" TestNet "v2.1.0")
|
|
||||||
describe "Wallets" $ do
|
|
||||||
describe "listwallet" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ListWallets
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
it "correct credentials, no wallet" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListWallets
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse
|
|
||||||
"zh"
|
|
||||||
(-32001)
|
|
||||||
"No wallets available. Please create one first"
|
|
||||||
describe "getnewwallet" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetNewWallet
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no params" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewWallet
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe` ErrorResponse "zh" (-32602) "Invalid params"
|
|
||||||
it "Valid params" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewWallet
|
|
||||||
(NameParams "Main")
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r -> r `shouldBe` NewItemResponse "zh" 1
|
|
||||||
it "duplicate name" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewWallet
|
|
||||||
(NameParams "Main")
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse
|
|
||||||
"zh"
|
|
||||||
(-32007)
|
|
||||||
"Entity with that name already exists."
|
|
||||||
describe "listwallet" $ do
|
|
||||||
it "wallet exists" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListWallets
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (WalletListResponse i k) ->
|
|
||||||
zw_name (head k) `shouldBe` "Main"
|
|
||||||
Right _ -> assertFailure "Unexpected response"
|
|
||||||
describe "Accounts" $ do
|
|
||||||
describe "listaccounts" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ListAccounts
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "invalid wallet" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListAccounts
|
|
||||||
(AccountsParams 17)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse "zh" (-32008) "Wallet does not exist."
|
|
||||||
it "valid wallet, no accounts" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListAccounts
|
|
||||||
(AccountsParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse
|
|
||||||
"zh"
|
|
||||||
(-32002)
|
|
||||||
"No accounts available for this wallet. Please create one first"
|
|
||||||
describe "getnewaccount" $ do
|
|
||||||
it "invalid credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetNewAccount
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "invalid wallet" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAccount
|
|
||||||
(NameIdParams "Personal" 17)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse "zh" (-32008) "Wallet does not exist."
|
|
||||||
it "valid wallet" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAccount
|
|
||||||
(NameIdParams "Personal" 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r -> r `shouldBe` NewItemResponse "zh" 1
|
|
||||||
it "valid wallet, duplicate name" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAccount
|
|
||||||
(NameIdParams "Personal" 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse
|
|
||||||
"zh"
|
|
||||||
(-32007)
|
|
||||||
"Entity with that name already exists."
|
|
||||||
describe "listaccounts" $ do
|
|
||||||
it "valid wallet" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListAccounts
|
|
||||||
(AccountsParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
AccountListResponse
|
|
||||||
"zh"
|
|
||||||
[ZcashAccountAPI 1 1 "Personal" Local]
|
|
||||||
describe "Addresses" $ do
|
|
||||||
describe "listaddresses" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ListAddresses
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
it "correct credentials, no addresses" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListAddresses
|
|
||||||
(AddressesParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse
|
|
||||||
"zh"
|
|
||||||
(-32003)
|
|
||||||
"No addresses available for this account. Please create one first"
|
|
||||||
describe "getnewaddress" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetNewAddress
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "invalid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAddress
|
|
||||||
(NewAddrParams 17 "Business" False False)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse "zh" (-32006) "Account does not exist."
|
|
||||||
it "valid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAddress
|
|
||||||
(NewAddrParams 1 "Business" False False)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (NewAddrResponse i a) -> zd_name a `shouldBe` "Business"
|
|
||||||
Right _ -> assertFailure "unexpected response"
|
|
||||||
it "valid account, duplicate name" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAddress
|
|
||||||
(NewAddrParams 1 "Business" False False)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right r ->
|
|
||||||
r `shouldBe`
|
|
||||||
ErrorResponse
|
|
||||||
"zh"
|
|
||||||
(-32007)
|
|
||||||
"Entity with that name already exists."
|
|
||||||
it "valid account, no sapling" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAddress
|
|
||||||
(NewAddrParams 1 "NoSapling" True False)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (NewAddrResponse i a) -> zd_legacy a `shouldBe` Nothing
|
|
||||||
Right _ -> assertFailure "unexpected response"
|
|
||||||
it "valid account, no transparent" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAddress
|
|
||||||
(NewAddrParams 1 "NoTransparent" False True)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (NewAddrResponse i a) ->
|
|
||||||
zd_transparent a `shouldBe` Nothing
|
|
||||||
Right _ -> assertFailure "unexpected response"
|
|
||||||
it "valid account, orchard only" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetNewAddress
|
|
||||||
(NewAddrParams 1 "OrchOnly" True True)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (NewAddrResponse i a) ->
|
|
||||||
a `shouldSatisfy`
|
|
||||||
(\b ->
|
|
||||||
(zd_transparent b == Nothing) && (zd_legacy b == Nothing))
|
|
||||||
Right _ -> assertFailure "unexpected response"
|
|
||||||
describe "listaddresses" $ do
|
|
||||||
it "correct credentials, addresses exist" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListAddresses
|
|
||||||
(AddressesParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (AddressListResponse i a) -> length a `shouldBe` 4
|
|
||||||
describe "Notes" $ do
|
|
||||||
describe "listreceived" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ListReceived
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListReceived
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "unknown index" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListReceived
|
|
||||||
(NotesParams "17")
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32004)
|
|
||||||
describe "Balance" $ do
|
|
||||||
describe "getbalance" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetBalance
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetBalance
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "unknown index" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetBalance
|
|
||||||
(BalanceParams 17)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
describe "Operations" $ do
|
|
||||||
describe "getoperationstatus" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetOperationStatus
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "invalid ID" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetOperationStatus
|
|
||||||
(NameParams "badId")
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "valid ID" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetOperationStatus
|
|
||||||
(OpParams
|
|
||||||
(ZenithUuid $
|
|
||||||
fromMaybe U.nil $
|
|
||||||
U.fromText "bd2aa95a-db51-4cc4-9fea-0f9cf79003a4"))
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (OpResponse i o) ->
|
|
||||||
operationUuid o `shouldBe`
|
|
||||||
(ZenithUuid $
|
|
||||||
fromMaybe U.nil $
|
|
||||||
U.fromText "bd2aa95a-db51-4cc4-9fea-0f9cf79003a4")
|
|
||||||
Right _ -> assertFailure "unexpected response"
|
|
||||||
it "valid ID not found" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetOperationStatus
|
|
||||||
(OpParams
|
|
||||||
(ZenithUuid $
|
|
||||||
fromMaybe U.nil $
|
|
||||||
U.fromText "bd2aa95a-db51-4cc4-9fea-0f9cf79003a5"))
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32009)
|
|
||||||
Right _ -> assertFailure "unexpected response"
|
|
||||||
describe "Send tx" $ do
|
|
||||||
describe "sendmany" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
SendMany
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "invalid account" $ do
|
|
||||||
let uaRead =
|
|
||||||
parseAddress
|
|
||||||
"utest1dl54utt6prjj5e0dnlknwumnxq9hycdjpkfr0sy6e6h522remqee8axe9zax0wsjrwpj76v555pdhvj9rnargpfyycs0vpkapq98xcdhem99gc4wchzn0ggepq3y6nz3a9sscwgqxgsh9vzhcad402y3x9szfregck5gslkya3c79d86xx0l33tpk8gnn7ew9vw37w43zh22u8dgdax"
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
SendMany
|
|
||||||
(SendParams
|
|
||||||
17
|
|
||||||
[ ProposedNote
|
|
||||||
(ValidAddressAPI $ fromJust uaRead)
|
|
||||||
0.005
|
|
||||||
(Just "A cool memo")
|
|
||||||
]
|
|
||||||
Full)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
it "valid account, empty notes" $ do
|
|
||||||
let uaRead =
|
|
||||||
parseAddress
|
|
||||||
"utest1dl54utt6prjj5e0dnlknwumnxq9hycdjpkfr0sy6e6h522remqee8axe9zax0wsjrwpj76v555pdhvj9rnargpfyycs0vpkapq98xcdhem99gc4wchzn0ggepq3y6nz3a9sscwgqxgsh9vzhcad402y3x9szfregck5gslkya3c79d86xx0l33tpk8gnn7ew9vw37w43zh22u8dgdax"
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
SendMany
|
|
||||||
(SendParams 1 [] Full)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "valid account, single output" $ do
|
|
||||||
let uaRead =
|
|
||||||
parseAddress
|
|
||||||
"utest1dl54utt6prjj5e0dnlknwumnxq9hycdjpkfr0sy6e6h522remqee8axe9zax0wsjrwpj76v555pdhvj9rnargpfyycs0vpkapq98xcdhem99gc4wchzn0ggepq3y6nz3a9sscwgqxgsh9vzhcad402y3x9szfregck5gslkya3c79d86xx0l33tpk8gnn7ew9vw37w43zh22u8dgdax"
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
SendMany
|
|
||||||
(SendParams
|
|
||||||
1
|
|
||||||
[ ProposedNote
|
|
||||||
(ValidAddressAPI $ fromJust uaRead)
|
|
||||||
5.0
|
|
||||||
(Just "A cool memo")
|
|
||||||
]
|
|
||||||
Full)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (SendResponse i o) -> o `shouldNotBe` U.nil
|
|
||||||
it "valid account, multiple outputs" $ do
|
|
||||||
let uaRead =
|
|
||||||
parseAddress
|
|
||||||
"utest1dl54utt6prjj5e0dnlknwumnxq9hycdjpkfr0sy6e6h522remqee8axe9zax0wsjrwpj76v555pdhvj9rnargpfyycs0vpkapq98xcdhem99gc4wchzn0ggepq3y6nz3a9sscwgqxgsh9vzhcad402y3x9szfregck5gslkya3c79d86xx0l33tpk8gnn7ew9vw37w43zh22u8dgdax"
|
|
||||||
let uaRead2 =
|
|
||||||
parseAddress
|
|
||||||
"ztestsapling136jp8z89v2jh6kqd5rs4dtvlxym90m43svzdwzxaplyvc5ttzppytpvx80ncllcsqzpmukxjl3y"
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
SendMany
|
|
||||||
(SendParams
|
|
||||||
1
|
|
||||||
[ ProposedNote
|
|
||||||
(ValidAddressAPI $ fromJust uaRead)
|
|
||||||
5.0
|
|
||||||
(Just "A cool memo")
|
|
||||||
, ProposedNote
|
|
||||||
(ValidAddressAPI $ fromJust uaRead2)
|
|
||||||
1.0
|
|
||||||
(Just "Not so cool memo")
|
|
||||||
]
|
|
||||||
Full)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (SendResponse i o) -> o `shouldNotBe` U.nil
|
|
||||||
describe "Shield notes" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ShieldNotes
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ShieldNotes
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "invalid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ShieldNotes
|
|
||||||
(ShieldNotesParams 27)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
it "valid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ShieldNotes
|
|
||||||
(ShieldNotesParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (MultiOpResponse i c) -> c `shouldNotBe` []
|
|
||||||
describe "Viewing Keys" $ do
|
|
||||||
describe "Full" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetFVK
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetFVK
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "invalid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetFVK
|
|
||||||
(ViewingKeyParams 27)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
it "valid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetFVK
|
|
||||||
(ViewingKeyParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ViewingKeyResponse i c) -> c `shouldNotBe` ""
|
|
||||||
Right x -> assertFailure $ show x
|
|
||||||
describe "Incoming" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
GetIVK
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetIVK
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "invalid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetIVK
|
|
||||||
(ViewingKeyParams 27)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32006)
|
|
||||||
it "valid account" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
GetIVK
|
|
||||||
(ViewingKeyParams 1)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ViewingKeyResponse i c) -> c `shouldNotBe` ""
|
|
||||||
Right x -> assertFailure $ show x
|
|
||||||
describe "Importing" $ do
|
|
||||||
it "bad credentials" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
"baduser"
|
|
||||||
"idontknow"
|
|
||||||
ImportVK
|
|
||||||
BlankParams
|
|
||||||
res `shouldBe` Left "Invalid credentials"
|
|
||||||
describe "correct credentials" $ do
|
|
||||||
it "no parameters" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ImportVK
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (ErrorResponse i c m) -> c `shouldBe` (-32602)
|
|
||||||
it "correct params" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ImportVK
|
|
||||||
(ImportVkParams
|
|
||||||
"OldWallet"
|
|
||||||
"uviewtest1jna46ql5qns5rlg99jgs6mhf0j9tk8zxvqsm472scgvmj0vs0rqv2kvdf626gftx7dgn2tltyf0s200gvjlsdvz5celpue9wxxw78txswqmayxc3pfrt5fs5frvr3ep0jrjg8euahqzc63yx9sy4z8lql4ev6q3asptl9rhsfzzrup2g5slwnlvy3dgft44jw3l08xtzypjmsrwxskgnp5s03xlc2kg5520a25pa6fdjxhzutam4wkwr6mh4zeq3qndpks8dk0y90y7gucgsp0j5k2xnhh90m3krk5glz4794dj93pf59h85dqms6337f85ccvpxhays94kvsj2hyjsltf52tygqs8y0vp2yf39drxl687the6xkp8nxkfffc3kqlkhw53t5plplde0vk9rwv340ys04gg48fs0pxfp35rvt2f2pvxjmgmln6lp5k2yzkm0r87k89p6xqv68a6uyfpsauswh9fsckfqey02pjedz5gs934qa"
|
|
||||||
3249286)
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (NewItemResponse i k) -> k `shouldSatisfy` (> 0)
|
|
||||||
it "list wallets" $ do
|
|
||||||
res <-
|
|
||||||
makeZenithCall
|
|
||||||
"127.0.0.1"
|
|
||||||
nodePort
|
|
||||||
nodeUser
|
|
||||||
nodePwd
|
|
||||||
ListWallets
|
|
||||||
BlankParams
|
|
||||||
case res of
|
|
||||||
Left e -> assertFailure e
|
|
||||||
Right (WalletListResponse i k) -> length k `shouldBe` 2
|
|
||||||
|
|
||||||
startAPI :: Config -> IO ()
|
|
||||||
startAPI config = do
|
|
||||||
putStrLn "Starting test RPC server"
|
|
||||||
checkDbFile <- doesFileExist "test.db"
|
|
||||||
when checkDbFile $ removeFile "test.db"
|
|
||||||
let ctx = authenticate config :. EmptyContext
|
|
||||||
w <-
|
|
||||||
try $ checkZebra (c_zebraHost config) (c_zebraPort config) :: IO
|
|
||||||
(Either IOError ZebraGetInfo)
|
|
||||||
case w of
|
|
||||||
Right zebra -> do
|
|
||||||
bc <-
|
|
||||||
try $ checkBlockChain (c_zebraHost config) (c_zebraPort config) :: IO
|
|
||||||
(Either IOError ZebraGetBlockChainInfo)
|
|
||||||
case bc of
|
|
||||||
Left e1 -> throwIO e1
|
|
||||||
Right chainInfo -> do
|
|
||||||
x <- runNoLoggingT $ initDb "test.db"
|
|
||||||
case x of
|
|
||||||
Left e2 -> throwIO $ userError e2
|
|
||||||
Right x' -> do
|
|
||||||
pool <- runNoLoggingT $ initPool "test.db"
|
|
||||||
ts <- getCurrentTime
|
|
||||||
y <-
|
|
||||||
saveOperation
|
|
||||||
pool
|
|
||||||
(Operation
|
|
||||||
(ZenithUuid $
|
|
||||||
fromMaybe U.nil $
|
|
||||||
U.fromText "bd2aa95a-db51-4cc4-9fea-0f9cf79003a4")
|
|
||||||
ts
|
|
||||||
Nothing
|
|
||||||
Processing
|
|
||||||
Nothing)
|
|
||||||
let myState =
|
|
||||||
State
|
|
||||||
(zgb_net chainInfo)
|
|
||||||
(c_zebraHost config)
|
|
||||||
(c_zebraPort config)
|
|
||||||
"test.db"
|
|
||||||
(zgi_build zebra)
|
|
||||||
(zgb_blocks chainInfo)
|
|
||||||
forkIO $
|
|
||||||
run (c_zenithPort config) $
|
|
||||||
serveWithContext
|
|
||||||
(Servant.Proxy :: Servant.Proxy ZenithRPC)
|
|
||||||
ctx
|
|
||||||
(zenithServer myState)
|
|
||||||
threadDelay 1000000
|
|
||||||
putStrLn "Test server is up!"
|
|
||||||
|
|
||||||
-- | Make a Zebra RPC call
|
|
||||||
makeZenithCall ::
|
|
||||||
T.Text -- ^ Hostname for `zebrad`
|
|
||||||
-> Int -- ^ Port for `zebrad`
|
|
||||||
-> BS.ByteString
|
|
||||||
-> BS.ByteString
|
|
||||||
-> ZenithMethod -- ^ RPC method to call
|
|
||||||
-> ZenithParams -- ^ List of parameters
|
|
||||||
-> IO (Either String ZenithResponse)
|
|
||||||
makeZenithCall host port usr pwd m params = do
|
|
||||||
let payload = RpcCall "2.0" "zh" m params
|
|
||||||
let myRequest =
|
|
||||||
setRequestBodyJSON payload $
|
|
||||||
setRequestPort port $
|
|
||||||
setRequestHost (E.encodeUtf8 host) $
|
|
||||||
setRequestBasicAuth usr pwd $ setRequestMethod "POST" defaultRequest
|
|
||||||
r <- httpJSONEither myRequest
|
|
||||||
case getResponseStatusCode r of
|
|
||||||
403 -> return $ Left "Invalid credentials"
|
|
||||||
200 ->
|
|
||||||
case getResponseBody r of
|
|
||||||
Left e -> return $ Left $ show e
|
|
||||||
Right r' -> return $ Right r'
|
|
||||||
e -> return $ Left $ show e ++ show (getResponseBody r)
|
|
1055
test/Spec.hs
1055
test/Spec.hs
File diff suppressed because it is too large
Load diff
|
@ -1 +1 @@
|
||||||
Subproject commit 0d042d639d471af14ebe94707f64b5ff5c2cb5eb
|
Subproject commit 90c8a7c3028bd6836dea5655221277a25d457653
|
1166
zenith-openrpc.json
1166
zenith-openrpc.json
File diff suppressed because it is too large
Load diff
85
zenith.cabal
85
zenith.cabal
|
@ -1,6 +1,6 @@
|
||||||
cabal-version: 3.0
|
cabal-version: 3.0
|
||||||
name: zenith
|
name: zenith
|
||||||
version: 0.9.1.0-beta
|
version: 0.5.2.0-beta
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Rene Vergara
|
author: Rene Vergara
|
||||||
|
@ -27,40 +27,32 @@ library
|
||||||
ghc-options: -Wall -Wunused-imports
|
ghc-options: -Wall -Wunused-imports
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Zenith.CLI
|
Zenith.CLI
|
||||||
Zenith.GUI
|
|
||||||
Zenith.GUI.Theme
|
|
||||||
Zenith.Core
|
Zenith.Core
|
||||||
Zenith.DB
|
Zenith.DB
|
||||||
Zenith.Types
|
Zenith.Types
|
||||||
Zenith.Utils
|
Zenith.Utils
|
||||||
Zenith.Zcashd
|
Zenith.Zcashd
|
||||||
Zenith.Scanner
|
Zenith.Scanner
|
||||||
Zenith.RPC
|
|
||||||
Zenith.Tree
|
|
||||||
hs-source-dirs:
|
hs-source-dirs:
|
||||||
src
|
src
|
||||||
build-depends:
|
build-depends:
|
||||||
Clipboard
|
Clipboard
|
||||||
, Hclip
|
|
||||||
, JuicyPixels
|
|
||||||
, aeson
|
, aeson
|
||||||
, array
|
, array
|
||||||
, ascii-progress
|
, ascii-progress
|
||||||
, async
|
|
||||||
, base >=4.12 && <5
|
, base >=4.12 && <5
|
||||||
, base64-bytestring
|
, base64-bytestring
|
||||||
, binary
|
|
||||||
, borsh
|
|
||||||
, brick
|
, brick
|
||||||
, bytestring
|
, bytestring
|
||||||
, configurator
|
|
||||||
, data-default
|
|
||||||
, directory
|
|
||||||
, esqueleto
|
, esqueleto
|
||||||
|
, resource-pool
|
||||||
|
, binary
|
||||||
, exceptions
|
, exceptions
|
||||||
, filepath
|
, monad-logger
|
||||||
|
, vty-crossplatform
|
||||||
|
, secp256k1-haskell
|
||||||
|
, pureMD5
|
||||||
, ghc
|
, ghc
|
||||||
, generics-sop
|
|
||||||
, haskoin-core
|
, haskoin-core
|
||||||
, hexstring
|
, hexstring
|
||||||
, http-client
|
, http-client
|
||||||
|
@ -69,35 +61,22 @@ library
|
||||||
, microlens
|
, microlens
|
||||||
, microlens-mtl
|
, microlens-mtl
|
||||||
, microlens-th
|
, microlens-th
|
||||||
, monad-logger
|
|
||||||
, transformers
|
|
||||||
, monomer
|
|
||||||
, mtl
|
, mtl
|
||||||
, persistent
|
, persistent
|
||||||
|
, Hclip
|
||||||
, persistent-sqlite
|
, persistent-sqlite
|
||||||
, persistent-template
|
, persistent-template
|
||||||
, process
|
, process
|
||||||
, pureMD5
|
|
||||||
, qrcode-core
|
|
||||||
, qrcode-juicypixels
|
|
||||||
, regex-base
|
, regex-base
|
||||||
, regex-compat
|
, regex-compat
|
||||||
, regex-posix
|
, regex-posix
|
||||||
, resource-pool
|
|
||||||
, scientific
|
, scientific
|
||||||
, secp256k1-haskell >= 1
|
|
||||||
, servant-server
|
|
||||||
, text
|
, text
|
||||||
, text-show
|
|
||||||
, time
|
, time
|
||||||
, uuid
|
|
||||||
, vector
|
, vector
|
||||||
, vty
|
, vty
|
||||||
, vty-crossplatform
|
|
||||||
, word-wrap
|
, word-wrap
|
||||||
, zcash-haskell
|
, zcash-haskell
|
||||||
, unordered-containers
|
|
||||||
, network-uri
|
|
||||||
--pkgconfig-depends: rustzcash_wrapper
|
--pkgconfig-depends: rustzcash_wrapper
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
@ -113,7 +92,7 @@ executable zenith
|
||||||
, configurator
|
, configurator
|
||||||
, data-default
|
, data-default
|
||||||
, sort
|
, sort
|
||||||
--, structured-cli
|
, structured-cli
|
||||||
, text
|
, text
|
||||||
, time
|
, time
|
||||||
, zenith
|
, zenith
|
||||||
|
@ -121,21 +100,15 @@ executable zenith
|
||||||
pkgconfig-depends: rustzcash_wrapper
|
pkgconfig-depends: rustzcash_wrapper
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
executable zenithserver
|
executable zenscan
|
||||||
ghc-options: -main-is Server -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -main-is ZenScan -threaded -rtsopts -with-rtsopts=-N
|
||||||
main-is: Server.hs
|
main-is: ZenScan.hs
|
||||||
hs-source-dirs:
|
hs-source-dirs:
|
||||||
app
|
app
|
||||||
build-depends:
|
build-depends:
|
||||||
base >=4.12 && <5
|
base >=4.12 && <5
|
||||||
, configurator
|
, configurator
|
||||||
, monad-logger
|
, monad-logger
|
||||||
, wai-extra
|
|
||||||
, warp
|
|
||||||
, servant-server
|
|
||||||
, text
|
|
||||||
, unix
|
|
||||||
, zcash-haskell
|
|
||||||
, zenith
|
, zenith
|
||||||
pkgconfig-depends: rustzcash_wrapper
|
pkgconfig-depends: rustzcash_wrapper
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
@ -149,11 +122,8 @@ test-suite zenith-tests
|
||||||
build-depends:
|
build-depends:
|
||||||
base >=4.12 && <5
|
base >=4.12 && <5
|
||||||
, bytestring
|
, bytestring
|
||||||
, aeson
|
|
||||||
, configurator
|
, configurator
|
||||||
, monad-logger
|
, monad-logger
|
||||||
, borsh
|
|
||||||
, aeson
|
|
||||||
, data-default
|
, data-default
|
||||||
, sort
|
, sort
|
||||||
, text
|
, text
|
||||||
|
@ -168,34 +138,3 @@ test-suite zenith-tests
|
||||||
, zenith
|
, zenith
|
||||||
pkgconfig-depends: rustzcash_wrapper
|
pkgconfig-depends: rustzcash_wrapper
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
test-suite zenithserver-tests
|
|
||||||
type: exitcode-stdio-1.0
|
|
||||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
|
||||||
main-is: ServerSpec.hs
|
|
||||||
hs-source-dirs:
|
|
||||||
test
|
|
||||||
build-depends:
|
|
||||||
base >=4.12 && <5
|
|
||||||
, bytestring
|
|
||||||
, aeson
|
|
||||||
, configurator
|
|
||||||
, monad-logger
|
|
||||||
, data-default
|
|
||||||
, sort
|
|
||||||
, text
|
|
||||||
, time
|
|
||||||
, uuid
|
|
||||||
, http-conduit
|
|
||||||
, persistent
|
|
||||||
, persistent-sqlite
|
|
||||||
, hspec
|
|
||||||
, hexstring
|
|
||||||
, warp
|
|
||||||
, servant-server
|
|
||||||
, HUnit
|
|
||||||
, directory
|
|
||||||
, zcash-haskell
|
|
||||||
, zenith
|
|
||||||
pkgconfig-depends: rustzcash_wrapper
|
|
||||||
default-language: Haskell2010
|
|
||||||
|
|
41
zenith.cfg
41
zenith.cfg
|
@ -1,42 +1,5 @@
|
||||||
#
|
|
||||||
# Zenith Configuration File
|
|
||||||
#
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# nodeUser -
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
nodeUser = "user"
|
nodeUser = "user"
|
||||||
# -------------------------------------------------------------
|
|
||||||
# nodePwd -
|
|
||||||
nodePwd = "superSecret"
|
nodePwd = "superSecret"
|
||||||
# -------------------------------------------------------------
|
dbFilePath = "zenith.db"
|
||||||
# nodePort -
|
|
||||||
nodePort = 8234
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# nodePwd -
|
|
||||||
# dbFileName - contains the SQLite database name used for
|
|
||||||
# keeping all Zenith's data
|
|
||||||
# default = zenith.db
|
|
||||||
#
|
|
||||||
dbFileName = "zenith.db"
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# zebraHost - Zebra IP
|
|
||||||
# Default - "127.0.0.1"
|
|
||||||
zebraHost = "127.0.0.1"
|
zebraHost = "127.0.0.1"
|
||||||
# -------------------------------------------------------------
|
zebraPort = 18232
|
||||||
# zebraPort - Port used for access Zebra API endpoints
|
|
||||||
# must be the same port configured for your
|
|
||||||
# Zebra node
|
|
||||||
zebraPort = 8232
|
|
||||||
# -------------------------------------------------------------
|
|
||||||
# currencyCode - ISO 4217 currency code
|
|
||||||
#
|
|
||||||
# Example of currency codes are:
|
|
||||||
#
|
|
||||||
# United States -> currencyCode = "usd"
|
|
||||||
# Canada -> currencyCode = "cnd"
|
|
||||||
# Australia -> currencyCode = "aud"
|
|
||||||
# Euro Region -> currencyCode = "eur"
|
|
||||||
# Great Britain -> currencyCode = "gbp"
|
|
||||||
# Japan -> currencyCode = "jpy"
|
|
||||||
#
|
|
||||||
currencyCode = "usd"
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue