Migración desde versiones anteriores de Marlowe

Este tutorial explica en qué se diferencia la última versión de Marlowe de las versiones anteriores del lenguaje.

 

Eliminar Both

En la última versión de Marlowe no incluimos la construcción Both , lo que hace que todos los contratos sean secuenciales.

Dado que en ninguna de las versiones de Marlowe hubo comunicación entre las ramas de Both, la única funcionalidad extra que proporcionaba Both en la práctica era la posibilidad de esperar varios depósitos de dinero al mismo tiempo.

Nos encargamos de esta funcionalidad actualizando la construcción When . En lugar de tener diferentes ramas esperando por diferentes entradas, pasamos a un modelo completamente secuencial y síncrono, donde podemos esperar una de varias entradas posibles al mismo tiempo (como en select).

La razón por la que eliminamos esta construcción es que los programas secuenciales son más fáciles de analizar y de razonar, ya que no hay necesidad de sincronización y no hay oportunidad de condiciones de carrera.

 

Incluir las cuentas

En versiones anteriores de Marlowe cada compromiso tiene su propio timeout. Esto significa que el dinero depositado en un contrato no es fungible, porque se puede distinguir por su timeout. Para lograr la fungibilidad hemos eliminado los timeouts de las construcciones individuales, y tenemos un único timeout para todos los compromisos. Este tiempo de vida del contrato es fácil de inferir a partir de los timeouts del contrato.

Sin embargo, incluimos cuentas para organizar el dinero depositado en el contrato. Esto hace más transparente el flujo de dinero dentro del contrato y, en particular, identifica a quién se le devuelve el dinero cuando el contrato termina.

Cada cuenta está identificada por un participante; el participante indica quién recibirá el dinero de la cuenta por defecto cuando se llegue al Close .

La razón por la que decidimos incluir las cuentas es que, sin ellas, nos dimos cuenta de que estábamos llevando a cabo un seguimiento manual de las cuentas. Además, en cada hoja del AST, nos encontrábamos calculando cuánto debíamos devolver a cada participante, lo que abarrotaba el árbol con una repetitiva "palabrería". Por lo tanto, tener el dinero organizado en cuentas puede hacer que los contratos sean más fáciles de razonar y menos propensos a errores.

Ten en cuenta que podemos proporcionar una fungibilidad completa utilizando una sola cuenta. Sólo tenemos que escribir los comandos de Pay apropiados en las hojas del contrato. Si todo el dinero se paga a los participantes, entonces Close no tiene ningún efecto. [1]

 

Discusión: Cuentas implícitas frente a cuentas explícitas

Muchos de los casos de uso de las cuentas -y todos los que podemos identificar para los contratos ACTUS- tienen una cuenta por participante, y un participante por cuenta (el "modelo 1-1"). Esto plantea la cuestión de si debemos dar un tratamiento implícito a las cuentas, siendo cada participante propietario de una cuenta.

Por otro lado, hay una variedad de escenarios plausibles para las cuentas que no se ajustan al modelo 1-1.

Ejemplos en los que varios participantes utilizan una cuenta.

  • Alice es propietaria de una cuenta en la que compromete dinero para que Bob lo gaste (piensa que Alice es la empleadora de Bob). Bob puede gastar hasta el límite de la cuenta, pero después de que el compromiso se agote, Alice recupera todo lo que queda.
  • Alice es propietaria de una cuenta en la que compromete dinero para que Bob y Carol lo gasten (piensa que Alice es la empleadora de Bob y Carol). Pueden gastar (conjuntamente) hasta el límite de la cuenta, pero después de que el compromiso se agote, Alice recupera todo lo que queda.
  • Por otro lado, se les podría dar a cada uno una cuenta separada desde la que gastar: eso haría cumplir los límites individuales así como un límite agregado.
  • Si Bob [y Carol] quieren gastar dinero también pueden añadir dinero a la cuenta, pero deben saber que todo lo que no se utilice se devolverá a Alice.

 

Ejemplos de cuentas múltiples para una persona:

  • Los ejemplos de aseguramiento encajarían aquí. Una persona asegura el riesgo de primer nivel y el de segundo nivel utilizando cuentas diferentes. Sólo cuando se haya gastado la garantía de primer nivel de todos los participantes se producirá el gasto de segundo nivel.

 

Close reemplaza a Null / Pay

Como todos los contratos son ahora secuenciales, podemos decir fácilmente cuando un contrato llega a su fin, es decir, cuando sólo queda Null Aprovechamos esta oportunidad para cerrar el contrato y devolver el dinero que queda en las cuentas; por eso hemos cambiado el nombre de Null por el de Close (para facilitar la comprensión).

Como se ha señalado anteriormente, ya no hay ningún timeout explícito en las cuentas, ya que todos los contratos acabarán reduciéndose a Close. De hecho, podemos calcular de forma estática y eficiente un límite superior para cuando esto ocurra, haciendo que este aspecto de Marlowe sea analizable.

 

Pay

Pay es ahora inmediato, y tiene una única continuación, y menos parámetros. [2] Permite los pagos de una cuenta a un participante o a otra cuenta. Descartamos PayAll, ya que se puede emular como una serie finita de Pay. De hecho, podemos definir payAll como una función Haskell (véase el ejemplo de zeroCouponBond ).

Una consecuencia de la eliminación de la construcción Both es que ahora es inequívoco cuál es el primer Pay : todos son secuenciales, lo que facilita el análisis. Con la construcción Both , podríamos tener Pays en cualquier orden (ya que ambos lados de Both se supone que se ejecutan simultáneamente).

 

Multi-cláusula When

Hemos modificado When para incluir un conjunto de posibles acciones que se pueden introducir mientras When espera. Llamamos a este enfoque "Uno de muchos", porque acepta una acción de las potencialmente muchas permitidas. When queda así:

donde When esperará al Timeout y continuará como Contract, o continuará como se especifica en uno de los Cases, lo que ocurra primero. Case se define como:

Action como:

Una cláusula de Case se activará sólo si se produce la Action correspondiente, y continuará como Contract. En caso de coincidencia de dos Actions , se ejecutará la primera de la lista.

Se admiten tres tipos de acciones:

  • Deposit representa un depósito de dinero en una cuenta; originalmente se llamaba Commit.
  • Choice representa una elección realizada por un participante dentro de un conjunto de valores Integer (especificados por la lista de Bounds).
  • Notify esperará a que se emita una acción Notify cuando la Observation sea verdadera. Lo llamamos Notify para dejar claro que no podemos esperar simplemente a las Observations, sino que alguien debe activar el contrato en un momento en el que una Observation sea verdadera.

Hemos descartado añadir observaciones a Deposit y Choice ya que no sería obvio si la Observation sería evaluada antes o después de aplicar la acción.

Además de los casos explícitos en When, debemos recordar que la rama timeout también es un caso, y también necesita ser activada (de forma similar a Notify). [3] [4]

 

Observations y Values

Hemos descartado Observations y Values que pueden ser expresados combinando otros: como el general AvailableMoney (para todo el contrato), o como DepositedMoneyBy, que recuerda la cantidad de dinero depositada por un participante, ya que el contrato puede ser reestructurado para observar eso, y apoyarlo requeriría información adicional en el estado (simplicidad).

Hemos mantenido la observación ChoseSomething a pesar de que, en la semántica propuesta, cada ocurrencia de ChoseSomething puede ser evaluada estática y eficientemente examinando su contexto.

Por ejemplo, en el siguiente contrato podemos ver que la primera ocurrencia de ChoseSomething se evaluará como True, y la segunda como False:

Sin embargo, hemos optado por mantener la construcción por dos razones:

  • Permite la reutilización del código (comodidad). Por ejemplo, en el contrato anterior, podríamos definir chosen1:

Pero esto no sería posible si no tuviéramos la construcción ChoseSomething, ya que el valor al que se reduce depende del contexto.

  • Puede que ya no sea posible evaluar estáticamente las ocurrencias de la construcción si ampliamos la construcción When para que admita entradas "muchas de muchas".

 

Inclusión de SlotIntervals

La especificación EUTxO proporciona scripts de validación con intervalos de slots en lugar de con números de slots. Esto es para promover el determinismo en los scripts de validación. Sin embargo, hemos mantenido el timeout de When (el único timeout) como un número de slot. La forma en que tratamos los intervalos de slot es requiriendo que el intervalo de una transacción no incluya ningún timeout sobre el que la semántica tenga que hacer una elección. Por ejemplo: si el timeout es 10, una transacción con el intervalo 5-15 fallará con AmbiguousSlotInterval. Los participantes tendrían que emitir una transacción con el intervalo 5-9 o 10-15 (o ambos).

Sin embargo, para los Values, proporcionamos las dos construcciones SlotIntervalStart y SlotIntervalEnd. Una alternativa a considerar sería modificar la semántica para que los Valores sean no deterministas, de esta manera podríamos incluir una construcción CurrentSlot y sólo invalidar las transacciones que sean ambiguas, pero esto complicaría la semántica y la haría menos predecible.

[1]

Potencialmente podemos proporcionar una forma de analizar estáticamente el contrato para comprobar si es posible que quede dinero en alguna cuenta cuando se alcance el Close .

[2]

Esto significa que los pagos ahora obedecen a un modelo "push" en lugar de un modelo "pull".

[3]

No obstante, la activación del contrato para el tratamiento de los timeouts no es urgente como en el caso de Notify, ya que mientras que lasObservations pueden alternar entre True y False, los timeouts sólo pueden ocurrir una vez e, independientemente de que hayan sido observados por el contrato o no, no pueden ser revertidos.

[4]

De hecho, ya no se puede emitir un Case explícito después del timeout, incluso si el timeout no ha sido observado por el contrato, ya que el timeout se comprueba antes que los Inputs. Sin embargo, un participante puede querer desencadenar un timeout en casos en los que no se necesitan otros Inputs , para desencadenar uno o más pagos, por ejemplo. En la implementación actual de la semántica eso se haría emitiendo una transacción con una lista vacía de Inputs.

© Copyright 2020, IOHK Revision 74cb849b.

 

Encuentra una copia oficial de este documento aquí:

https://alpha.marlowe.iohkdev.io/doc/marlowe/tutorials/migrating.html

https://docs.cardano.org/projects/plutus/en/latest/marlowe/tutorials/migrating.html

 

Más traducciones de Cardano en: Cardano For The World