Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

Commit 774482b

Browse files
authored
Merge pull request #3461 from input-output-hk/Squad1/CO-325/api-v1-improvements
[CO-325] API V1 Improvements - Part 2
2 parents 5df33c5 + 2e31c10 commit 774482b

File tree

23 files changed

+713
-81
lines changed

23 files changed

+713
-81
lines changed

README.md

+72-11
Original file line numberDiff line numberDiff line change
@@ -73,25 +73,53 @@ $ stack exec cardano-node -- --topology=wallet-new/topology-examples/testnet.yam
7373

7474
From there, you can browse the API documentation for V0 and V1 through the following URLs:
7575

76-
- http://localhost:8090/docs/v0/index/
77-
- http://localhost:8090/docs/v1/index/
76+
- https://localhost:8091/docs/v0/index/
77+
- https://localhost:8091/docs/v1/index/
7878

79-
### HTTPS
8079

81-
By default, wallet backend only accepts HTTPS connections:
80+
You may also run a simple cURL command to check whether the node is up-and-running:
8281

8382
```
84-
$ curl localhost:8090/docs/v1/index/
85-
This server only accepts secure HTTPS connections.
83+
$ curl https://localhost:8090/api/v1/node-info \
84+
--cacert scripts/tls-files/ca.crt \
85+
--cert scripts/tls-files/client.pem
8686
```
8787

88-
We should provide our `ca.crt`:
88+
> *NOTE*
89+
>
90+
> Every node running a wallet API needs x509 certificates for enabling TLS support. By default,
91+
> those certificates are located in `./scripts/tls-files`. Use them if you need a CA or a
92+
> client certificate.
93+
94+
95+
## Local Cluster
96+
97+
Running a node against `mainnet_staging` may not be ideal for testing. The node will also need
98+
time to synchronize and won't run the full API capabilities until having done so. To cope with
99+
this, one may run a local cluster of nodes, acting upon a fresh database, speeding up most of
100+
the operations. To run a local cluster, _nix_ is your friend:
101+
102+
```
103+
$ nix-build -A demoCluster -o run-demo --arg useStackBinaries true && ./run-demo
104+
```
105+
106+
This will run a local cluster after having set up a fresh environment for it in `./state-demo`.
107+
There are some files of interest in this folder you may need like the tls certificates or the
108+
logging configurations.
109+
110+
111+
### HTTPS
112+
113+
By default, wallet backend only accepts HTTPS connections:
89114

90115
```
91-
$ curl --cacert scripts/tls-files/ca.crt https://localhost:8090/docs/v1/index/
116+
$ curl localhost:8090/api/v1/node-info
117+
This server only accepts secure HTTPS connections.
92118
```
93119

94-
But if we launch a node with `--wallet-debug` option, we can send simple `http`-requests.
120+
Read the documentation about TLS authentication in [docs/tls-authentication.md](../docs/tls-authentication.md)
121+
for details about how to contact a wallet node with TLS.
122+
95123

96124
### Swagger Specification
97125

@@ -126,9 +154,33 @@ $ stack test cardano-sl-wallet-new
126154
Wallet integration tests can be run using this command (from the project *root* directory):
127155

128156
```
129-
$ nix-build release.nix -A walletIntegrationTests
157+
$ nix-build -A walletIntegrationTests --arg useStackBinaries true
130158
```
131159

160+
> **NOTE**:
161+
> `nix-build -A walletIntegrationTests` (with or without `useStackBinaries`) runs a
162+
> local demo cluster, either via stack or nix by default on your local machine
163+
> that is fully usable by daedalus/curl etc... and requires port 8090 and
164+
> ports 3001-3004 and 3101 to be available. This cluster has four core nodes, 1
165+
> relay, and a single wallet and has full x509 CA cert enabled. It then
166+
> pre-loads some genesis poor keys for testing and runs the wal-integr-test
167+
> haskell program, which connects to the running cluster. When it completes, it
168+
> terminates the demo cluster and wallet. This will fail if ports aren't
169+
> available to bind (although cardano-node will happily run without crashing,
170+
> it just will be broken), you try running two of these at once, etc...
171+
>
172+
> This is differentiated from `nix-build -A tests.walletIntegration` which **DOES
173+
> NOT** support `useStackBinaries` and builds/runs the entire cluster in a sandbox
174+
> isolated from the rest of the system (assuming nix sandboxing is enabled).
175+
> This is how hydra runs the tests and why hydra is capable or running more
176+
> than one cluster at the same time. This will use any binaries cached by hydra
177+
> if you have the IOHK binary cache enabled, or will build everything cleanly
178+
> in nix if the binaries aren't available in the local nix store. One other
179+
> thing to note is that tests.walletIntegration will only run once and will
180+
> cache the results (unless of a failure). If you have a need to rerun the
181+
> test, you can pass the `--check` flag to force the test to run again. `--check`
182+
> is used to confirm that results from one test match the results again.
183+
132184
## Developing
133185

134186
We have a [`Makefile`](./Makefile) with some helpful commands for development.
@@ -152,7 +204,8 @@ Now use following command (from the `cardano-sl` *root* directory):
152204
$ curl -X POST \
153205
-H "Content-Type: application/json" \
154206
-d '"PATH_TO_SECRET_KEY"' \
155-
--cacert scripts/tls-files/ca.crt
207+
--cacert scripts/tls-files/ca.crt \
208+
--cert scripts/tls-files/client.pem \
156209
https://localhost:8090/api/wallets/keys
157210
```
158211

@@ -217,6 +270,7 @@ using environment variables as follows:
217270
LANG=en_GB.UTF-8 LC_ALL=en_GB.UTF-8 stack exec -- ...
218271
```
219272

273+
220274
##### API returns `415 Unsupported Media Type`
221275

222276
The wallet's API can be quite picky about media-types and expect both a given type and an
@@ -232,3 +286,10 @@ value:
232286
```
233287
application/json;charset=utf-8
234288
```
289+
290+
291+
##### API returns `error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown`
292+
293+
You're missing a valid client certificate to contact the node. For development, you may run the
294+
node with `--no-client-auth` or provide a valid corresponding client x509 certificates. More
295+
information in [docs/tls-authentication.md](../docs/tls-authentication.md).

cardano-sl-wallet-new.cabal

+4-3
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ library
129129
Cardano.Wallet.Server.CLI
130130
Cardano.Wallet.Server.Plugins
131131
Cardano.Wallet.TypeLits
132+
Cardano.Wallet.Types.UtxoStatistics
132133
Cardano.Wallet.Client
133134
Cardano.Wallet.Client.Http
134135

@@ -175,7 +176,6 @@ library
175176
, cardano-sl-node-ipc
176177
, cardano-sl-util
177178
, cardano-sl-wallet
178-
, cardano-sl-wallet-test
179179
, cereal
180180
, conduit
181181
, connection
@@ -194,6 +194,7 @@ library
194194
, http-client-tls
195195
, http-types
196196
, ixset-typed
197+
, foldl
197198
, lens
198199
, log-warper
199200
, memory
@@ -207,6 +208,7 @@ library
207208
, reflection
208209
, resourcet
209210
, retry
211+
, stm
210212
, safecopy
211213
, safe-exceptions
212214
, serokell-util
@@ -354,6 +356,7 @@ executable wal-integr-test
354356
, aeson-diff
355357
, aeson-pretty
356358
, bytestring
359+
, cardano-sl
357360
, cardano-sl-core
358361
, cardano-sl-wallet
359362
, cardano-sl-wallet-new
@@ -502,7 +505,6 @@ test-suite wallet-unit-tests
502505
, data-default
503506
, formatting
504507
, hspec
505-
, ixset-typed
506508
, lens
507509
, log-warper
508510
, mtl
@@ -640,7 +642,6 @@ benchmark cardano-sl-wallet-new-bench
640642
, bytestring
641643
, cardano-sl-client
642644
, cardano-sl-core
643-
, cardano-sl-db
644645
, cardano-sl-wallet
645646
, cassava
646647
, connection

integration/QuickCheckSpecs.hs

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module QuickCheckSpecs (mkSpec) where
66

77
import Universum
88

9+
import GHC.TypeLits (KnownSymbol)
910
import Network.HTTP.Client hiding (Proxy)
1011
import Network.HTTP.Types
1112
import Servant
@@ -21,6 +22,7 @@ import qualified Cardano.Wallet.API.V1 as V0
2122
import qualified Cardano.Wallet.API.V1 as V1
2223
import Cardano.Wallet.API.V1.Parameters (WalletRequestParams,
2324
WithWalletRequestParams)
25+
import Pos.Util.Servant (CustomQueryFlag)
2426

2527
-- Our API apparently is returning JSON Arrays which is considered bad practice as very old
2628
-- browsers can be hacked: https://haacked.com/archive/2009/06/25/json-hijacking.aspx/
@@ -72,6 +74,12 @@ instance HasGenRequest sub => HasGenRequest (Tags tags :> sub) where
7274
instance HasGenRequest (sub :: *) => HasGenRequest (WalletRequestParams :> sub) where
7375
genRequest _ = genRequest (Proxy @(WithWalletRequestParams sub))
7476

77+
instance ( KnownSymbol sym
78+
, HasGenRequest sub
79+
) =>
80+
HasGenRequest (CustomQueryFlag sym flag :> sub) where
81+
genRequest _ = genRequest (Proxy @(QueryFlag sym :> sub))
82+
7583
--
7684
-- RESTful-abiding predicates
7785
--

integration/TransactionSpecs.hs

+45-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ import Control.Lens
1111
import Test.Hspec
1212
import Text.Show.Pretty (ppShow)
1313

14+
import Util
15+
16+
import qualified Data.Map.Strict as Map
1417
import qualified Pos.Core as Core
18+
import qualified Pos.Core.Txp as Txp
1519

16-
import Util
1720

1821
{-# ANN module ("HLint: ignore Reduce duplication" :: Text) #-}
1922

@@ -24,7 +27,7 @@ ppShowT :: Show a => a -> Text
2427
ppShowT = fromString . ppShow
2528

2629
transactionSpecs :: WalletRef -> WalletClient IO -> Spec
27-
transactionSpecs wRef wc = do
30+
transactionSpecs wRef wc =
2831
describe "Transactions" $ do
2932
it "posted transactions appear in the index" $ do
3033
genesis <- genesisWallet wc
@@ -187,3 +190,43 @@ transactionSpecs wRef wc = do
187190
etxn <- postTransaction wc payment
188191

189192
void $ etxn `shouldPrism` _Left
193+
194+
xit "posted transactions gives rise to nonempty Utxo histogram" $ do
195+
genesis <- genesisWallet wc
196+
(fromAcct, _) <- firstAccountAndId wc genesis
197+
198+
wallet <- sampleWallet wRef wc
199+
(_, toAddr) <- firstAccountAndId wc wallet
200+
201+
let payment val = Payment
202+
{ pmtSource = PaymentSource
203+
{ psWalletId = walId genesis
204+
, psAccountIndex = accIndex fromAcct
205+
}
206+
, pmtDestinations = pure PaymentDistribution
207+
{ pdAddress = addrId toAddr
208+
, pdAmount = V1 (Core.mkCoin val)
209+
}
210+
, pmtGroupingPolicy = Nothing
211+
, pmtSpendingPassword = Nothing
212+
}
213+
214+
eresp0 <- getUtxoStatistics wc (walId wallet)
215+
utxoStatistics0 <- fmap wrData eresp0 `shouldPrism` _Right
216+
let utxoStatistics0Expected = computeUtxoStatistics log10 []
217+
utxoStatistics0 `shouldBe` utxoStatistics0Expected
218+
219+
void $ postTransaction wc (payment 1)
220+
threadDelay 120000000
221+
222+
let txIn = Txp.TxInUnknown 0 "test"
223+
let txOut = Txp.TxOutAux Txp.TxOut
224+
{ Txp.txOutAddress = unV1 (addrId toAddr)
225+
, Txp.txOutValue = Core.mkCoin 1
226+
}
227+
let utxos = [Map.fromList [(txIn, txOut)]]
228+
229+
eresp <- getUtxoStatistics wc (walId wallet)
230+
utxoStatistics <- fmap wrData eresp `shouldPrism` _Right
231+
let utxoStatisticsExpected = computeUtxoStatistics log10 utxos
232+
utxoStatistics `shouldBe` utxoStatisticsExpected

integration/WalletSpecs.hs

+10-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Util
1313

1414

1515
walletSpecs :: WalletRef -> WalletClient IO -> Spec
16-
walletSpecs _ wc = do
16+
walletSpecs _ wc =
1717
describe "Wallets" $ do
1818
it "Creating a wallet makes it available." $ do
1919
newWallet <- randomWallet CreateWallet
@@ -51,6 +51,15 @@ walletSpecs _ wc = do
5151
}
5252

5353
eresp `shouldPrism_` _Right
54+
55+
it "creating wallet gives rise to an empty Utxo histogram" $ do
56+
newWallet <- randomWallet CreateWallet
57+
wallet <- createWalletCheck wc newWallet
58+
59+
eresp <- getUtxoStatistics wc (walId wallet)
60+
utxoStatistics <- fmap wrData eresp `shouldPrism` _Right
61+
let utxoStatisticsExpected = computeUtxoStatistics log10 []
62+
utxoStatistics `shouldBe` utxoStatisticsExpected
5463
where
5564
testWalletAlreadyExists action = do
5665
newWallet1 <- randomWallet action

src/Cardano/Wallet/API/V1/Handlers/Info.hs

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ import Servant
66

77
import Cardano.Wallet.API.Response (WalletResponse, single)
88
import qualified Cardano.Wallet.API.V1.Info as Info
9-
import Cardano.Wallet.API.V1.Types (NodeInfo)
9+
import Cardano.Wallet.API.V1.Types (ForceNtpCheck, NodeInfo)
1010
import Cardano.Wallet.WalletLayer (ActiveWalletLayer)
1111
import qualified Cardano.Wallet.WalletLayer as WalletLayer
1212

1313
handlers :: ActiveWalletLayer IO -> ServerT Info.API Handler
1414
handlers = getNodeInfo
1515

16-
getNodeInfo :: ActiveWalletLayer IO -> Handler (WalletResponse NodeInfo)
17-
getNodeInfo w = liftIO $ single <$> WalletLayer.getNodeInfo w
16+
getNodeInfo
17+
:: ActiveWalletLayer IO
18+
-> ForceNtpCheck
19+
-> Handler (WalletResponse NodeInfo)
20+
getNodeInfo w forceNtp =
21+
liftIO $ single <$> WalletLayer.getNodeInfo w forceNtp

src/Cardano/Wallet/API/V1/Handlers/Wallets.hs

+15-3
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ module Cardano.Wallet.API.V1.Handlers.Wallets where
22

33
import Universum
44

5-
import Pos.Core (Coin)
5+
import Servant
66

77
import Cardano.Wallet.API.Request
88
import Cardano.Wallet.API.Response
99
import Cardano.Wallet.API.V1.Types as V1
1010
import qualified Cardano.Wallet.API.V1.Wallets as Wallets
11-
1211
import Cardano.Wallet.WalletLayer (PassiveWalletLayer)
1312
import qualified Cardano.Wallet.WalletLayer as WalletLayer
1413

15-
import Servant
14+
import Pos.Core.Common (Coin (..))
15+
1616

1717
-- | All the @Servant@ handlers for wallet-specific operations.
1818
handlers :: PassiveWalletLayer IO -> ServerT Wallets.API Handler
@@ -22,6 +22,7 @@ handlers pwl = newWallet pwl
2222
:<|> deleteWallet pwl
2323
:<|> getWallet pwl
2424
:<|> updateWallet pwl
25+
:<|> getUtxoStatistics pwl
2526
:<|> checkExternalWallet pwl
2627
:<|> newExternalWallet pwl
2728
:<|> deleteExternalWallet pwl
@@ -96,6 +97,17 @@ updateWallet pwl wid walletUpdateRequest = do
9697
Left e -> throwM e
9798
Right w -> return $ single w
9899

100+
getUtxoStatistics
101+
:: PassiveWalletLayer IO
102+
-> WalletId
103+
-> Handler (WalletResponse UtxoStatistics)
104+
getUtxoStatistics pwl wid = do
105+
res <- liftIO $ WalletLayer.getUtxos pwl wid
106+
case res of
107+
Left e -> throwM e
108+
Right w ->
109+
return $ single $ V1.computeUtxoStatistics V1.log10 (map snd w)
110+
99111
checkExternalWallet :: PassiveWalletLayer IO
100112
-> PublicKeyAsBase58
101113
-> Handler (WalletResponse WalletAndTxHistory)

src/Cardano/Wallet/API/V1/Info.hs

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import Cardano.Wallet.API.Response (ValidJSON, WalletResponse)
44
import Cardano.Wallet.API.Types
55
import Cardano.Wallet.API.V1.Types
66

7+
import Pos.Util.Servant (CustomQueryFlag)
78
import Servant
89

910
type API = Tags '["Info"] :>
10-
( "node-info" :> Summary "Retrieves the dynamic information for this node."
11-
:> Get '[ValidJSON] (WalletResponse NodeInfo)
11+
( "node-info" :> Summary "Retrieves the dynamic information for this node."
12+
:> CustomQueryFlag "force_ntp_check" ForceNtpCheck
13+
:> Get '[ValidJSON] (WalletResponse NodeInfo)
1214
)

0 commit comments

Comments
 (0)