Los tipos de datos Marlowe
Este tutorial introduce formalmente a Marlowe como un tipo de datos de Haskell, además de presentar los diferentes tipos utilizados por el modelo, y discutir una serie de supuestos sobre la infraestructura en la que se ejecutarán los contratos. El código que describimos aquí proviene de los módulos Haskell Semantics.hs y Util.hs.
Marlowe
El lenguaje específico de dominio (DSL) de Marlowe se modela como una colección de tipos algebraicos en Haskell, con contratos dados por el tipo Contract
:
En el tutorial anterior vimos lo que hacen estos contratos. En el resto de este tutorial profundizaremos un poco más en los tipos Haskell que se utilizan para representar los distintos componentes de los contratos, incluyendo cuentas, valores, observaciones y acciones. También veremos los tipos que se relacionan con la ejecución de los contratos, incluyendo las entradas, los estados, el entorno.
Componentes básicos
Para modelar las partes básicas de Marlowe utilizamos una combinación de Haskell data
types, que definen nuevos types, y type
sinónimos que dan un nuevo nombre a un existente type. 1
Una Cuenta Marlowe contiene importes de múltiples monedas y/o tokens fungibles y no fungibles. Una cantidad concreta está indexada por un Token
, que es un par de CurrencySymbol
y TokenName
. Puedes considerar un Account como un Map Token Integer
, donde
El token Ada de Cardano es Token adaSymbol adaToken
. Pero puedes crear tus propias monedas y tokens.
Los tokens de una moneda pueden representar roles en un contrato, por ejemplo, “comprador” y “vendedor”. Piensa en un contrato legal en el sentido de “en lo sucesivo, el ejecutante/vendedor/artista/consultor”. De este modo, podemos desvincular la noción de propiedad de un rol contractual y hacer que sea negociable. Así, puedes vender tu préstamo o comprar una parte de un rol en algún contrato.
Aquí account
tiene un buyer
token de moneda “TradeRoles”, y 1000 lovelace.
Un Party
se representa como un hash de clave pública o un nombre de rol.
Para hacer progresar un contrato Marlowe, una parte debe aportar una evidencia. Para parte PK
esto sería una firma válida de una transacción firmada por una clave privada de una clave pública que tiene el hash del PubKeyHash
de la parte, similar al mecanismo Pay to Public Key Hash
de Bitcoin. Para una parte Role
la evidencia es gastar un role token
dentro de la misma transacción, normalmente al mismo propietario.
Así que, las partes Role
se verán como (Role "alice")
, (Role "bob")
y así sucesivamente. Sin embargo, Haskell nos permite presentar y leer estos valores de forma más concisa (declarando una instancia personalizada de Show
y utilizando overloaded strings ) para que estos puedan ser introducidos y leídos como "alice"
, "bob"
etc.
Los números de slot y las cantidades de dinero se tratan de forma similar; con el mismo esquema de show/overload aparecerán en los contratos como números:
Nota que "alice"
es la propietaria en el sentido de que se le devolverá el dinero que haya en la cuenta cuando el contrato finalice.
Podemos utilizar overloaded strings para permitirnos abreviar esta cuenta por el nombre de su propietario: en este caso "alice"
.
Un pago puede hacerse a una de las partes del contrato, o a una de las cuentas del contrato, y esto se refleja en la definición
Las opciones -de números enteros- se identifican con ChoiceId
que combina un nombre para la elección con el Party
que ha hecho la elección:
Los valores, definidos mediante Let
are also identified by integers. 2
Values, observations and actions
Partiendo de los tipos básicos, podemos describir tres componentes de nivel superior de los contratos: un tipo de values, encima un tipo de observations, y también un tipo de actions, que desencadenan casos particulares. En primer lugar, observando a Value
tenemos
Los diferentes tipos de values – que todos ellos son Integer
– se explican por sí mismos, pero con el fin de estar completos, tenemos
- Consulta del valor en una cuenta
AvailableMoney
, hecha en una elecciónChoiceValue
y en un identificador ya definidoUseValue
. - Constantes y operadores aritméticos.
-
Scale
multiplica unValue
por una constante racional, por ejemplo, 2/3, y redondea el resultado utilizando el redondeo " a medias " o " bancario ". Así, 14/10 se redondea a 1, tanto 15/10 como 25/10 se redondean a 2. - El inicio y el final del intervalo del slot actual; véase más abajo para más información sobre esto.
-
Cond
representa las expresiones if, es decir, el primer argumento deCond
es una condición (Observation
) para chequear, el segundo es unValue
para tomar cuando la condición es satisfecha y el último es unValue
para la condición insatisfecha; por ejemplo:(Cond FalseObs (Constant 1) (Constant 2))
es equivalente a(Constant 2)
A continuación tenemos observations
Son realmente autoexplicativos: podemos comparar valores para la (in)igualdad y la ordenación, y combinar observations utilizando las conectivas booleanas. La única otra construcción ChoseSomething
indica si se ha hecho alguna elección para un determinado ChoiceId
.
Los casos y las acciones vienen dados por estos tipos:
Tres tipos de actions son posibles:
-
Un
Deposit n p t v
hace un depósito de valuev
de tokent
de partyp
dentro de accountn
. -
Se hace una elección para un id particular con una lista de límites en los valores que son aceptables. Por ejemplo,
[Bound 0 0, Bound 3 5]
ofrece la posibilidad de elegir una de las siguientes opciones0
,3
,4
y5
. -
El contrato es notificado para que se realice una determinada observación. Normalmente, esto lo haría una de las partes, o uno de sus wallets actuando automáticamente.
Esto completa nuestro análisis de los tipos que componen los contratos de Marlowe.
Transactions
Como hemos señalado anteriormente, la semántica de Marlowe consiste en la construcción de transacciones, así:
Una transacción se construye a partir de una serie de pasos, algunos de los cuales consumen un valor de entrada, y otros producen efectos, o pagos. Al describir esto explicamos que una transacción modificaba un contrato (a su continuación) y el estado, pero más precisamente tenemos una función
donde los tipos se definen así:
La notación utilizada aquí añade los nombres de los campos a los argumentos de los constructores, proporcionando selectores para los datos, así como haciendo más claro el propósito de cada campo.
El tipo TransactionInput
tiene dos componentes: el SlotInterval
en el que puede añadirse válidamente a la blockchain, y una secuencia ordenada de valores de Input
que se procesarán en esa transacción.
Un value TransactionOutput
tiene cuatro componentes: los dos últimos son el State
y el Contract
actualizados, mientras que el segundo da una secuencia ordenada de Payments
producidos por la transacción. El primer componente contiene una lista de las advertencias producidas por el procesamiento de la transacción.
Series de slots
Esto forma parte de la arquitectura de Cardano/Plutus, que reconoce que no es posible predecir con precisión en qué slot se procesará una transacción concreta. Por lo tanto, a las transacciones se les da un intervalo de slots en el que se espera que se procesen, y esto se traslada a Marlowe: cada paso de un contrato de Marlowe se procesa en el contexto de una serie de slots.
¿Cómo afecta esto al procesamiento de un contrato Marlowe? Cada paso se procesa en relación con un intervalo de slots, y el valor del slot actual tiene que estar dentro de ese intervalo.
Los puntos finales del intervalo son accesibles como los valores SlotIntervalStart
y SlotIntervalEnd
, y estos pueden ser utilizados en las observaciones. Los timeouts deben procesarse de forma inequívoca , de modo que todos los valores del intervalo de slots tienen que haber superado el timeout para que surta efecto, o caer antes del timeout, para que la ejecución normal surta efecto. En otras palabras, el valor del timeout debe ser menor o igual que SlotIntervalStart
(para que el timeout tenga efecto) o ser estrictamente mayor que SlotIntervalEnd
(para que la ejecución normal tenga lugar).
Notas
El modelo hace una serie de suposiciones sobre la infraestructura de blockchain en la que se ejecuta.
- Se supone que las funciones y operaciones criptográficas son proporcionadas por una capa externa a Marlowe, por lo que no es necesario modelarlas explícitamente.
- Suponemos que el tiempo es de “grano grueso” y se mide por número de bloque o slot, de modo que, en particular, los timeouts se delimitan utilizando números de bloque/slot.
- La realización de un depósito no es algo que un contrato pueda llevar a cabo; más bien, puede solicitar que se realice un depósito, pero eso entonces tiene que establecerse externamente: de ahí la entrada de (una colección de) depósitos para cada transacción.
- El modelo administra la devolución de fondos al propietario de una cuenta particular cuando un contrato alcanza el punto de
Close
.
De hecho, utilizamos declaraciones newtype en vez de data
types porque se implementan de manera más eficiente.
Esto puede ser modificado en el futuro para permitir que los valores sean nombrados por strings.
© Copyright 2020, IOHK Revision 34aa9c32.
Encuentra una copia oficial de este documento aquí:
https://alpha.marlowe.iohkdev.io/doc/marlowe/tutorials/marlowe-data.html
https://docs.cardano.org/projects/plutus/en/latest/marlowe/tutorials/marlowe-data.html
Más traducciones de Cardano en: Cardano For The World