DAML and container image manifests

Last week I wrote about belatedly learning how container image manifests work. My motivation was, in part, in order to try to prototype this mechanism.

First, in DAML:

https://github.com/DazWilkin/manifests/blob/master/daml/Manifests.daml

With thanks to Daniel and Neil for helping educate me on DAML.

If you read no further, Neil taught me two most-excellent things:

1. Hoogle

This may be an obvious solution to Haskellians (sp?) but, when I struggled to identify functions, Neil provided me with this DAML package explorer:

https://hoogle.daml.com

Hoogle is a Haskell search engine, geddit?

2. GitHub Linguist for “DAML”

Create .gitattributes and set:

*.daml linguist-language=Haskell

And benefit from GitHub language-detection of your DAMLs:

Summary

I’m a DAML neophyte and I’ve (not|never) used Haskell. I find DAML to be “unusual” but I’m able to achieve my economical goals using it. I wrote the sample referenced in this post in a couple of hours this week and spent the majority of my time, scratching around docs.daml.com to recall syntax and to find functions (e.g. lists).

In a spirit of learning by teaching, and teaching by helping others with my mistakes, I’m going to summarize my challenges here in building this sample.

Visual Studio Code

The DAML SDK works excellent with Visual Studio Code. I’m generally in need of software help particularly for code completion, signature help etc. As I “build a relationship” with DAML, the Code integration is wonderful.

Types

I know what I want (aliases, structs|records etc.) but I find the Haskell syntax a little ‘wonky’:

data SHA256 = SHA256 Text
deriving (Eq,Show)

I don’t grok why I must reproduce the ‘type’. Runtime errors guided me to adding the deriving (Eq,Show) and I suspect (!) that e.g. Eq works because it’s the same as equality on Text but… magic.

I learned that this is more simply written as:

type SHA256 = Text

And that there will be a foundational type of “SHA-256” in the SDK.

User-defined Functions

Having learned ML and Prolog back in the day, after seeing somewhere (?) in the documentation an example constructing lists a :: [b,c,d], and (pre-Hoogle) being unaware of map, I needed a way to map a list of Blob to a list of Layer. First working attempt:

computeLayers: [Blob] -> [Layer]
computeLayers [] = []
computeLayers (b::l) = (Layer with
mediaType = ""
size = computeSize b
digest = computeSHA256 b
)::computeLayers l

Which I was proud of ;-) computeLayers takes a list of Blob and returns a list of Layer. It’s defined as, not much on an empty list ([]) and recursively applies the implicit function mapping a Blob to a Layer for any other list.

Neil pointed me to Hoogle and map yielding the more elegant:

computeLayer: Blob -> Layer
computeLayer b = Layer with
mediaType = ""
size = computeSize b
digest = computeSHA256 b
computeLayers: [Blob] -> [Layer]
computeLayers = map computeLayer

With an explicit definition of computeLayer and its list variant as being simply map computeLayer.

Templates

I’m still slightly ‘fragile’ about when to use template versus data. Intuitively, I seem to pick the correct one but why data manifest but template image is difficult to articulate.

A fundamental differentiator is that, things that have Party properties are Templates, but (!) the following works:

data Dog = Dog
with
guardian: Party

So, back to square one.

Perhaps it’s that Templates are primarily ledger-resident entities because they can be create’d and other Verb’d?

Templates map closely (?) to O-Objects or Golang types and the verb actions mapping to O-Methods or Go’s function receivers. All good there. I struggle slightly with:

Accept: ContractId Account

Here, ContractId is the ID of the Account template but it must always be ContractIdand the syntax highlighting (both ContractId and Account in this example are colored blue) suggests these are the same type of thing. In this example, the Accept method returns the ID of an Account template. Its parameter (name) is provided using the with statement:

Accept: ContractId Account
with
name: Text

That continues to be quirky to my eyes.

There’s Pythonesque indentation requirements too that invariably cause me to shift blocks of statements in|out until the syntax checker stops complaining.

Scenarios

The DAML SDK not only provides excellent editing with Visual Studio Code but it also includes an outstanding testing framework:

The editor detects scenario do in your source and provides clickable Scenario results that takes you this view wherein you can determine the Contracts (Templates) that are created and archived using both a (more useful) transaction view and a table view.

The syntax for scenarios has changed between DAML versions and it took me a little while to get my head around the new syntax but it’s relatively straightforward. The ambition here is to emulate instantiating Contract (Templates) and applying methods to them. The tooling is able to identify errors in your code (you can’t send money to dead accounts, for example) and you can’t perform actions unless you’re a signatory.

It’s likely good practice to start a prototype by writing (or having someone write for you) the tests that you wish fulfilled and *then* writing the implementation. In this example, short of creating their own Registry, Alice must submit an AccountRequest to a Registry owner and only the Registry owner can approve the request thereby creating an Account for Alice to use.

Commonly, scenarios would include assertions that, you often can’t spend more money than you have or sell things that you don’t possess.

Conclusion

If you’re familiar with Haskell, you probably didn’t read this far as this is obvious to you.

If you’re unfamiliar with Haskell and DAML, I encourage you to explore the language using the excellent SDK if you’re interested in developing formal solutions to workflow scenarios particularly smart contracts.

For me, DAML isn’t an intuitively obvious language but, then again, I’ve not used anything else that provides the same rapid development and controls for solutions in this domain.

A possible next step for me is to rewrite this solution using a more familiar language (e.g. Golang) to see which is more productive and which is more accurate.

The DAML SDK is excellent and the documentation (including Hoogle) are comprehensive.