From 9546613e0f4872b56a2f3eb54eb71c7a8f41533a Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 18 Dec 2024 13:31:13 -0600 Subject: [PATCH] feat(rpc): implement `shieldnotes` method --- src/Zenith/CLI.hs | 4 +- src/Zenith/Core.hs | 166 +++++++++++++++++++++++--------------------- src/Zenith/RPC.hs | 9 +-- test/ServerSpec.hs | 50 ++++++++++++- test/Spec.hs | 31 ++++----- zcash-haskell | 2 +- zenith-openrpc.json | 39 +++++++++++ 7 files changed, 195 insertions(+), 106 deletions(-) diff --git a/src/Zenith/CLI.hs b/src/Zenith/CLI.hs index 15f87db..80b30e9 100644 --- a/src/Zenith/CLI.hs +++ b/src/Zenith/CLI.hs @@ -780,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) diff --git a/src/Zenith/Core.hs b/src/Zenith/Core.hs index 67d132c..046da6a 100644 --- a/src/Zenith/Core.hs +++ b/src/Zenith/Core.hs @@ -777,88 +777,94 @@ shieldTransparentNotes pool zHost zPort 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 - 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 <- + 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 $ - 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 <- + 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 $ - 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 + 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/RPC.hs b/src/Zenith/RPC.hs index d0d4fd1..2925eab 100644 --- a/src/Zenith/RPC.hs +++ b/src/Zenith/RPC.hs @@ -307,11 +307,8 @@ instance FromJSON ZenithResponse where pure $ NoteListResponse i k5 Nothing -> fail "Unknown object" String s -> do - case U.fromText s of - Nothing -> fail "Unknown value" - Just _u -> do - k7 <- parseJSON r1 - pure $ MultiOpResponse i k7 + k7 <- parseJSON r1 + pure $ MultiOpResponse i k7 _anyOther -> fail "Malformed JSON" Number k -> do case floatingOrInteger k of @@ -611,7 +608,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 -> 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 4289a9d..d350c2e 160000 --- a/zcash-haskell +++ b/zcash-haskell @@ -1 +1 @@ -Subproject commit 4289a9ded67ef2ca432abc412934fb5b8b59a9cf +Subproject commit d350c2e7844a526ff9b21bb14e1723fce9b0b46b diff --git a/zenith-openrpc.json b/zenith-openrpc.json index 8a8c638..686bb56 100644 --- a/zenith-openrpc.json +++ b/zenith-openrpc.json @@ -686,6 +686,45 @@ "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" },