Plutus Tuto – Part 1

Hi guys!
Let’s now have a look at what Plutus look like now.

We will have a look and detail the different sample code that IOHK provides us in a first time to be able to understand clearly what is going on exactly, and I’ll do my best to be as clear as possible about it. One piece of advice though, if you have the opportunity, learn a bit of Haskell. Compared to other code, Haskell can be quite easy, but there are some magic happening sometime which are easier to apprehend with some background on the subject. Moreover, learning Haskell is cool 😀

One great resource that I used to learn Haskell: http://learnyouahaskell.com/

Here is the link of the Plutus playground that IOHK provides: https://prod.playground.plutus.iohkdev.io/
It is the easiest way to get started, and if you want, you can decide to setup your own environment. 

An other resource that I use a lot is the doc that they provide about Plutus: https://input-output-hk.github.io/plutus/

So let’s go!!!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
-- Contract endpoints that generate different kinds of errors for the log:
-- logAMessage produces a log message from a wallet
-- submitInvalidTxn submits an invalid txn which should result in a "Validation failed" message
-- throwWalletAPIError throws an error from a wallet (client)
module Language.PlutusTx.Coordination.Contracts.Messages where

import qualified Data.Set                     as Set
import           Data.Text                    (Text)

import           Ledger
import           Ledger.Validation
import           Wallet
import           Playground.Contract

logAMessage :: MockWallet ()
logAMessage = logMsg "wallet log"

submitInvalidTxn :: MockWallet ()
submitInvalidTxn = do
    logMsg "Preparing to submit an invalid transaction"
    let tx = Tx
            { txInputs = Set.empty
            , txOutputs = []
            , txForge = 2
            , txFee = 0
            , txSignatures = []
            }
    submitTxn tx

throwWalletAPIError :: Text -> MockWallet ()
throwWalletAPIError = throwOtherError

$(mkFunction 'logAMessage)
$(mkFunction 'submitInvalidTxn)
$(mkFunction 'throwWalletAPIError)

The first type of interest in this script is the MockWallet type. This type implement different Type Classes, which is Haskell’s way to implement function overloading. This type implement the main following type classes:

There are other implementation on this type, but they are more for technical reason, and we won’t look at them now.

The fact that MockWallet implements Monad in this case enables you to use this do notation which is syntax sugar to a more complicated notation we won’t dive into here. This is Haskell’s way to wrap side effect and help the developer managing them.

The WalletAPI one enables you to the following function: 

  • submitTxn :: Tx -> MockWallet ()
  • myKeyPair :: MockWallet KeyPair
  • createPaymentWithChange :: Value -> MockWallet (Set TxIn', Maybe TxOut')
  • register :: EventTrigger -> EventHandler MockWallet -> MockWallet ()
  • watchedAddresses :: MockWallet AddressMap
  • startWatching :: Address' -> MockWallet ()
  • blockHeight :: MockWallet Height

As you can, the MockWallet type here is used to wrapping up different kind of side effect, the same way the IO does. It can wrap something that doesn’t return anything (that’s what the () means), a pair of cryptographic keys, registering events…

Regarding the WalletDiagnostics, it implements only one function:

logMsg :: Text -> MockWallet ()

Which enables you to…. log things! (No shit Sherlock!)

So, at that point, I believe the first function is quite easier to understand: you call logMsg on a Text, it returns a MockWallet of (), which mean essentially that it returns nothing, and that’s it. You just logged a message.

The second function is quite the same thing, but with more operations going on.

You first log a message, and discard the result of it. Then you create a transaction by using the Tx type constructor. Here is the constructor in question:


1
2
3
4
5
6
Tx   
    txInputs :: Set TxIn'    
    txOutputs :: [TxOut']    
    txForge :: !Value    
    txFee :: !Value  
    txSignatures :: [Signature]

Looking at the transaction which is defined in our code, we can imagine that it won’t go very well when we execute it…

The last function we define is just some dummy function which throws an error.

Then, we have some funny thing at the end of the script, which are just here for the playground to be able to use these functions, nothing to worry about here.

Once important thing to notice here, we haven’t written any Plutus code here in fact. We are just playing around with the API that is exposed to use, and we will discussed the benefit of being able to do this kind of things.

It’s time now to plug all of this in the playground and see what is going on here!

Let first setup 2 wallets from which we will be sending different events. The vents that will be happening are the following:

  • Log a message from Wallet #1
  • Wait for 10 blocks
  • Log a message from Wallet #2
  • Wait for 10 blocks
  • Throw a walletError from Wallet #2

As we can see in the logs, the workflow we described above are happening in the correct order and the balance of the different portfolio didn’t change.

Leave a Reply

Your email address will not be published. Required fields are marked *