Skip to Content

User requests

A user request explicitly signals the user’s intention to alter the L2 ledger state. Gummiworm recognizes two request types:

  1. Deposit request – the L2 state updates only if and when Gummiworm decides to accept the user’s deposit on L1.
  2. Transaction request — the L2 state changes occur immediately and unconditionally.
type UserRequest = | { "DepositRequest": DepositRequest } | { "TransactionRequest": TransactionRequest }
Note

Many expect to see withdrawals in this list. However, withdrawals are simply an effect of a transaction request which remits a payout on the L1.

Both request types share a common header. The header consists of:

  • Head ID — the unique identifier of the Gummiworm head to which the request is addressed.
  • Validity interval — a start time and an end time that limit Gummiworm’s timeline to soft-confirm the request’s validity. They are both optional for transaction requests, but the validity end time must be specified for a deposit request.
  • Body hash — a Blake2b-256 hash of the request body.
type UserRequestHeader = { headId: HeadId, validityStart: number, // POSIX time, seconds validityEnd: number, // POSIX time, seconds bodyHash: Hash32 // Hash of UserRequestBody } // Hex-encoded type ByteString = string type HeadId = ByteString // 32 bytes type Hash32 = ByteString

A deposit request’s body has two parts:

  • An L1 payload characterizing the user’s L1 deposit. It is transparent to both Gummiworm and the L2 ledger.
  • An L2 payload characterizing the intended L2 state changes if the deposit is absorbed. It is opaque to Gummiworm but transparent to the L2 ledger.
type DepositRequest = { header: UserRequestHeader, body: DepositRequestBody, userVk: ByteString, signature: ByteString, // Signature of header, verifiable by userVk. } type DepositRequestBody = { l1Payload: ByteString, l2Payload: ByteString, userVk: ByteString, signature: ByteString, // Signature of header, verifiable by userVk. }

A transaction request’s body carries only the L2 payload. Transactions affect L2 state immediately, with no L1 deposit step.

type TransactionRequest = { header: UserRequestHeader, body: TransactionRequestBody, userVk: ByteString, signature: ByteString, // Signature of header, verifiable by userVk. } type TransactionRequestBody = { l2Payload: ByteString }

When a user submits a request to a head peer, the receiving node checks the request’s signature. If the signature is valid, the node assigns a unique ID to the request and broadcasts the request (with this ID) to the other head and coil peers.

Commands

Each deposit request’s outcome is determined in two stages, while each transaction request’s outcome is determined in a single stage. Accordingly, at each stage, Gummiworm issues one of three commands to the black-box L2 ledger.

RegisterDeposit is issued upon receiving a deposit request. The command omits the request’s L1 payload, replacing it with the L1 payload’s hash and information that Gummiworm parsed from the L1 payload: the deposit ID, fee, L2 value, and refund destination.

type RegisterDeposit = { requestId: RequestId, userVk: ByteString, blockNumber: BlockNumber, blockCreationStartTime: PosixTime, depositId: DepositId, // L1-specific depositFee: number, depositL2Value: Value, // L1-specific refundDestination: Destination, // L1-specific l2Payload: ByteString, } // Opaque request id - both peer/request number encoded in one number type RequestId = number type BlockNumber = number // in seconds type PosixTime = number

DepositId, Value, and Destination are L1-specific. For their Cardano definitions, see cardano-as-l1.

ApplyDepositDecisions is issued in bulk for multiple deposit requests at a time. Each invocation lists the deposits absorbed and rejected in a single block.

type ApplyDepositDecisions = { blockNumber: BlockNumber, blockCreationEndTime: PosixTime, absorbedDeposits: RequestId[], rejectedDeposits: RequestId[], }

ApplyTransaction passes on a transaction request to the L2 ledger with some additional block context.

type ApplyTransaction = { requestId: RequestId, userVk: ByteString, blockNumber: BlockNumber, blockCreationStartTime: PosixTime, l2Payload: ByteString, }

To understand the block-related fields in the above commands, see: blocks.

The rest of this page describes how Gummiworm issues these commands and how the black-box L2 ledger responds to them.

Deposit requests

When a user submits a deposit request, she expresses intent to deposit funds on L1 under Gummiworm’s custody, specifying the state that Gummiworm must introduce to the L2 ledger’s main compartment if the deposit is absorbed.

Before proceeding with that intent, the user must be assured that she can recover her funds on L1 if Gummiworm fails to absorb her deposit. Thus, the L1 payload in her request includes instructions for a deferred refund, which she can use to recover the funds if Gummiworm fails to absorb the deposit by a deadline. She waits for Gummiworm to hard-confirm the refund effect before she deposits her funds.

Similarly, before Gummiworm attempts to absorb the L1 deposit, it must be sufficiently certain that the deposit exists on L1. In particular, since the L1 blockchain has probabilistic finality, Gummiworm must wait a while (controlled by the maturity duration parameter) before checking whether the deposit exists on L1. Thus, Gummiworm determines the deposit request’s outcome in two stages:

  1. Registration. Upon receiving the deposit request from the user, if the request timing rules are satisfied, Gummiworm issues a RegisterDeposit command to the black-box L2 ledger:

    • If the command is valid, the L2 ledger stores the request’s L2 state in a new deposit compartment and reports successful registration to Gummiworm, meaning that the next stage will determine the request’s outcome.

    • If the command is invalid, the L2 ledger reports the deposit’s request’s outcome to Gummiworm — invalid with error code, so no changes to the evacuation map.

  2. Decision. Upon maturity of the deposit and while it is non-expired, Gummiworm periodically checks whether the deposit exists on L1:

    • If the deposit does not exist or has expired, then Gummiworm rejects it. This means that Gummiworm will never attempt to absorb it. Gummiworm informs the L2 ledger about this rejection via an ApplyDepositDecisions command:

      • The L2 ledger removes the request’s deposit compartment and reports success to Gummiworm.
      • The L2 ledger reports the deposit request’s outcome to Gummiworm — rejected with error code, so no resulting changes to the evacuation map.
    • If the deposit exists and absorbing it now would not exceed Gummiworm’s max-deposits-absorbed-per-block parameter, then Gummiworm decides to absorb it. Gummiworm informs the ledger via an ApplyDepositDecisions command:

      • The L2 ledger transfers the L2 state from the request’s deposit compartment to the main compartment.
      • The L2 ledger reports the deposit request’s outcome to Gummiworm — absorbed, with corresponding changes to the evacuation map.
    • Otherwise, Gummiworm checks on the deposit later.

Deposit requests are immediately invalid if the request timing rules are not satisfied.

If Cardano EUTXO is the L2 ledger, see: Deposit request (EUTXO) (with diagram).

Transaction requests

When a user submits a transaction request, she intends immediate changes to the L2 state.

Accordingly, Gummiworm determines the outcome of the transaction request in a single stage. Upon receiving the request from the user, if the request timing rules are satisfied, Gummiworm passes it to the black-box L2 ledger:

  • If the request is valid, then the L2 ledger applies its changes to the L2 state. The L2 ledger reports the request’s outcome to Gummiworm — valid, possibly with changes to the evacuation map and immediate L1 payouts required.

  • If the request is invalid, then the L2 ledger makes no changes to the L2 state. The L2 ledger reports the request’s outcome to Gummiworm — invalid with error code, so no changes to the evacuation map and no immediate L1 payouts are required.

Transaction requests are invalid if the request timing rules are not satisfied.

If Cardano EUTXO is the L2 ledger, see: Transaction request (EUTXO) (with diagram).

Last updated on