APC data model: Wire encoding example

By mako (@mako.dreamshrine.org)
Published:

This document presents an example of a complex but ordinary APC object and its encoding on the wire, which is also used to compute its hash address.

We describe the structure in a kind of wire assembly, which has a simple mapping to a binary representation, but we will discuss binary representatiosn in a later document. There may end up being more than one binary target, since the current IPLD format, dag-cbor, is nice to have, but hardly ideal.

The example object is a declaration/id/contract of a mutable (flippable) boolean with a description ("please leave turned off"). The boolean can be flipped by mako or imhotep, and can be observed by mako, imhotep and also steve. The boolean was initially set to false. The permissioning structure allows the writers mako or imhotep to add and remove additional writers and readers, and it allows steve to add more readers. Mako, imhotep and steve are all able to read the current state of both permissioning sets. All of this is declared immutably, though it concerns a mutable state.

First note that the above paragraph explaining the behavior of the data is almost as long as the code representation. This is a very concise representation of the data. There isn't a better way of expressing the data, so please forgive the following:

Notice that permission sets often have a cyclic structure. The writer set of the writer set is itself. The reader set of the reader set is itself. The two refer to each other. There are then, many languages in which they couldn't easily be worked, and we have to do some clever stuff to fit them into a content-addressed format, but it seems like we'll be able to keep the intricacies of that abstracted away.

wr := PermissionedSet(
  writers: wr
  readers: union(wr, rd)
  adders: wr
  Set(mako, imhotep)
)
rd := PermissionedSet(
  writers: wr
  readers: union(wr, rd)
  adders: union(wr, rd)
  Set(steve)
)
#Described(
  "please leave turned off"
  PermissionedSlot(
    writers: wr
    readers: rd
    v: false
  )
)

And the next code snippet describes the structure of the wire representation of the above structure. (I don't think we'll actually be sending s-expressions around, think of it as a kind of assembly format.)

Notice the impls of Contains. These wouldn't be here in reality because Contains would be implemented by Set and Union and so on in the standard library, so it wouldn't need to be explained to the recipient how these types provide Contains functionality, they would already know, but if it had not been so, for instance, if someone had just invented Contains and not provided impls for Sets or T or Union or Intersection, we demonstrate here that it would still be possible to send implementations of Contains over the wire in this way, even without sending any executable code (ie webassembly), simply by referring to extension tactics (ie, impls) like ContainsForSet or ContainsForUnion that the server may already have on their end.

impl components work by starting from the root type, then applying extension rules to the indicated parts of the component types until the required type (in this case, Contains<User>) is produced. If the chain holds, then the entity can be said to implement the provided type via these impl tactics.

(def std (std_glossary 0))
(import (std User String PermissionedSet Set Union Burl))
(def mako (entity
  (data User (entity (data String "mako")))))
  (impl (Contains User) ((ContainsForSelf User) 0))
(def imhotep (entity
  (data User (entity (data String "imhotep")))))
  (impl (Contains User) ((ContainsForSelf User) 0))
(def steve (entity
  (data User (entity (data String "steve")))))
  (impl (Contains User) ((ContainsForSelf User) 0))
(import (#Contains_apt Contains ContainsForSet ContainsForUnion))
(def k1 (entity (data Burl
  (entity
    (data (PermissionedSet User)
      (ref .. 0)
      (entity
        (data (Union (Contains User)) mako imhotep)
        (impl (Contains User) ((ContainsForUnion User) 0)))
      (ref .. 0)
      (entity (data Set mako imhotep)))
    (impl (Contains User) (via ((ContainsForSet User) 0))))
  (entity
    ((PermissionedSet User)
      (ref .. 0)
      (entity
        (data (Union (Contains User)) (ref .. 0) (ref .. 1))
        (impl (Contains User) ((ContainsForUnion User) 0)))
      (entity
        (data (Union (Contains User)) (ref .. 0) (ref .. 1))
        (impl (Contains User) ((ContainsForUnion User) 0)))
      (entity (data Set steve)))
    (impl (Contains User) ((ContainsForSet User) 0))))))

(entity
  (data (#Described (PermissionedSlot bool))
    (entity (data String "please leave turned off"))
    (entity (data (PermissionedSlot bool)
      (ref k1 0)
      (ref k1 1)
      (entity (data bool false))))))

definitions:

not mentioned here but will be used later: