Skip to content

Commit

Permalink
[ADP-3305] Add send faucet end-point to local cluster (#4566)
Browse files Browse the repository at this point in the history
- [x] Add a send faucet assets end-point to the local cluster http
service

ADP-3305
  • Loading branch information
paolino authored May 9, 2024
2 parents 124a01c + 65c1da1 commit 6dc7c03
Show file tree
Hide file tree
Showing 31 changed files with 1,833 additions and 458 deletions.
4 changes: 2 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ bench target:
local-cluster:
nix shell '.#local-cluster' '.#cardano-node' \
-c "local-cluster" \
control \
--cluster-configs lib/local-cluster/test/data/cluster-configs \
--cluster-logs ignore-me/cluster.logs \
--socket-path ignore-me/cluster.socket
--socket-path ignore-me/cluster.socket \
--monitoring-port 12788

# run unit tests on a match
unit-tests-cabal-match match:
Expand Down
85 changes: 85 additions & 0 deletions lib/local-cluster/data/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,69 @@
},
"Ready": {
"type": "boolean"
},
"SendAssets": {
"properties": {
"assets": {
"items": {
"properties": {
"address": {
"type": "string"
},
"bundle": {
"properties": {
"assets": {
"items": {
"properties": {
"asset": {
"properties": {
"name": {
"type": "string"
},
"policy": {
"type": "string"
}
},
"type": "object"
},
"quantity": {
"type": "integer"
}
},
"type": "object"
},
"type": "array"
},
"coin": {
"type": "integer"
}
},
"type": "object"
},
"metadata": {
"items": {
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
},
"type": "array"
},
"batch-size": {
"type": "integer"
}
},
"type": "object"
}
}
},
Expand Down Expand Up @@ -210,6 +273,28 @@
},
"summary": "Check if the local-cluster is ready"
}
},
"/send/assets": {
"parameters": [
{
"in": "path",
"name": "assets",
"schema": {
"$ref": "#/components/schemas/SendAssets"
}
}
],
"post": {
"responses": {
"204": {
"content": {
"application/json": {}
},
"description": "No Content"
}
},
"summary": "Send assets to the faucet"
}
}
}
}
94 changes: 94 additions & 0 deletions lib/local-cluster/lib/Cardano/Wallet/Faucet/Gen/Address.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.Wallet.Faucet.Gen.Address
( genAddress
, NetworkTag (..)
, allTags
)
where

import Prelude

import Cardano.Address
( Address
, unsafeMkAddress
)
import Data.Bits
( Bits (shiftL, (.|.))
)
import Data.ByteString
( ByteString
)
import Data.Word
( Word8
)
import Test.QuickCheck
( Arbitrary (arbitrary)
, Gen
, elements
, vectorOf
)

import qualified Data.ByteString as BS

{-
ADDRESS = %b0000 | NETWORK-TAG | KEY-HASH | KEY-HASH ; type 00, Base Shelley address
\ %b0001 | NETWORK-TAG | SCRIPT-HASH | KEY-HASH ; type 01, Base Shelley address
\ %b0010 | NETWORK-TAG | KEY-HASH | SCRIPT-HASH ; type 02, Base Shelley address
\ %b0011 | NETWORK-TAG | SCRIPT-HASH | SCRIPT-HASH ; type 03, Base Shelley address
\ %b0100 | NETWORK-TAG | KEY-HASH | POINTER ; type 04, Pointer Shelley address
\ %b0101 | NETWORK-TAG | SCRIPT-HASH | POINTER ; type 05, Pointer Shelley address
\ %b0110 | NETWORK-TAG | KEY-HASH ; type 06, Payment Shelley address
\ %b0111 | NETWORK-TAG | SCRIPT-HASH ; type 07, Payment Shelley address
\ %b1000 | BYRON-PAYLOAD ; type 08, Byron / Bootstrap address
\ %b1110 | NETWORK-TAG | KEY-HASH ; type 14, Stake Shelley address
\ %b1111 | NETWORK-TAG | SCRIPT-HASH ; type 15, Stake Shelley address
NETWORK-TAG = %b0000 ; Testnet
\ %b0001 ; Mainnet
POINTER = VARIABLE-LENGTH-UINT ; slot number
| VARIABLE-LENGTH-UINT ; transaction index
| VARIABLE-LENGTH-UINT ; certificate index
VARIABLE-LENGTH-UINT = (%b1 | UINT7 | VARIABLE-LENGTH-UINT)
/ (%b0 | UINT7)
UINT7 = 7BIT
KEY-HASH = 28OCTET
SCRIPT-HASH= 28OCTET
BYRON-PAYLOAD = *OCTET ; see 'Byron Addresses' section or cddl specification.
-}

data NetworkTag = TestnetTag | MainnetTag

tag :: NetworkTag -> Word8
tag TestnetTag = 0
tag MainnetTag = 1

allTags :: [NetworkTag]
allTags = [TestnetTag, MainnetTag]

genPrefix :: [NetworkTag] -> [Word8] -> Gen Word8
genPrefix ts xs = do
network <- elements ts
prefix <- elements xs
pure $ prefix `shiftL` 4 .|. tag network

genHash :: Gen ByteString
genHash = BS.pack <$> vectorOf 28 arbitrary

-- | Generate a random address for the given networks excluding the Byron addresses.
genAddress :: [NetworkTag] -> Gen Address
genAddress tags = fmap unsafeMkAddress $ do
hash1 <- genHash
hash2 <- genHash
prefixONE <- genPrefix tags [6, 7]
prefixTWO <- genPrefix tags [0, 1, 2, 3]
elements
[ prefixONE `BS.cons` hash1
, prefixTWO `BS.cons` hash1 <> hash2
]
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -Wno-missing-local-signatures #-}

module Cardano.Wallet.Launch.Cluster.Monitoring.Monitor
module Cardano.Wallet.Launch.Cluster.Http
( MsgHttpMonitoring (..)
, MonitorConfiguration (..)
, withMonitoring
Expand All @@ -13,14 +13,14 @@ where

import Prelude

import Cardano.Wallet.Launch.Cluster.Monitoring.Http.Client
import Cardano.Wallet.Launch.Cluster.Http.Monitor.Client
( RunQuery
, withHttpClient
)
import Cardano.Wallet.Launch.Cluster.Monitoring.Http.Logging
import Cardano.Wallet.Launch.Cluster.Http.Monitor.Logging
( MsgHttpMonitoring (..)
)
import Cardano.Wallet.Launch.Cluster.Monitoring.Http.Server
import Cardano.Wallet.Launch.Cluster.Http.Monitor.Server
( mkHandlers
, withHttpServer
)
Expand Down
19 changes: 19 additions & 0 deletions lib/local-cluster/lib/Cardano/Wallet/Launch/Cluster/Http/API.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{-# LANGUAGE TypeOperators #-}

module Cardano.Wallet.Launch.Cluster.Http.API
( API
)
where

import Cardano.Wallet.Launch.Cluster.Http.Faucet.API
( FaucetAPI
)
import Cardano.Wallet.Launch.Cluster.Http.Monitor.API
( ControlAPI
)
import Servant.API
( (:<|>)
)

-- | The API for the monitoring server and the query cluster application
type API n = ControlAPI :<|> FaucetAPI n
116 changes: 116 additions & 0 deletions lib/local-cluster/lib/Cardano/Wallet/Launch/Cluster/Http/Client.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.Wallet.Launch.Cluster.Http.Client
( withHttpClient
, MsgClient (..)
)
where

import Prelude

import Cardano.Wallet.Launch.Cluster.Http.Faucet.Client
( MsgFaucetClient
, RunFaucetQ
, mkFaucet
, newFaucetQ
)
import Cardano.Wallet.Launch.Cluster.Http.Monitor.Client
( MsgMonitorClient
, RunMonitorQ
, mkMonitorClient
, newRunQuery
)
import Cardano.Wallet.Primitive.NetworkId
( HasSNetworkId
, SNetworkId
)
import Control.Monad.Cont
( ContT (..)
)
import Control.Monad.IO.Class
( liftIO
)
import Control.Tracer
( Tracer
, traceWith
)
import Data.Functor.Contravariant
( (>$<)
)
import Data.Text.Class
( ToText (..)
)
import Network.HTTP.Client
( ManagerSettings (..)
, defaultManagerSettings
, newManager
, responseTimeoutNone
)
import Network.Socket
( PortNumber
)
import Servant.Client
( BaseUrl (..)
, ClientM
, Scheme (..)
, mkClientEnv
, runClientM
)
import UnliftIO
( MonadUnliftIO
, throwIO
)

data MsgClient
= MsgClientStart
| MsgClientDone
| MsgMonitorClient MsgMonitorClient
| MsgFaucetClient MsgFaucetClient
deriving stock (Show)

instance ToText MsgClient where
toText = \case
MsgClientStart -> "HTTP client started"
MsgClientDone -> "HTTP client done"
MsgMonitorClient msg -> toText msg
MsgFaucetClient msg -> toText msg

-- | Produce a closure over the http client of an http monitoring server that
-- can be used to query the server.
withHttpClient
:: (MonadUnliftIO m, HasSNetworkId n)
=> SNetworkId n
-> Tracer m MsgClient
-- ^ how to trace the http client operations
-> PortNumber
-- ^ Monitoring port to attach to (http://localhost is hardcoded)
-> ContT () m (RunMonitorQ m, RunFaucetQ m)
withHttpClient networkId tracer httpPort = ContT $ \continue -> do
let tr = traceWith tracer
tr MsgClientStart
let url = BaseUrl Http "localhost" (fromIntegral httpPort) ""
manager <-
liftIO
$ newManager
$ defaultManagerSettings
{ managerResponseTimeout = responseTimeoutNone
}
let
query :: ClientM a -> IO a
query f = do
r <- runClientM f $ mkClientEnv manager url
either throwIO pure r
runQuery <- newRunQuery query (MsgMonitorClient >$< tracer) mkMonitorClient
runFaucet <-
newFaucetQ
query
(MsgFaucetClient >$< tracer)
$ mkFaucet networkId
continue (runQuery, runFaucet)

tr MsgClientDone
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}

module Cardano.Wallet.Launch.Cluster.Http.Faucet.API
( FaucetAPI
, SendFaucetAssetsAPI
)
where

import Cardano.Wallet.Launch.Cluster.Http.Faucet.SendFaucetAssets
( SendFaucetAssets
, WithNetwork (..)
)
import Servant
( JSON
, PostNoContent
, ReqBody
, (:>)
)

type SendFaucetAssetsAPI n =
"send"
:> "faucet-assets"
:> ReqBody '[JSON] (WithNetwork SendFaucetAssets n)
:> PostNoContent

type FaucetAPI n = SendFaucetAssetsAPI n
Loading

0 comments on commit 6dc7c03

Please sign in to comment.