Implement listaccounts

This commit is contained in:
Rene Vergara 2024-08-06 13:38:00 -05:00
parent dbe352acac
commit 4553f964f3
Signed by: pitmutt
GPG key ID: 65122AD495A7F5B2
5 changed files with 120 additions and 8 deletions

View file

@ -75,6 +75,7 @@ import Zenith.Types
, ScopeDB(..) , ScopeDB(..)
, TransparentSpendingKeyDB , TransparentSpendingKeyDB
, UnifiedAddressDB(..) , UnifiedAddressDB(..)
, ZcashAccountAPI(..)
, ZcashNetDB(..) , ZcashNetDB(..)
, ZcashPool(..) , ZcashPool(..)
, ZcashWalletAPI(..) , ZcashWalletAPI(..)
@ -275,6 +276,14 @@ toZcashWalletAPI w =
(zcashWalletBirthdayHeight $ entityVal w) (zcashWalletBirthdayHeight $ entityVal w)
(zcashWalletLastSync $ entityVal w) (zcashWalletLastSync $ entityVal w)
-- | @ZcashAccount@
toZcashAccountAPI :: Entity ZcashAccount -> ZcashAccountAPI
toZcashAccountAPI a =
ZcashAccountAPI
(fromIntegral $ fromSqlKey $ entityKey a)
(fromIntegral $ fromSqlKey $ zcashAccountWalletId $ entityVal a)
(zcashAccountName $ entityVal a)
-- * Database functions -- * Database functions
-- | Initializes the database -- | Initializes the database
initDb :: initDb ::

View file

@ -17,6 +17,7 @@ import Control.Monad.Logger (runNoLoggingT)
import Data.Aeson import Data.Aeson
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Vector as V import qualified Data.Vector as V
import Database.Esqueleto.Experimental (toSqlKey)
import Servant import Servant
import ZcashHaskell.Types import ZcashHaskell.Types
( RpcError(..) ( RpcError(..)
@ -25,18 +26,28 @@ import ZcashHaskell.Types
, ZebraGetInfo(..) , ZebraGetInfo(..)
) )
import Zenith.Core (checkBlockChain, checkZebra) import Zenith.Core (checkBlockChain, checkZebra)
import Zenith.DB (getWallets, initDb, initPool, toZcashWalletAPI) import Zenith.DB
import Zenith.Types (Config(..), ZcashWalletAPI(..)) ( getAccounts
, getWallets
, initDb
, initPool
, toZcashAccountAPI
, toZcashWalletAPI
)
import Zenith.Types (Config(..), ZcashAccountAPI(..), ZcashWalletAPI(..))
import Zenith.Utils (jsonNumber)
data ZenithMethod data ZenithMethod
= GetInfo = GetInfo
| ListWallets | ListWallets
| ListAccounts
| UnknownMethod | UnknownMethod
deriving (Eq, Prelude.Show) deriving (Eq, Prelude.Show)
instance ToJSON ZenithMethod where instance ToJSON ZenithMethod where
toJSON GetInfo = Data.Aeson.String "getinfo" toJSON GetInfo = Data.Aeson.String "getinfo"
toJSON ListWallets = Data.Aeson.String "listwallets" toJSON ListWallets = Data.Aeson.String "listwallets"
toJSON ListAccounts = Data.Aeson.String "listaccounts"
toJSON UnknownMethod = Data.Aeson.Null toJSON UnknownMethod = Data.Aeson.Null
instance FromJSON ZenithMethod where instance FromJSON ZenithMethod where
@ -44,22 +55,26 @@ instance FromJSON ZenithMethod where
withText "ZenithMethod" $ \case withText "ZenithMethod" $ \case
"getinfo" -> pure GetInfo "getinfo" -> pure GetInfo
"listwallets" -> pure ListWallets "listwallets" -> pure ListWallets
"listaccounts" -> pure ListAccounts
_ -> pure UnknownMethod _ -> pure UnknownMethod
data ZenithParams data ZenithParams
= BlankParams = BlankParams
| BadParams | BadParams
| AccountsParams !Int
| TestParams !T.Text | TestParams !T.Text
deriving (Eq, Prelude.Show) deriving (Eq, Prelude.Show)
instance ToJSON ZenithParams where instance ToJSON ZenithParams where
toJSON BlankParams = Data.Aeson.Array V.empty toJSON BlankParams = Data.Aeson.Array V.empty
toJSON BadParams = Data.Aeson.Null toJSON BadParams = Data.Aeson.Null
toJSON (AccountsParams n) = Data.Aeson.Array $ V.fromList [jsonNumber n]
toJSON (TestParams t) = Data.Aeson.Array $ V.fromList [Data.Aeson.String t] toJSON (TestParams t) = Data.Aeson.Array $ V.fromList [Data.Aeson.String t]
data ZenithResponse data ZenithResponse
= InfoResponse !T.Text !ZenithInfo = InfoResponse !T.Text !ZenithInfo
| WalletListResponse !T.Text ![ZcashWalletAPI] | WalletListResponse !T.Text ![ZcashWalletAPI]
| AccountListResponse !T.Text ![ZcashAccountAPI]
| ErrorResponse !T.Text !Double !T.Text | ErrorResponse !T.Text !Double !T.Text
deriving (Eq, Prelude.Show) deriving (Eq, Prelude.Show)
@ -68,6 +83,8 @@ instance ToJSON ZenithResponse where
object ["jsonrpc" .= ("2.0" :: String), "id" .= t, "result" .= i] object ["jsonrpc" .= ("2.0" :: String), "id" .= t, "result" .= i]
toJSON (WalletListResponse i w) = toJSON (WalletListResponse i w) =
object ["jsonrpc" .= ("2.0" :: String), "id" .= i, "result" .= w] object ["jsonrpc" .= ("2.0" :: String), "id" .= i, "result" .= w]
toJSON (AccountListResponse i a) =
object ["jsonrpc" .= ("2.0" :: String), "id" .= i, "result" .= a]
toJSON (ErrorResponse i c m) = toJSON (ErrorResponse i c m) =
object object
[ "jsonrpc" .= ("2.0" :: String) [ "jsonrpc" .= ("2.0" :: String)
@ -162,6 +179,16 @@ instance FromJSON RpcCall where
if null (p :: [Value]) if null (p :: [Value])
then pure $ RpcCall v i GetInfo BlankParams then pure $ RpcCall v i GetInfo BlankParams
else pure $ RpcCall v i GetInfo BadParams else pure $ RpcCall v i GetInfo BadParams
ListAccounts -> do
p <- obj .: "params"
case p of
Array a ->
if V.length a == 1
then do
w <- parseJSON $ V.head a
pure $ RpcCall v i ListAccounts (AccountsParams w)
else pure $ RpcCall v i ListAccounts BadParams
_anyOther -> pure $ RpcCall v i ListAccounts BadParams
type ZenithRPC type ZenithRPC
= "status" :> Get '[ JSON] Value :<|> BasicAuth "zenith-realm" Bool :> ReqBody = "status" :> Get '[ JSON] Value :<|> BasicAuth "zenith-realm" Bool :> ReqBody
@ -211,6 +238,26 @@ zenithServer config = getinfo :<|> handleRPC
"No wallets available. Please create one first" "No wallets available. Please create one first"
_anyOther -> _anyOther ->
return $ ErrorResponse (callId req) (-32602) "Invalid params" return $ ErrorResponse (callId req) (-32602) "Invalid params"
ListAccounts ->
case parameters req of
AccountsParams w -> do
let dbPath = c_dbPath config
pool <- liftIO $ runNoLoggingT $ initPool dbPath
accList <-
liftIO $
runNoLoggingT $ getAccounts pool (toSqlKey $ fromIntegral w)
if not (null accList)
then return $
AccountListResponse
(callId req)
(map toZcashAccountAPI accList)
else return $
ErrorResponse
(callId req)
(-32002)
"No accounts available for this wallet. Please create one first"
_anyOther ->
return $ ErrorResponse (callId req) (-32602) "Invalid params"
GetInfo -> GetInfo ->
case parameters req of case parameters req of
BlankParams -> do BlankParams -> do

View file

@ -130,6 +130,24 @@ instance FromJSON ZcashWalletAPI where
l <- obj .: "lastSync" l <- obj .: "lastSync"
pure $ ZcashWalletAPI i n net b l pure $ ZcashWalletAPI i n net b l
data ZcashAccountAPI = ZcashAccountAPI
{ za_index :: !Int
, za_wallet :: !Int
, za_name :: !T.Text
} deriving (Eq, Prelude.Show)
instance ToJSON ZcashAccountAPI where
toJSON (ZcashAccountAPI i w n) =
object ["index" .= i, "wallet" .= w, "name" .= n]
instance FromJSON ZcashAccountAPI where
parseJSON =
withObject "ZcashAccountAPI" $ \obj -> do
i <- obj .: "index"
w <- obj .: "wallet"
n <- obj .: "name"
pure $ ZcashAccountAPI i w n
-- ** `zebrad` -- ** `zebrad`
-- | Type for modeling the tree state response -- | Type for modeling the tree state response
data ZebraTreeInfo = ZebraTreeInfo data ZebraTreeInfo = ZebraTreeInfo

View file

@ -95,6 +95,35 @@ main = do
"zh" "zh"
(-32001) (-32001)
"No wallets available. Please create one first" "No wallets available. Please create one first"
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"
it "correct credentials, 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"
startAPI :: Config -> IO () startAPI :: Config -> IO ()
startAPI config = do startAPI config = do

View file

@ -21,7 +21,7 @@
"name": "getinfo", "name": "getinfo",
"summary": "Get basic Zenith information", "summary": "Get basic Zenith information",
"description": "Get basic information about Zenith, such as the network it is running on and the version of Zebra it is connected to", "description": "Get basic information about Zenith, such as the network it is running on and the version of Zebra it is connected to",
"tags": [ { "$ref": "#/components/tags/information" }], "tags": [],
"result" : { "result" : {
"name": "Zenith information", "name": "Zenith information",
"schema": { "$ref": "#/components/schemas/ZenithInfo" } "schema": { "$ref": "#/components/schemas/ZenithInfo" }
@ -52,7 +52,7 @@
"name": "listwallets", "name": "listwallets",
"summary": "Get the list of available wallets", "summary": "Get the list of available wallets",
"description": "Returns a list of available wallets per the network that the Zebra node is running on.", "description": "Returns a list of available wallets per the network that the Zebra node is running on.",
"tags": [ { "$ref": "#/components/tags/wallet" }], "tags": [],
"result": { "result": {
"name": "Wallets", "name": "Wallets",
"schema": { "schema": {
@ -98,9 +98,9 @@
}, },
{ {
"name": "listaccounts", "name": "listaccounts",
"summary": "DRAFT: List existing accounts for a wallet ID", "summary": "List existing accounts for a wallet ID",
"description": "List existing accounts for the given wallet ID or provide an error if none", "description": "List existing accounts for the given wallet ID or provide an error if none",
"tags": [ { "$ref": "#/components/tags/wallet" }], "tags": [],
"result": { "result": {
"name": "Accounts", "name": "Accounts",
"schema": { "schema": {
@ -127,6 +127,16 @@
"result": { "result": {
"name": "ListAccounts result", "name": "ListAccounts result",
"value": [ "value": [
{
"index": 3,
"name": "Business",
"wallet": 1
},
{
"index": 1,
"name": "Savings",
"wallet": 1
}
] ]
} }
@ -180,8 +190,7 @@
}, },
"examples": {}, "examples": {},
"tags": { "tags": {
"information": {"name": "Information"}, "draft": {"name": "Draft"}
"wallet": {"name": "Wallet"}
}, },
"errors": { "errors": {
"ZebraNotAvailable": { "ZebraNotAvailable": {