0

Server seems to have built ok:

[nix-shell:~/plutus/plutus-starter]$ cabal build plutus-starter-pab
Resolving dependencies...
Up to date

I am using Plutus-Starter project on Macbook Monterey M1 but have not been able to generate the wallet Ids or confirm that the server fully started. It seems to just say "[INFO] Starting PAB backend server on port 9080" full log is below. Is there a verbose mode for starting the server?

[nix-shell:~/plutus/plutus-starter]$ cabal exec -- plutus-starter-pab
[INFO] Slot 0: TxnValidate 08111487e032e647e23e6e6866665ab726a4c92532e9589f9e670f2585e35807
[INFO] Starting plutus-starter PAB webserver on port 9080. Press enter to exit.
[INFO] W[2]: Balancing an unbalanced transaction:
               Tx:
                 Tx 318797441458154cf284463902d8e152cc240ab65a58fff5287b0a1f5d5de3a1:
                   {inputs:
                   collateral inputs:
                   outputs:
                     - Value (Map [(,Map [("",10000000000)])]) addressed to
                       PubKeyCredential: bb22a3608c50bdb141d2f1255836a7f4fc829a47d801c985746cfca6 (no staking credential)
                   mint: Value (Map [])
                   fee: Value (Map [])
                   mps:
                   signatures:
                   validity range: Interval {ivFrom = LowerBound NegInf True, ivTo = UpperBound PosInf True}
                   data:}
               Requires signatures:
               Utxo index:
               Validity range:
                 (-∞ , +∞)
[INFO] W[2]: Finished balancing:
               Tx e5581a9ec85d0525e8aee67e8ec2e453b6e098121aa29fab8698ff091ebd3bd6:
                 {inputs:
                    - 08111487e032e647e23e6e6866665ab726a4c92532e9589f9e670f2585e35807!20

                    - 08111487e032e647e23e6e6866665ab726a4c92532e9589f9e670f2585e35807!21

                 collateral inputs:
                   - 08111487e032e647e23e6e6866665ab726a4c92532e9589f9e670f2585e35807!20

                 outputs:
                   - Value (Map [(,Map [("",9999999489)])]) addressed to
                     PubKeyCredential: 80a4f45b56b88d1139da23bc4c3c75ec6d32943c087f250b86193ca7 (no staking credential)
                   - Value (Map [(,Map [("",10000000000)])]) addressed to
                     PubKeyCredential: bb22a3608c50bdb141d2f1255836a7f4fc829a47d801c985746cfca6 (no staking credential)
                 mint: Value (Map [])
                 fee: Value (Map [(,Map [("",511)])])
                 mps:
                 signatures:
                 validity range: Interval {ivFrom = LowerBound NegInf True, ivTo = UpperBound PosInf True}
                 data:}
[INFO] W[2]: Signing tx: e5581a9ec85d0525e8aee67e8ec2e453b6e098121aa29fab8698ff091ebd3bd6
[INFO] W[2]: Submitting tx: e5581a9ec85d0525e8aee67e8ec2e453b6e098121aa29fab8698ff091ebd3bd6
[INFO] Slot 1: TxnValidate e5581a9ec85d0525e8aee67e8ec2e453b6e098121aa29fab8698ff091ebd3bd6
[INFO] Starting PAB backend server on port 9080

I don't see confirmation that it fully started but there is a response to service definition request:

 % curl -s http://localhost:9080/api/contract/definitions | jq
[
  {
    "csrSchemas": [
      {
        "argument": {
          "contents": [
            [
              "guessWord",
              {
                "tag": "FormSchemaString"
              }
            ]
          ],
          "tag": "FormSchemaObject"
        },
        "endpointDescription": {
          "getEndpointDescription": "guess"
        }
      },
      {
        "argument": {
          "contents": [
            [
              "secretWord",
              {
                "tag": "FormSchemaString"
              }
            ],
            [
              "amount",
              {
                "tag": "FormSchemaValue"
              }
            ]
          ],
          "tag": "FormSchemaObject"
        },
        "endpointDescription": {
          "getEndpointDescription": "lock"
        }
      }
    ],
    "csrDefinition": "GameContract"
  }
]

This does not seem to include enough endpoint information.

And the Wallet Creation request returns empty

deano@Ds-MacBook-Pro ~ % curl -s -d '' http://localhost:9080/wallet/create
deano@Ds-MacBook-Pro ~ % 

Update: Digging into the source I see some instructions in a readme file related to starting the PAB backend server for a local cluster but I am not sure this is related.

cat ./dist-newstyle/src/plutus-ap_-cbcc5c6ab544aad6/plutus-pab-executables/README.md
#### Example

1. Build necessary components:

cabal build plutus-pab-local-cluster


2. Get config data:

  Clone <https://github.com/input-output-hk/cardano-wallet/> to $DIR and set the
  `SHELLEY_TEST_DATA` environment variable:

export SHELLEY_TEST_DATA=$DIR/lib/shelley/test/data/cardano-node-shelley


3. Run the local cluster:

cabal exec plutus-pab-local-cluster


4. Wait until the message `Starting PAB backend server on port 9080` appears.

5. Run the integration test:

curl -H "Content-Type: application/json" -v \
       -X POST \
       -d '{"caID":{"tag":"IntegrationTest"},"caWallet":{"getWalletId":"2d4cc31a4b3116ab86bfe529d30d9c362acd0b44"}}' \
       localhost:9080/api/contract/activate


A couple of log messages appear, the last one should say something like "Tx
confirmed. Integration test complete."

PAB Server starting message seems to be in PABLogMsg

I don't see there there is any message available within PABLogMsg to confirm a successful start. I think there are no further messages about this. However there is some reason the PAB Server cannot create the walletId. Do I need to be running anything else for this to work?

[nix-shell:~/plutus/plutus-starter]$ cat ./dist-newstyle/src/plutus-ap_-cbcc5c6ab544aad6/plutus-pab/src/Plutus/PAB/Monitoring/PABLogMsg.hs
{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE DeriveAnyClass       #-}
{-# LANGUAGE DeriveGeneric        #-}
{-# LANGUAGE DerivingVia          #-}
{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE LambdaCase           #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE TypeApplications     #-}
{-# LANGUAGE UndecidableInstances #-}

-- | PAB Log messages and instances
module Plutus.PAB.Monitoring.PABLogMsg(
    PABLogMsg(..),
    ChainIndexServerMsg,
    WalletMsg,
    PABServerLogMsg,
    AppMsg(..),
    CoreMsg(..),
    PABMultiAgentMsg(..),
    RequestSize(..),
    WalletClientMsg(..)
    ) where

import Cardano.Api qualified as C
import Cardano.BM.Data.Tracer (ToObject (toObject), TracingVerbosity (MaximalVerbosity))
import Cardano.BM.Data.Tracer.Extras (StructuredLog, Tagged (Tagged), mkObjectStr)
import Cardano.ChainIndex.Types (ChainIndexServerMsg)
import Cardano.Node.Types (PABServerConfig, PABServerLogMsg)
import Cardano.Wallet.Mock.Types (WalletMsg)
import Control.Monad.Freer.Extras.Beam (BeamLog)
import Data.Aeson (FromJSON, ToJSON, Value)
import Data.Aeson.Text (encodeToLazyText)
import Data.Text (Text)
import Data.Text qualified as T
import GHC.Generics (Generic)
import Plutus.Contract.Effects (PABReq, PABResp)
import Plutus.Contract.Resumable (Response)
import Plutus.Contract.State (ContractResponse)
import Plutus.PAB.Core.ContractInstance (ContractInstanceMsg)
import Plutus.PAB.Effects.Contract (PABContract (..))
import Plutus.PAB.Events.Contract (ContractInstanceId)
import Plutus.PAB.Instances ()
import Prettyprinter (Pretty (pretty), colon, line, viaShow, (<+>))
import Wallet.Emulator.LogMessages (TxBalanceMsg)
import Wallet.Emulator.MultiAgent (EmulatorEvent)
import Wallet.Emulator.Wallet (Wallet)

data WalletClientMsg =
    WalletClientError String
    | BalanceTxError String
    deriving stock (Eq, Show, Generic)
    deriving anyclass (ToJSON, FromJSON)

instance Pretty WalletClientMsg where
    pretty = viaShow

instance ToObject WalletClientMsg where
    toObject _ m = mkObjectStr (T.pack $ show m) ()

data AppMsg t =
    ActiveContractsMsg
    | ContractHistoryMsg
    | PABMsg (PABLogMsg t)
    | AvailableContract Text
    | ContractInstances (ContractDef t) [ContractInstanceId]
    | ContractHistoryItem ContractInstanceId (Response PABResp)
    deriving stock (Generic)

deriving stock instance (Show (ContractDef t)) => Show (AppMsg t)
deriving anyclass instance (ToJSON (ContractDef t)) => ToJSON (AppMsg t)
deriving anyclass instance (FromJSON (ContractDef t)) => FromJSON (AppMsg t)

instance (Pretty (ContractDef t)) => Pretty (AppMsg t) where
    pretty = \case
        ActiveContractsMsg               -> "Active contracts"
        ContractHistoryMsg               -> "Contract history"
        PABMsg m                         -> pretty m
        AvailableContract t              -> pretty t
        ContractInstances t s            -> pretty t <+> pretty s
        ContractHistoryItem instanceId s -> pretty instanceId <> colon <+> pretty (fmap encodeToLazyText s)

data PABLogMsg t =
    SCoreMsg (CoreMsg t)
    | SChainIndexServerMsg ChainIndexServerMsg
    | SWalletMsg WalletMsg
    | SMockserverLogMsg PABServerLogMsg
    | SMultiAgent (PABMultiAgentMsg t)
    deriving stock (Generic)

deriving stock instance (Show (ContractDef t)) => Show (PABLogMsg t)
deriving anyclass instance (ToJSON (ContractDef t)) => ToJSON (PABLogMsg t)
deriving anyclass instance (FromJSON (ContractDef t)) => FromJSON (PABLogMsg t)

instance Pretty (ContractDef t) => Pretty (PABLogMsg t) where
    pretty = \case
        SCoreMsg m             -> pretty m
        SChainIndexServerMsg m -> pretty m
        SWalletMsg m           -> pretty m
        SMockserverLogMsg m    -> pretty m
        SMultiAgent m          -> pretty m



{- ToObject instances

'ToObject.toObject' is very similar to 'ToJSON.toJSON' except that

* 'toObject' has an additional paramter for verbosity
* 'toObject' must always produce a JSON object (key-value map)

In the definitions below, every object produced by 'toObject' has a field
'string' with a friendly description of the message, similar to its
'Pretty' instance. Additional fields depend on the type of message.

-}

instance (ToJSON (ContractDef t), StructuredLog (ContractDef t)) => ToObject (AppMsg t) where
    toObject v = \case
        ActiveContractsMsg ->
            mkObjectStr "Listing active contract instances" ()
        ContractHistoryMsg ->
            mkObjectStr "Showing contract history" ()
        PABMsg m -> toObject v m
        AvailableContract t ->
            mkObjectStr "Available contract" t
        ContractInstances exe ids ->
            mkObjectStr
                "Active instances for contract"
                (exe, Tagged @"instances" ids)
        ContractHistoryItem i state ->
            mkObjectStr "Contract history item" $
                case v of
                    MaximalVerbosity -> Left (i, state)
                    _                -> Right i

instance (StructuredLog (ContractDef t), ToJSON (ContractDef t)) => ToObject (PABLogMsg t) where
    toObject v = \case
        SCoreMsg m             -> toObject v m
        SChainIndexServerMsg m -> toObject v m
        SWalletMsg m           -> toObject v m
        SMockserverLogMsg m    -> toObject v m
        SMultiAgent m          -> toObject v m

-- | FIXME: Redundant?
data PABMultiAgentMsg t =
    EmulatorMsg EmulatorEvent
    | ContractInstanceLog (ContractInstanceMsg t)
    | UserLog T.Text
    | BeamLogItem BeamLog
    | PABStateRestored Int
    | RestoringPABState
    | StartingPABBackendServer Int
    | WalletBalancingMsg Wallet TxBalanceMsg
    | WalletClient WalletClientMsg
    deriving stock Generic

instance (StructuredLog (ContractDef t), ToJSON (ContractDef t)) => ToObject (PABMultiAgentMsg t) where
    toObject v = \case
        EmulatorMsg e              -> mkObjectStr "emulator message" (Tagged @"payload" e)
        ContractInstanceLog m      -> toObject v m
        UserLog t                  -> toObject v t
        BeamLogItem b              -> toObject v b
        RestoringPABState          -> mkObjectStr "Restoring PAB state ..." ()
        PABStateRestored n         -> mkObjectStr ( "PAB state restored with "
                                                 <> T.pack (show n)
                                                 <> " contract instance(s)."
                                                  ) ()
        StartingPABBackendServer i -> mkObjectStr "starting backend server" (Tagged @"port" i)
        WalletBalancingMsg w m     -> mkObjectStr "balancing" (Tagged @"wallet" w, Tagged @"message" m)
        WalletClient m -> toObject v m

deriving stock instance (Show (ContractDef t)) => Show (PABMultiAgentMsg t)
deriving anyclass instance (ToJSON (ContractDef t)) => ToJSON (PABMultiAgentMsg t)
deriving anyclass instance (FromJSON (ContractDef t)) => FromJSON (PABMultiAgentMsg t)

instance Pretty (ContractDef t) => Pretty (PABMultiAgentMsg t) where
    pretty = \case
        EmulatorMsg m         -> pretty m
        ContractInstanceLog m -> pretty m
        UserLog m             -> pretty m
        BeamLogItem b         -> pretty b
        RestoringPABState     -> "Restoring PAB state ..."
        PABStateRestored 0    -> "No contract instance were restored in the PAB state."
        PABStateRestored 1    -> "PAB state restored with 1 contract instance."
        PABStateRestored n    -> "PAB state restored with"
                              <+> pretty n
                              <+> "contract instances."
        StartingPABBackendServer port ->
            "Starting PAB backend server on port" <+> pretty port
        WalletBalancingMsg w m -> pretty w <> colon <+> pretty m
        WalletClient m -> pretty m

data CoreMsg t =
    FindingContract ContractInstanceId
    | FoundContract (Maybe (ContractResponse Value Value PABResp PABReq))
    | ConnectingToAlonzoNode PABServerConfig C.SlotNo
    deriving stock Generic

deriving stock instance (Show (ContractDef t)) => Show (CoreMsg t)
deriving anyclass instance (ToJSON (ContractDef t)) => ToJSON (CoreMsg t)
deriving anyclass instance (FromJSON (ContractDef t)) => FromJSON (CoreMsg t)

instance Pretty (ContractDef t) => Pretty (CoreMsg t) where
    pretty = \case
        FindingContract i      -> "Finding contract" <+> pretty i
        FoundContract c        -> "Found contract" <+> viaShow c
        ConnectingToAlonzoNode config slotNo ->
                "Connecting to Alonzo node with config:"
            <>  line
            <>  pretty config
            <>  line
            <>  "The tip of the local node:"
            <+> viaShow slotNo

instance (StructuredLog (ContractDef t), ToJSON (ContractDef t)) => ToObject (CoreMsg t) where
    toObject v = \case
        FindingContract instanceID ->
            mkObjectStr "finding contract instance" instanceID
        FoundContract state ->
            mkObjectStr "found contract" $
                case v of
                    MaximalVerbosity -> Left (Tagged @"contract" state)
                    _                -> Right ()
        ConnectingToAlonzoNode _ _ -> mkObjectStr "Connecting to Alonzo node" ()

newtype RequestSize = RequestSize Int
    deriving stock (Show)
    deriving newtype (ToJSON, FromJSON)

instance Pretty RequestSize where
    pretty (RequestSize i) = pretty i <+> "bytes"

1 Answer 1

0

I realize that this doesn't directly answer your question, but I spent a lot of time (too much?) on getting the pab local cluster working. The issue is that you will need to pivot away from the PAB when you get to the testnet because there are limitation using the pab on the testnet (shared wallet passwords, 3+ days for chain index synch, etc.) and not even possible using it on mainnet. The PAB is awesome for development and using the simlutor, but it ends there.

So, in hindsight it is probably best to just focus on using a local devnet from cardano-node directly. Then interact with your plutus scripts the way you will when you get to the testnet and mainnet.

I've just released The Open Source Cardano Lottery project and in that repository is working code and script examples for setting up & interacting with a local devnet and a testnet. It has basic shell scripts for a PAB, but there are other options out there but I have not tried them (eg. PyCardano, cardano-serialization-lib ).

https://github.com/lley154/cardano-lottery

Hope this helps!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.