diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f041b4..30d4a3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.1.0-beta] + +### Changed + +- Removed workaround to obtain block time + ## [0.7.0.0-beta] ### Added diff --git a/app/Server.hs b/app/Server.hs index 7944fe3..e18e47c 100644 --- a/app/Server.hs +++ b/app/Server.hs @@ -67,7 +67,7 @@ main = do zebraPort (zgb_net chainInfo) threadDelay 90000000 - putStrLn "Zenith RPC Server 0.7.0.0-beta" + putStrLn "Zenith RPC Server 0.8.0.0-beta" putStrLn "------------------------------" putStrLn $ "Connected to " ++ diff --git a/cabal.project.freeze b/cabal.project.freeze index b836f57..34022e4 100644 --- a/cabal.project.freeze +++ b/cabal.project.freeze @@ -9,19 +9,18 @@ constraints: any.Cabal ==3.10.3.0, any.OneTuple ==0.4.2, any.OpenGLRaw ==3.3.4.1, OpenGLRaw -osandroid +usegles2 +useglxgetprocaddress +usenativewindowslibraries, - any.QuickCheck ==2.14.3, + 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.10.3, - X11 -pedantic, + 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.1, + any.ansi-terminal ==1.1.2, ansi-terminal -example, any.ansi-terminal-types ==1.1, any.appar ==0.1.8, @@ -39,11 +38,11 @@ constraints: any.Cabal ==3.10.3.0, attoparsec -developer, any.attoparsec-aeson ==2.2.2.0, any.authenticate-oauth ==1.7, - any.auto-update ==0.2.1, + any.auto-update ==0.2.4, any.base ==4.18.2.1, - any.base-compat ==0.13.1, - any.base-compat-batteries ==0.13.1, - any.base-orphans ==0.9.2, + 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, @@ -62,18 +61,16 @@ constraints: any.Cabal ==3.10.3.0, any.boring ==0.2.2, boring +tagged, any.borsh ==0.3.0, - any.brick ==2.4, + any.brick ==2.6, brick -demos, any.bsb-http-chunked ==0.0.0.4, any.byteorder ==1.0.4, - any.bytes ==0.17.3, + any.bytes ==0.17.4, any.bytestring ==0.11.5.3, - any.bytestring-builder ==0.10.8.2.0, - bytestring-builder +bytestring_has_builder, any.bytestring-to-vector ==0.3.0.1, any.c2hs ==0.28.8, c2hs +base3 -regression, - any.cabal-doctest ==1.0.10, + 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, @@ -84,10 +81,10 @@ constraints: any.Cabal ==3.10.3.0, any.clock ==0.8.4, clock -llvm, any.colour ==2.3.6, - any.comonad ==5.0.8, + any.comonad ==5.0.9, comonad +containers +distributive +indexed-traversable, any.concurrent-output ==1.10.21, - any.conduit ==1.3.5, + any.conduit ==1.3.6, any.conduit-extra ==1.3.6, any.config-ini ==0.2.7.0, config-ini -enable-doctests, @@ -101,21 +98,20 @@ constraints: any.Cabal ==3.10.3.0, any.crypto-api ==0.13.3, crypto-api -all_cpolys, any.crypto-pubkey-types ==0.4.3, - any.crypton ==1.0.0, + 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.1, + 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.12, + 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.7.1.1, - any.data-default-class ==0.1.2.0, - any.data-default-instances-containers ==0.0.1, - any.data-default-instances-dlist ==0.0.1, - any.data-default-instances-old-locale ==0.0.1, + 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, @@ -129,11 +125,11 @@ constraints: any.Cabal ==3.10.3.0, any.easy-file ==0.2.5, any.entropy ==0.4.1.10, entropy -donotgetentropy, - any.envy ==2.1.3.0, - any.esqueleto ==3.5.11.2, + any.envy ==2.1.4.0, + any.esqueleto ==3.5.13.1, any.exceptions ==0.10.7, - any.extra ==1.7.16, - any.fast-logger ==3.2.3, + 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, @@ -142,8 +138,6 @@ constraints: any.Cabal ==3.10.3.0, any.formatting ==7.2.0, formatting -no-double-conversion, any.free ==5.2, - any.generic-deriving ==1.14.5, - generic-deriving +base-4-9, any.generically ==0.1.1, any.generics-sop ==0.5.1.4, any.ghc ==9.6.5, @@ -153,33 +147,34 @@ constraints: any.Cabal ==3.10.3.0, any.ghc-heap ==9.6.5, any.ghc-prim ==0.10.0, any.ghci ==9.6.5, - any.half ==0.3.1, - any.happy ==1.20.1.1, + 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.1, + 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.9, - any.hspec-core ==2.11.9, - any.hspec-discover ==2.11.9, + 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.3, - any.http-conduit ==2.3.8.3, + 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.1.2, + any.http-semantics ==0.3.0, any.http-types ==0.12.4, - any.http2 ==5.2.6, + any.http2 ==5.3.9, http2 -devel -h2spec, any.indexed-traversable ==0.1.4, any.indexed-traversable-instances ==0.1.2, @@ -187,19 +182,19 @@ constraints: any.Cabal ==3.10.3.0, any.integer-gmp ==1.1, any.integer-logarithms ==1.0.3.1, integer-logarithms -check-bounds +integer-gmp, - any.invariant ==0.6.3, - any.iproute ==1.7.12, + any.invariant ==0.6.4, + any.iproute ==1.7.15, any.kan-extensions ==5.2.6, - any.language-c ==0.9.3, - language-c -allwarnings +iecfpextension +usebytestrings, + 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.1.1, + 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.6.1, + any.megaparsec ==9.7.0, megaparsec -dev, any.memory ==0.18.0, memory +support_bytestring +support_deepseq, @@ -213,30 +208,31 @@ constraints: any.Cabal ==3.10.3.0, monad-logger +template_haskell, any.monad-loops ==0.4.3, monad-loops +base4, - any.mono-traversable ==1.0.17.0, + 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.1.0, + any.network ==3.2.7.0, network -devel, any.network-byte-order ==0.1.7, - any.network-control ==0.1.1, + 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.6, + 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.1, + 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, @@ -250,13 +246,13 @@ constraints: any.Cabal ==3.10.3.0, any.psqueues ==0.2.8.0, any.pureMD5 ==2.1.4, pureMD5 -test, - any.qrcode-core ==0.9.9, - any.qrcode-juicypixels ==0.8.5, + 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.8, + any.reflection ==2.1.9, reflection -slow +template-haskell, any.regex-base ==0.94.0.2, any.regex-compat ==0.95.2.1, @@ -271,7 +267,7 @@ constraints: any.Cabal ==3.10.3.0, scientific -integer-simple, any.sdl2 ==2.5.5.0, sdl2 -examples -no-linear -opengl-example +pkgconfig +recent-ish, - any.secp256k1-haskell ==1.2.0, + any.secp256k1-haskell ==1.4.2, any.semialign ==1.3.1, semialign +semigroupoids, any.semigroupoids ==6.0.1, @@ -280,9 +276,9 @@ constraints: any.Cabal ==3.10.3.0, 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.1, - any.servant-server ==0.20, - any.silently ==1.2.5.3, + 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, @@ -301,8 +297,10 @@ constraints: any.Cabal ==3.10.3.0, any.strict ==0.5.1, any.string-conversions ==0.4.0.1, any.system-cxx-std-lib ==1.0, - any.tagged ==0.8.8, + 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, @@ -310,42 +308,43 @@ constraints: any.Cabal ==3.10.3.0, any.text-iso8601 ==0.1.1, any.text-short ==0.1.6, text-short -asserts, - any.text-show ==3.10.5, - text-show +base-4-9 +integer-gmp +new-functor-classes +template-haskell-2-11, + any.text-show ==3.11, + text-show +integer-gmp, any.text-zipper ==0.13, any.tf-random ==0.5, - any.th-abstraction ==0.7.0.0, - any.th-compat ==0.1.5, - any.th-lift ==0.8.4, + 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.1.0, - any.tls ==2.1.0, + 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.11.1, + any.typed-process ==0.2.12.0, any.unix ==2.8.4.0, - any.unix-compat ==0.7.2, - any.unix-time ==0.4.15, + 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.1.0, + any.vector ==0.13.2.0, vector +boundschecks -internalchecks -unsafechecks -wall, - any.vector-algorithms ==0.9.0.2, + 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, @@ -357,10 +356,10 @@ constraints: any.Cabal ==3.10.3.0, any.wai ==3.2.4, any.wai-app-static ==3.1.9, wai-app-static +crypton -print, - any.wai-extra ==3.1.15, + any.wai-extra ==3.1.17, wai-extra -build-example, - any.wai-logger ==2.4.0, - any.warp ==3.4.1, + 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, @@ -370,4 +369,4 @@ constraints: any.Cabal ==3.10.3.0, 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-07-10T18:40:26Z +index-state: hackage.haskell.org 2024-12-14T09:52:48Z diff --git a/sapling-output.params b/sapling-output.params deleted file mode 100644 index 01760fa..0000000 Binary files a/sapling-output.params and /dev/null differ diff --git a/sapling-spend.params b/sapling-spend.params deleted file mode 100644 index b91cd77..0000000 Binary files a/sapling-spend.params and /dev/null differ diff --git a/src/Zenith/CLI.hs b/src/Zenith/CLI.hs index c2fa1a7..29157c1 100644 --- a/src/Zenith/CLI.hs +++ b/src/Zenith/CLI.hs @@ -79,6 +79,7 @@ import Data.Scientific (Scientific, scientific) import qualified Data.Text as T import qualified Data.Text.Encoding as E import Data.Time.Clock.POSIX (posixSecondsToUTCTime) +import qualified Data.UUID as U import qualified Data.Vector as Vec import Database.Persist import Database.Persist.Sqlite @@ -116,6 +117,7 @@ import Zenith.Types , ValidAddressAPI(..) , ZcashNetDB(..) , ZenithStatus(..) + , ZenithUuid(..) ) import Zenith.Utils ( displayTaz @@ -528,7 +530,7 @@ drawUI s = [splashDialog s, helpDialog s, displayDialog s, inputDialog s, ui s] (str " _____ _ _ _ \n|__ /___ _ __ (_) |_| |__\n / // _ \\ '_ \\| | __| '_ \\\n / /| __/ | | | | |_| | | |\n/____\\___|_| |_|_|\\__|_| |_|") <=> C.hCenter - (withAttr titleAttr (str "Zcash Wallet v0.7.0.0-beta")) <=> + (withAttr titleAttr (str "Zcash Wallet v0.7.1.0-beta")) <=> C.hCenter (withAttr blinkAttr $ str "Press any key...")) else emptyWidget capCommand3 :: String -> String -> String -> Widget Name @@ -778,8 +780,8 @@ listDrawTx znet sel tx = else displayTaz amt fmtAmt = if amt > 0 - then "↘" <> dispAmount <> " " - else " " <> dispAmount <> "↗" + then "↘ " <> dispAmount <> " " + else " " <> dispAmount <> "↗ " selStr s = if sel then withAttr customAttr (txt $ "> " <> s) @@ -894,29 +896,16 @@ scanZebra dbP zHost zPort b eChan znet = do _ <- liftIO $ completeSync pool Failed liftIO $ BC.writeBChan eChan $ TickMsg e1 Right blk -> do - r2 <- - liftIO $ - makeZebraCall - zHost - zPort - "getblock" - [Data.Aeson.String $ T.pack $ show bl, jsonNumber 0] - case r2 of - Left e2 -> do - _ <- liftIO $ completeSync pool Failed - liftIO $ BC.writeBChan eChan $ TickMsg e2 - Right hb -> do - let blockTime = getBlockTime hb - bi <- - saveBlock pool $ - ZcashBlock - (fromIntegral $ bl_height blk) - (HexStringDB $ bl_hash blk) - (fromIntegral $ bl_confirmations blk) - blockTime - (ZcashNetDB znet) - mapM_ (processTx zHost zPort bi pool) $ bl_txs blk - liftIO $ BC.writeBChan eChan $ TickVal step + bi <- + saveBlock pool $ + ZcashBlock + (fromIntegral $ bl_height blk) + (HexStringDB $ bl_hash blk) + (fromIntegral $ bl_confirmations blk) + (fromIntegral $ bl_time blk) + (ZcashNetDB znet) + mapM_ (processTx zHost zPort bi pool) $ bl_txs blk + liftIO $ BC.writeBChan eChan $ TickVal step appEvent :: BT.BrickEvent Name Tick -> BT.EventM Name State () appEvent (BT.AppEvent t) = do @@ -1296,45 +1285,23 @@ appEvent (BT.VtyEvent e) = do Just (_j, w1) -> return w1 Just (_k, w) -> return w fs1 <- BT.zoom deshieldForm $ BT.gets formState - let tAddrMaybe = - Transparent <$> - ((decodeTransparentAddress . - E.encodeUtf8 . - encodeTransparentReceiver (s ^. network)) =<< - (t_rec =<< - (isValidUnifiedAddress . - E.encodeUtf8 . - getUA . walletAddressUAddress) - (entityVal selAddr))) bl <- liftIO $ getChainTip (s ^. zebraHost) (s ^. zebraPort) - case tAddrMaybe of - Nothing -> do - BT.modify $ - set - msg - "Failed to obtain transparent address" - BT.modify $ set displayBox MsgDisplay - BT.modify $ set dialogBox Blank - Just tAddr -> do - _ <- - liftIO $ - forkIO $ - deshieldTransaction - pool - (s ^. eventDispatch) - (s ^. zebraHost) - (s ^. zebraPort) - (s ^. network) - (entityKey selAcc) - bl - (ProposedNote - (ValidAddressAPI tAddr) - (fs1 ^. shAmt) - Nothing) - BT.modify $ set displayBox SendDisplay - BT.modify $ set dialogBox Blank + _ <- + liftIO $ + forkIO $ + deshieldTransaction + pool + (s ^. eventDispatch) + (s ^. zebraHost) + (s ^. zebraPort) + (s ^. network) + (entityKey selAcc) + bl + (fs1 ^. shAmt) + BT.modify $ set displayBox SendDisplay + BT.modify $ set dialogBox Blank else do BT.modify $ set msg "Invalid inputs" BT.modify $ set displayBox MsgDisplay @@ -2063,19 +2030,20 @@ shieldTransaction :: shieldTransaction pool chan zHost zPort znet accId bl = do BC.writeBChan chan $ TickMsg "Preparing shielding transaction..." res <- runNoLoggingT $ shieldTransparentNotes pool zHost zPort znet accId bl - forM_ res $ \case - Left e -> BC.writeBChan chan $ TickMsg $ show e - Right rawTx -> do - BC.writeBChan chan $ TickMsg "Transaction ready, sending to Zebra..." - resp <- - makeZebraCall - zHost - zPort - "sendrawtransaction" - [Data.Aeson.String $ toText rawTx] - case resp of - Left e1 -> BC.writeBChan chan $ TickMsg $ "Zebra error: " ++ show e1 - Right txId -> BC.writeBChan chan $ TickTx txId + ops <- + mapM + (\case + Left e -> return $ T.pack $ show e + Right x -> do + thisOp <- getOperation pool x + case thisOp of + Nothing -> return "" + Just o -> + return $ + (U.toText . getUuid . operationUuid $ entityVal o) <> + ": " <> (T.pack . show . operationStatus $ entityVal o)) + res + BC.writeBChan chan $ TickMsg $ T.unpack $ T.intercalate "\n" ops deshieldTransaction :: ConnectionPool @@ -2085,7 +2053,7 @@ deshieldTransaction :: -> ZcashNet -> ZcashAccountId -> Int - -> ProposedNote + -> Scientific -> IO () deshieldTransaction pool chan zHost zPort znet accId bl pnote = do BC.writeBChan chan $ TickMsg "Deshielding funds..." diff --git a/src/Zenith/Core.hs b/src/Zenith/Core.hs index 835a00d..5d26696 100644 --- a/src/Zenith/Core.hs +++ b/src/Zenith/Core.hs @@ -3,6 +3,7 @@ -- | Core wallet functionality for Zenith module Zenith.Core where +import Control.Concurrent (forkIO) import Control.Exception (throwIO, try) import Control.Monad (forM, unless, when) import Control.Monad.IO.Class (liftIO) @@ -25,6 +26,8 @@ import Data.Scientific (Scientific, scientific, toBoundedInteger) import qualified Data.Text as T import qualified Data.Text.Encoding as E import Data.Time +import qualified Data.UUID as U +import Data.UUID.V4 (nextRandom) import qualified Database.Esqueleto.Experimental as ESQ import Database.Persist import Database.Persist.Sqlite @@ -41,6 +44,7 @@ import ZcashHaskell.Orchard , getOrchardTreeParts , getOrchardWitness , isValidUnifiedAddress + , parseAddress , updateOrchardCommitmentTree , updateOrchardWitness ) @@ -80,7 +84,10 @@ import Zenith.Types , ValidAddressAPI(..) , ZcashNetDB(..) , ZebraTreeInfo(..) + , ZenithStatus(..) + , ZenithUuid(..) ) +import Zenith.Utils (getTransparentFromUA) -- * Zebra Node interaction -- | Checks the status of the `zebrad` node @@ -746,14 +753,37 @@ deshieldNotes :: -> ZcashNet -> ZcashAccountId -> Int - -> ProposedNote + -> Scientific -> NoLoggingT IO (Either TxError HexString) deshieldNotes pool zebraHost zebraPort znet za bh pnote = do bal <- liftIO $ getShieldedBalance pool za - let zats = pn_amt pnote * scientific 1 8 - if fromInteger bal > (scientific 2 4 + zats) - then prepareTxV2 pool zebraHost zebraPort znet za bh [pnote] Low - else return $ Left InsufficientFunds + addrs <- getAddresses pool za + let defAddr = + parseAddress $ + E.encodeUtf8 $ getUA $ walletAddressUAddress $ entityVal $ head addrs + case defAddr of + Nothing -> return $ Left ZHError + Just (Unified x) -> do + case getTransparentFromUA x of + Nothing -> return $ Left ZHError + Just ta -> do + let zats = pnote * scientific 1 8 + if fromInteger bal > (scientific 2 4 + zats) + then prepareTxV2 + pool + zebraHost + zebraPort + znet + za + bh + [ ProposedNote + (ValidAddressAPI $ Transparent ta) + pnote + Nothing + ] + Low + else return $ Left InsufficientFunds + _anyOther -> return $ Left ZHError shieldTransparentNotes :: ConnectionPool @@ -762,8 +792,8 @@ shieldTransparentNotes :: -> ZcashNet -> ZcashAccountId -> Int - -> NoLoggingT IO [Either TxError HexString] -shieldTransparentNotes pool zebraHost zebraPort znet za bh = do + -> NoLoggingT IO [Either TxError U.UUID] +shieldTransparentNotes pool zHost zPort znet za bh = do accRead <- liftIO $ getAccountById pool za logDebugN $ T.pack $ "Target block: " ++ show bh case accRead of @@ -772,58 +802,94 @@ shieldTransparentNotes pool zebraHost zebraPort znet za bh = do return [Left ZHError] Just acc -> do trNotes' <- liftIO $ getWalletUnspentTrNotes pool za - dRecvs <- liftIO $ getReceivers pool trNotes' - let fNotes = - map - (\x -> - filter (\y -> walletTrNoteAddress (entityVal y) == x) trNotes') - dRecvs - sTree <- liftIO $ getSaplingTree pool - oTree <- liftIO $ getOrchardTree pool - forM fNotes $ \trNotes -> do - let noteTotal = getTotalAmount (trNotes, [], []) - tSpends <- - liftIO $ - prepTSpends - (getTranSK $ zcashAccountTPrivateKey $ entityVal acc) - trNotes - chgAddr <- getInternalAddresses pool $ entityKey acc - let internalUA = - getUA $ walletAddressUAddress $ entityVal $ head chgAddr - let oRcvr = - fromJust $ - o_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA) - let dummy = - OutgoingNote - 4 - (getBytes $ getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc) - (getBytes oRcvr) - (fromIntegral $ noteTotal - 500) - "" - True - let feeAmt = calculateTxFee (trNotes, [], []) [dummy] - let snote = - OutgoingNote - 4 - (getBytes $ getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc) - (getBytes oRcvr) - (fromIntegral $ noteTotal - fromIntegral feeAmt) - "" - True - tx <- - liftIO $ - createTransaction - (maybe (hexString "00") (getHash . value . fst) sTree) - (maybe (hexString "00") (getHash . value . fst) oTree) - tSpends - [] - [] - [snote] - znet - (bh + 3) - True - logDebugN $ T.pack $ show tx - return tx + if null trNotes' + then return [Left InsufficientFunds] + else do + dRecvs <- liftIO $ getReceivers pool trNotes' + let fNotes = + map + (\x -> + filter + (\y -> walletTrNoteAddress (entityVal y) == x) + trNotes') + dRecvs + sTree <- liftIO $ getSaplingTree pool + oTree <- liftIO $ getOrchardTree pool + forM fNotes $ \trNotes -> do + opid <- liftIO nextRandom + startTime <- liftIO getCurrentTime + opkey <- + liftIO $ + saveOperation pool $ + Operation (ZenithUuid opid) startTime Nothing Processing Nothing + case opkey of + Nothing -> return $ Left ZHError + Just opkey' -> do + let noteTotal = getTotalAmount (trNotes, [], []) + tSpends <- + liftIO $ + prepTSpends + (getTranSK $ zcashAccountTPrivateKey $ entityVal acc) + trNotes + chgAddr <- getInternalAddresses pool $ entityKey acc + let internalUA = + getUA $ walletAddressUAddress $ entityVal $ head chgAddr + let oRcvr = + fromJust $ + o_rec =<< isValidUnifiedAddress (E.encodeUtf8 internalUA) + let dummy = + OutgoingNote + 4 + (getBytes $ + getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc) + (getBytes oRcvr) + (fromIntegral $ noteTotal - 500) + "" + True + let feeAmt = calculateTxFee (trNotes, [], []) [dummy] + let snote = + OutgoingNote + 4 + (getBytes $ + getOrchSK $ zcashAccountOrchSpendKey $ entityVal acc) + (getBytes oRcvr) + (fromIntegral $ noteTotal - fromIntegral feeAmt) + "" + True + _ <- + liftIO $ + forkIO $ do + tx <- + liftIO $ + createTransaction + (maybe (hexString "00") (getHash . value . fst) sTree) + (maybe (hexString "00") (getHash . value . fst) oTree) + tSpends + [] + [] + [snote] + znet + (bh + 3) + True + case tx of + Left e -> + finalizeOperation pool opkey' Failed $ T.pack $ show e + Right rawTx -> do + zebraRes <- + makeZebraCall + zHost + zPort + "sendrawtransaction" + [Data.Aeson.String $ toText rawTx] + case zebraRes of + Left e1 -> + finalizeOperation pool opkey' Failed $ + T.pack $ show e1 + Right txId -> + finalizeOperation pool opkey' Successful $ + "Tx ID: " <> toText txId + logDebugN $ T.pack $ show opid + return $ Right opid where getTotalAmount :: ( [Entity WalletTrNote] diff --git a/src/Zenith/DB.hs b/src/Zenith/DB.hs index dfbedf9..7de2015 100644 --- a/src/Zenith/DB.hs +++ b/src/Zenith/DB.hs @@ -630,6 +630,7 @@ getAddresses pool a = addrs <- from $ table @WalletAddress where_ (addrs ^. WalletAddressAccId ==. val a) where_ (addrs ^. WalletAddressScope ==. val (ScopeDB External)) + orderBy [asc $ addrs ^. WalletAddressId] pure addrs getAddressById :: diff --git a/src/Zenith/GUI.hs b/src/Zenith/GUI.hs index 304d960..a059b89 100644 --- a/src/Zenith/GUI.hs +++ b/src/Zenith/GUI.hs @@ -28,6 +28,7 @@ import Data.Scientific (Scientific, fromFloatDigits) import qualified Data.Text as T import qualified Data.Text.Encoding as E import Data.Time.Clock.POSIX (posixSecondsToUTCTime) +import qualified Data.UUID as U import Database.Esqueleto.Experimental (ConnectionPool, fromSqlKey) import Database.Persist import Lens.Micro ((&), (+~), (.~), (?~), (^.), set) @@ -1729,29 +1730,16 @@ scanZebra dbPath zHost zPort net sendMsg = do _ <- completeSync pool Failed sendMsg (ShowError $ showt e1) Right blk -> do - r2 <- - liftIO $ - makeZebraCall - zHost - zPort - "getblock" - [Data.Aeson.String $ showt bl, jsonNumber 0] - case r2 of - Left e2 -> do - _ <- completeSync pool Failed - sendMsg (ShowError $ showt e2) - Right hb -> do - let blockTime = getBlockTime hb - bi <- - saveBlock pool $ - ZcashBlock - (fromIntegral $ bl_height blk) - (HexStringDB $ bl_hash blk) - (fromIntegral $ bl_confirmations blk) - blockTime - (ZcashNetDB net) - mapM_ (processTx zHost zPort bi pool) $ bl_txs blk - sendMsg (SyncVal step) + bi <- + saveBlock pool $ + ZcashBlock + (fromIntegral $ bl_height blk) + (HexStringDB $ bl_hash blk) + (fromIntegral $ bl_confirmations blk) + (fromIntegral $ bl_time blk) + (ZcashNetDB net) + mapM_ (processTx zHost zPort bi pool) $ bl_txs blk + sendMsg (SyncVal step) shieldTransaction :: Config -> ZcashNet -> ZcashAccountId -> (AppEvent -> IO ()) -> IO () @@ -1763,19 +1751,20 @@ shieldTransaction config znet accId sendMsg = do pool <- runNoLoggingT $ initPool dbPath bl <- getChainTip zHost zPort res <- runNoLoggingT $ shieldTransparentNotes pool zHost zPort znet accId bl - forM_ res $ \case - Left e -> sendMsg $ ShowError $ T.pack (show e) - Right rawTx -> do - sendMsg $ ShowMsg "Transaction ready, sending to Zebra..." - resp <- - makeZebraCall - zHost - zPort - "sendrawtransaction" - [Data.Aeson.String $ toText rawTx] - case resp of - Left e1 -> sendMsg $ ShowError $ "Zebra error: " <> T.pack (show e1) - Right txId -> sendMsg $ ShowTxId txId + ops <- + mapM + (\case + Left e -> return $ T.pack $ show e + Right x -> do + thisOp <- getOperation pool x + case thisOp of + Nothing -> return "" + Just o -> + return $ + (U.toText . getUuid . operationUuid $ entityVal o) <> + ": " <> (T.pack . show . operationStatus $ entityVal o)) + res + sendMsg $ ShowMsg $ T.intercalate "\n" ops deshieldTransaction :: Config @@ -1795,40 +1784,20 @@ deshieldTransaction config znet accId addR pnote sendMsg = do let zPort = c_zebraPort config pool <- runNoLoggingT $ initPool dbPath bl <- getChainTip zHost zPort - let tAddrMaybe = - Transparent <$> - ((decodeTransparentAddress . - E.encodeUtf8 . encodeTransparentReceiver znet) =<< - (t_rec =<< - (isValidUnifiedAddress . - E.encodeUtf8 . getUA . walletAddressUAddress) - (entityVal addr))) - case tAddrMaybe of - Nothing -> sendMsg $ ShowError "No transparent address available" - Just tAddr -> do - res <- - runNoLoggingT $ - deshieldNotes - pool + res <- runNoLoggingT $ deshieldNotes pool zHost zPort znet accId bl pnote + case res of + Left e -> sendMsg $ ShowError $ T.pack (show e) + Right rawTx -> do + sendMsg $ ShowModal "Transaction ready, sending to Zebra..." + resp <- + makeZebraCall zHost zPort - znet - accId - bl - (ProposedNote (ValidAddressAPI tAddr) pnote Nothing) - case res of - Left e -> sendMsg $ ShowError $ T.pack (show e) - Right rawTx -> do - sendMsg $ ShowModal "Transaction ready, sending to Zebra..." - resp <- - makeZebraCall - zHost - zPort - "sendrawtransaction" - [Data.Aeson.String $ toText rawTx] - case resp of - Left e1 -> sendMsg $ ShowError $ "Zebra error: " <> showt e1 - Right txId -> sendMsg $ ShowTxId txId + "sendrawtransaction" + [Data.Aeson.String $ toText rawTx] + case resp of + Left e1 -> sendMsg $ ShowError $ "Zebra error: " <> showt e1 + Right txId -> sendMsg $ ShowTxId txId sendTransaction :: Config @@ -2023,7 +1992,7 @@ runZenithGUI config = do Left _e -> print "Zebra not available" where params hd = - [ appWindowTitle "Zenith - Zcash Full Node Wallet" + [ appWindowTitle "Zenith - Zcash Full Node Wallet - 0.7.1.0-beta" , appWindowState $ MainWindowNormal (1000, 700) , appTheme zenithTheme , appFontDef diff --git a/src/Zenith/RPC.hs b/src/Zenith/RPC.hs index a32fb8f..82f62c1 100644 --- a/src/Zenith/RPC.hs +++ b/src/Zenith/RPC.hs @@ -20,7 +20,7 @@ import Control.Monad.Logger (runFileLoggingT, runNoLoggingT, runStderrLoggingT) import Data.Aeson import qualified Data.HexString as H import Data.Int -import Data.Scientific (floatingOrInteger) +import Data.Scientific (Scientific(..), floatingOrInteger) import qualified Data.Text as T import qualified Data.Text.Encoding as E import Data.Time.Clock (getCurrentTime) @@ -50,7 +50,9 @@ import Zenith.Core ( checkBlockChain , createCustomWalletAddress , createZcashAccount + , deshieldNotes , prepareTxV2 + , shieldTransparentNotes , syncWallet , updateCommitmentTrees ) @@ -121,6 +123,8 @@ data ZenithMethod | GetNewAddress | GetOperationStatus | SendMany + | ShieldNotes + | DeshieldFunds | UnknownMethod deriving (Eq, Prelude.Show) @@ -136,6 +140,8 @@ instance ToJSON ZenithMethod where toJSON GetNewAddress = Data.Aeson.String "getnewaddress" toJSON GetOperationStatus = Data.Aeson.String "getoperationstatus" toJSON SendMany = Data.Aeson.String "sendmany" + toJSON ShieldNotes = Data.Aeson.String "shieldnotes" + toJSON DeshieldFunds = Data.Aeson.String "deshieldfunds" toJSON UnknownMethod = Data.Aeson.Null instance FromJSON ZenithMethod where @@ -152,6 +158,8 @@ instance FromJSON ZenithMethod where "getnewaddress" -> pure GetNewAddress "getoperationstatus" -> pure GetOperationStatus "sendmany" -> pure SendMany + "shieldnotes" -> pure ShieldNotes + "deshieldfunds" -> pure DeshieldFunds _ -> pure UnknownMethod data ZenithParams @@ -167,6 +175,8 @@ data ZenithParams | OpParams !ZenithUuid | SendParams !Int ![ProposedNote] !PrivacyPolicy | TestParams !T.Text + | ShieldNotesParams !Int + | DeshieldParams !Int !Scientific deriving (Eq, Prelude.Show) instance ToJSON ZenithParams where @@ -191,6 +201,9 @@ instance ToJSON ZenithParams where Data.Aeson.Array $ V.fromList [Data.Aeson.String $ U.toText $ getUuid i] toJSON (SendParams i ns p) = Data.Aeson.Array $ V.fromList [jsonNumber i, toJSON ns, toJSON p] + toJSON (ShieldNotesParams i) = Data.Aeson.Array $ V.fromList [jsonNumber i] + toJSON (DeshieldParams i s) = + Data.Aeson.Array $ V.fromList [jsonNumber i, Data.Aeson.Number s] data ZenithResponse = InfoResponse !T.Text !ZenithInfo @@ -203,6 +216,7 @@ data ZenithResponse | NewAddrResponse !T.Text !ZcashAddressAPI | OpResponse !T.Text !Operation | SendResponse !T.Text !U.UUID + | MultiOpResponse !T.Text ![T.Text] | ErrorResponse !T.Text !Double !T.Text deriving (Eq, Prelude.Show) @@ -224,6 +238,7 @@ instance ToJSON ZenithResponse where toJSON (NewAddrResponse i a) = packRpcResponse i a toJSON (OpResponse i u) = packRpcResponse i u toJSON (SendResponse i o) = packRpcResponse i o + toJSON (MultiOpResponse i o) = packRpcResponse i o instance FromJSON ZenithResponse where parseJSON = @@ -298,6 +313,9 @@ instance FromJSON ZenithResponse where k5 <- parseJSON r1 pure $ NoteListResponse i k5 Nothing -> fail "Unknown object" + String s -> do + k7 <- parseJSON r1 + pure $ MultiOpResponse i k7 _anyOther -> fail "Malformed JSON" Number k -> do case floatingOrInteger k of @@ -489,6 +507,27 @@ instance FromJSON RpcCall where _anyOther -> pure $ RpcCall v i SendMany BadParams else pure $ RpcCall v i SendMany BadParams _anyOther -> pure $ RpcCall v i SendMany BadParams + ShieldNotes -> do + p <- obj .: "params" + case p of + Array a -> + if V.length a == 1 + then do + x <- parseJSON $ a V.! 0 + pure $ RpcCall v i ShieldNotes (ShieldNotesParams x) + else pure $ RpcCall v i ShieldNotes BadParams + _anyOther -> pure $ RpcCall v i ShieldNotes BadParams + DeshieldFunds -> do + p <- obj .: "params" + case p of + Array a -> + if V.length a == 2 + then do + x <- parseJSON $ a V.! 0 + y <- parseJSON $ a V.! 1 + pure $ RpcCall v i DeshieldFunds (DeshieldParams x y) + else pure $ RpcCall v i DeshieldFunds BadParams + _anyOther -> pure $ RpcCall v i DeshieldFunds BadParams type ZenithRPC = "status" :> Get '[ JSON] Value :<|> BasicAuth "zenith-realm" Bool :> ReqBody @@ -511,7 +550,7 @@ zenithServer state = getinfo :<|> handleRPC getinfo = return $ object - [ "version" .= ("0.7.0.0-beta" :: String) + [ "version" .= ("0.8.0.0-beta" :: String) , "network" .= ("testnet" :: String) ] handleRPC :: Bool -> RpcCall -> Handler ZenithResponse @@ -587,7 +626,7 @@ zenithServer state = getinfo :<|> handleRPC return $ InfoResponse (callId req) - (ZenithInfo "0.7.0.0-beta" (w_network state) (w_build state)) + (ZenithInfo "0.8.0.0-beta" (w_network state) (w_build state)) _anyOtherParams -> return $ ErrorResponse (callId req) (-32602) "Invalid params" ListReceived -> @@ -871,6 +910,137 @@ zenithServer state = getinfo :<|> handleRPC "Account does not exist." _anyOtherParams -> return $ ErrorResponse (callId req) (-32602) "Invalid params" + ShieldNotes -> do + case parameters req of + ShieldNotesParams i -> do + let dbPath = w_dbPath state + let net = w_network state + let zHost = w_host state + let zPort = w_port state + pool <- liftIO $ runNoLoggingT $ initPool dbPath + syncChk <- liftIO $ isSyncing pool + if syncChk + then return $ + ErrorResponse + (callId req) + (-32012) + "The Zenith server is syncing, please try again later." + else do + acc <- + liftIO $ getAccountById pool $ toSqlKey $ fromIntegral i + case acc of + Just acc' -> do + bl <- + liftIO $ + getLastSyncBlock + pool + (zcashAccountWalletId $ entityVal acc') + opids <- + liftIO $ + runNoLoggingT $ + shieldTransparentNotes + pool + zHost + zPort + net + (entityKey acc') + bl + let ops = + map + (\case + Left e -> T.pack $ show e + Right op -> U.toText op) + opids + return $ MultiOpResponse (callId req) ops + Nothing -> + return $ + ErrorResponse + (callId req) + (-32006) + "Account does not exist." + _anyOtherParams -> + return $ ErrorResponse (callId req) (-32602) "Invalid params" + DeshieldFunds -> do + case parameters req of + DeshieldParams i k -> do + let dbPath = w_dbPath state + let net = w_network state + let zHost = w_host state + let zPort = w_port state + pool <- liftIO $ runNoLoggingT $ initPool dbPath + syncChk <- liftIO $ isSyncing pool + if syncChk + then return $ + ErrorResponse + (callId req) + (-32012) + "The Zenith server is syncing, please try again later." + else do + opid <- liftIO nextRandom + startTime <- liftIO getCurrentTime + opkey <- + liftIO $ + saveOperation pool $ + Operation + (ZenithUuid opid) + startTime + Nothing + Processing + Nothing + case opkey of + Nothing -> + return $ + ErrorResponse (callId req) (-32010) "Internal Error" + Just opkey' -> do + acc <- + liftIO $ getAccountById pool $ toSqlKey $ fromIntegral i + case acc of + Just acc' -> do + bl <- + liftIO $ + getLastSyncBlock + pool + (zcashAccountWalletId $ entityVal acc') + _ <- + liftIO $ + forkIO $ do + res <- + runNoLoggingT $ + deshieldNotes + pool + zHost + zPort + net + (entityKey acc') + bl + k + case res of + Left e -> + finalizeOperation pool opkey' Failed $ + T.pack $ show e + Right rawTx -> do + zebraRes <- + makeZebraCall + zHost + zPort + "sendrawtransaction" + [Data.Aeson.String $ H.toText rawTx] + case zebraRes of + Left e1 -> + finalizeOperation pool opkey' Failed $ + T.pack $ show e1 + Right txId -> + finalizeOperation pool opkey' Successful $ + "Tx ID: " <> H.toText txId + return $ SendResponse (callId req) opid + Nothing -> + return $ + ErrorResponse + (callId req) + (-32006) + "Account does not exist." + _anyOtherParams -> + return $ ErrorResponse (callId req) (-32602) "Invalid params" authenticate :: Config -> BasicAuthCheck Bool authenticate config = BasicAuthCheck check @@ -932,22 +1102,12 @@ scanZebra dbPath zHost zPort net = do case r of Left _ -> completeSync pool Failed Right blk -> do - r2 <- - makeZebraCall - zHost - zPort - "getblock" - [Data.Aeson.String $ T.pack (show bl), jsonNumber 0] - case r2 of - Left _ -> completeSync pool Failed - Right hb -> do - let blockTime = getBlockTime hb - bi <- - saveBlock pool $ - ZcashBlock - (fromIntegral $ bl_height blk) - (HexStringDB $ bl_hash blk) - (fromIntegral $ bl_confirmations blk) - blockTime - (ZcashNetDB net) - mapM_ (processTx zHost zPort bi pool) $ bl_txs blk + bi <- + saveBlock pool $ + ZcashBlock + (fromIntegral $ bl_height blk) + (HexStringDB $ bl_hash blk) + (fromIntegral $ bl_confirmations blk) + (fromIntegral $ bl_time blk) + (ZcashNetDB net) + mapM_ (processTx zHost zPort bi pool) $ bl_txs blk diff --git a/src/Zenith/Scanner.hs b/src/Zenith/Scanner.hs index 50d6235..8bef9f6 100644 --- a/src/Zenith/Scanner.hs +++ b/src/Zenith/Scanner.hs @@ -133,29 +133,16 @@ processBlock host port pool pg net b = do _ <- completeSync pool Failed liftIO $ throwIO $ userError e Right blk -> do - r2 <- - liftIO $ - makeZebraCall - host - port - "getblock" - [Data.Aeson.String $ T.pack $ show b, jsonNumber 0] - case r2 of - Left e2 -> do - _ <- completeSync pool Failed - liftIO $ throwIO $ userError e2 - Right hb -> do - let blockTime = getBlockTime hb - bi <- - saveBlock pool $ - ZcashBlock - (fromIntegral $ bl_height blk) - (HexStringDB $ bl_hash blk) - (fromIntegral $ bl_confirmations blk) - blockTime - net - mapM_ (processTx host port bi pool) $ bl_txs blk - liftIO $ tick pg + bi <- + saveBlock pool $ + ZcashBlock + (fromIntegral $ bl_height blk) + (HexStringDB $ bl_hash blk) + (fromIntegral $ bl_confirmations blk) + (fromIntegral $ bl_time blk) + net + mapM_ (processTx host port bi pool) $ bl_txs blk + liftIO $ tick pg -- | Function to process a raw transaction processTx :: diff --git a/src/Zenith/Utils.hs b/src/Zenith/Utils.hs index c3b74ee..53fc8bb 100644 --- a/src/Zenith/Utils.hs +++ b/src/Zenith/Utils.hs @@ -235,7 +235,7 @@ isValidString c = do padWithZero :: Int -> String -> String padWithZero n s - | (length s) >= n = s + | length s >= n = s | otherwise = padWithZero n ("0" ++ s) isEmpty :: [a] -> Bool @@ -248,3 +248,6 @@ getChainTip zHost zPort = do case r of Left e1 -> pure 0 Right i -> pure i + +getTransparentFromUA :: UnifiedAddress -> Maybe TransparentAddress +getTransparentFromUA ua = TransparentAddress (ua_net ua) <$> t_rec ua diff --git a/test/ServerSpec.hs b/test/ServerSpec.hs index 882b5e0..f41668e 100644 --- a/test/ServerSpec.hs +++ b/test/ServerSpec.hs @@ -86,7 +86,7 @@ main = do Left e -> assertFailure e Right r -> r `shouldBe` - InfoResponse "zh" (ZenithInfo "0.7.0.0-beta" TestNet "v1.9.0") + InfoResponse "zh" (ZenithInfo "0.8.0.0-beta" TestNet "v2.1.0") describe "Wallets" $ do describe "listwallet" $ do it "bad credentials" $ do @@ -676,6 +676,54 @@ main = do 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` [] startAPI :: Config -> IO () startAPI config = do diff --git a/test/Spec.hs b/test/Spec.hs index ca66599..fb4b13e 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -643,8 +643,7 @@ main = do case ix of Nothing -> assertFailure "couldn't find index at block" Just i -> do - updatedTree <- - runFileLoggingT "test.log" $ truncateTree oTree i + updatedTree <- runNoLoggingT $ truncateTree oTree i let finalAnchor = getOrchardTreeAnchor $ OrchardCommitmentTree $ ztiOrchard zebraTreesIn @@ -737,7 +736,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -763,7 +762,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -787,7 +786,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -815,7 +814,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -847,7 +846,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -873,7 +872,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -897,7 +896,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -926,7 +925,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -957,7 +956,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -983,7 +982,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -1007,7 +1006,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -1034,7 +1033,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -1061,7 +1060,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" @@ -1086,7 +1085,7 @@ main = do Just ua -> do pool <- runNoLoggingT $ initPool "/home/rav/Zenith/zenith.db" tx <- - runFileLoggingT "zenith.log" $ + runNoLoggingT $ prepareTxV2 pool "localhost" diff --git a/zcash-haskell b/zcash-haskell index d45bd7d..7d3ae36 160000 --- a/zcash-haskell +++ b/zcash-haskell @@ -1 +1 @@ -Subproject commit d45bd7dcf3c3cf4e893900a1774d24b14bf56591 +Subproject commit 7d3ae36d2b48b8ed91a70e40a77fb7efe57765a0 diff --git a/zenith-openrpc.json b/zenith-openrpc.json index 53cb005..ce0dfa5 100644 --- a/zenith-openrpc.json +++ b/zenith-openrpc.json @@ -1,7 +1,7 @@ { "openrpc": "1.0.0-rc1", "info": { - "version": "0.7.0.0-beta", + "version": "0.8.0.0-beta", "title": "Zenith RPC", "description": "The RPC methods to interact with the Zenith Zcash wallet", "license": { @@ -605,10 +605,9 @@ ], "paramStructure": "by-position", "result": { - "name": "Operation ID(s)", + "name": "Operation ID", "schema": { - "type": "array", - "items": { "$ref": "#/components/contentDescriptors/OperationId"} + "$ref": "#/components/contentDescriptors/OperationId" } }, "examples": [ @@ -620,7 +619,7 @@ { "name": "Account index", "summary": "The index for the account to use", - "value": "1" + "value": 1 }, { "name": "Privacy Policy", @@ -641,9 +640,8 @@ ], "result": { "name": "SendMany result", - "value": [ - "3cc31c07-07cf-4a6e-9190-156c4b8c4088" - ] + "value": "3cc31c07-07cf-4a6e-9190-156c4b8c4088" + } } ], @@ -669,6 +667,130 @@ "errors": [ { "$ref": "#/components/errors/OpNotFound" } ] + }, + { + "name": "shieldnotes", + "summary": "Shield all transparent notes into the Orchard pool for the given account", + "description": "Creates one or more transactions, grouping all the unspent transparent notes for the given account by their transparent address to avoid associating different transparent addresses. These notes are sent to the given account's internal change address as shielded Orchard notes.", + "tags": [], + "params": [ + { "$ref": "#/components/contentDescriptors/AccountId"} + ], + "paramStructure": "by-position", + "result": { + "name": "Operation ID(s)", + "schema": { + "type": "array", + "items": { "$ref": "#/components/contentDescriptors/OperationId"} + } + }, + "examples": [ + { + "name": "Shield transparent notes", + "summary": "Shield transparent notes", + "description": "Shield the transparent notes in a given account", + "params": [ + { + "name": "Account index", + "summary": "The index for the account to use", + "value": "3" + } + ], + "result": { + "name": "ShieldNotes result", + "value": [ + "ab350df0-9f57-44c0-9e0d-f7b8af1f4231", + "8c6f2656-22ef-4f9d-b465-80ddd13fc485" + ] + } + }, + { + "name": "No transparent funds", + "summary": "Shield transparent notes with no transparent funds", + "description": "Attempt to shield the transparent notes in a given account, when account has none", + "params": [ + { + "name": "Account index", + "summary": "The index for the account to use", + "value": "3" + } + ], + "result": { + "name": "ShieldNotes result", + "value": [ + "InsufficientFunds" + ] + } + } + ], + "errors": [ + { "$ref": "#/components/errors/ZebraNotAvailable" }, + { "$ref": "#/components/errors/ZenithBusy" }, + { "$ref": "#/components/errors/InvalidAccount" } + ] + }, + { + "name": "deshieldfunds", + "summary": "De-shield the given amount of ZEC from the given account", + "description": "Creates a new internal transaction with the requested amount of ZEC to the transparent pool. The fee is not included in the given amount.", + "tags": [], + "params": [ + { "$ref": "#/components/contentDescriptors/AccountId"}, + { "$ref": "#/components/contentDescriptors/Amount"} + ], + "paramStructure": "by-position", + "result": { + "name": "Operation ID", + "schema": { + "$ref": "#/components/contentDescriptors/OperationId" + } + }, + "examples": [ + { + "name": "De-Shield funds", + "summary": "De-shield funds", + "description": "Move the given amount of ZEC for the given acount from the shielded pool to the transparent pool", + "params": [ + { + "name": "Account index", + "summary": "The index for the account to use", + "value": "3" + }, + { + "name": "Amount", + "summary": "The amount of ZEC to use", + "value": 1.23 + } + ], + "result": { + "name": "Deshield funds result", + "value": "ab350df0-9f57-44c0-9e0d-f7b8af1f4231" + } + }, + { + "name": "No transparent funds", + "summary": "Shield transparent notes with no transparent funds", + "description": "Attempt to shield the transparent notes in a given account, when account has none", + "params": [ + { + "name": "Account index", + "summary": "The index for the account to use", + "value": "3" + } + ], + "result": { + "name": "ShieldNotes result", + "value": [ + "InsufficientFunds" + ] + } + } + ], + "errors": [ + { "$ref": "#/components/errors/ZebraNotAvailable" }, + { "$ref": "#/components/errors/ZenithBusy" }, + { "$ref": "#/components/errors/InvalidAccount" } + ] } ], "components": { @@ -700,6 +822,15 @@ "type": "string" } }, + "Amount": { + "name": "A numeric amount", + "summary": "A numeric amount", + "description": "A number that represents an amount to be used by a function as an input", + "required": true, + "schema": { + "type": "number" + } + }, "Name": { "name": "Name", "summary": "A user-friendly name", diff --git a/zenith.cabal b/zenith.cabal index 5ee487b..8691137 100644 --- a/zenith.cabal +++ b/zenith.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: zenith -version: 0.7.0.0-beta +version: 0.7.1.0-beta license: MIT license-file: LICENSE author: Rene Vergara diff --git a/zenith_er.bmp b/zenith_er.bmp deleted file mode 100644 index d248b8f..0000000 Binary files a/zenith_er.bmp and /dev/null differ diff --git a/zenith_er.png b/zenith_er.png deleted file mode 100644 index 5d6d21c..0000000 Binary files a/zenith_er.png and /dev/null differ