Skip to content

Lease Lifecycle

A compute lease passes through three phases: creation, acceptance, and settlement. Each phase produces an on-chain block that the ledger validates.

Phase 1: Lease creation (consumer)

The consumer creates a lease block on their account chain. This debits XUSD from their balance to pay for the requested resources.

{
  "type": "lease",
  "account": "<consumer pubkey>",
  "previous": "<frontier hash>",
  "balance": "<previous XUSD balance - cost>",
  "asset": "XUSD",
  "destination": "<provider pubkey>",
  "amount": "<cost>",
  "vcpus": 2,
  "memory_mb": 4096,
  "disk_gb": 50,
  "duration": 3600,
  "access_pub_key": "<ed25519 pubkey hex, 64 chars>"
}

The block is signed, PoW-solved, and broadcast to the network via gossip.

Cost must match the formula

The ledger validates that amount exactly equals the deterministic cost computed from the resource dimensions and duration. See Cost Model.

What happens on broadcast

The lease block creates a pending send to the provider. The provider's node sees this pending send and -- if configured with -provide -- automatically begins the acceptance flow.

Phase 2: Lease acceptance (provider)

The provider creates a lease_accept block on their account chain. This stakes XUSD collateral and records timekeeper-attested start time.

{
  "type": "lease_accept",
  "account": "<provider pubkey>",
  "previous": "<frontier hash>",
  "balance": "<previous XUSD balance - stake>",
  "asset": "XUSD",
  "source": "<lease block hash>",
  "amount": "<stake>",
  "certificate_hash": "<performance certificate hash>",
  "attestations": [...]
}

Stake calculation

Stake = cost / 5, with a minimum of 1 XUSD. The provider must have sufficient XUSD balance to cover the stake.

Acceptance steps

  1. Balance check — verify sufficient XUSD for the stake.
  2. Resource check — verify available vCPUs, memory, and disk (including resources reserved by in-flight provisions).
  3. Gather attestations — request signed timestamps from trusted timekeepers (see Attestations). Attestations are mandatory.
  4. Provision VM — start the virtual machine with the requested resources. This happens before the accept block is committed — if provisioning fails, the lease is not accepted.
  5. Create block — build the lease_accept block with certificate_hash referencing the provider's performance certificate.
  6. Validate certificate — the ledger verifies the certificate exists in the gossip cache, belongs to this provider, and is not expired.
  7. Broadcast — publish to the network via gossip.
  8. Send credentials — deliver VM access info to the consumer via direct messaging.

Lease record

When the ledger processes a valid lease_accept, it creates a Lease record:

Field Source
LeaseHash Hash of the original lease block
Consumer Lease block's account (creator)
Provider Lease block's destination
VCPUs From the lease block
MemoryMB From the lease block
DiskGB From the lease block
Duration From the lease block (seconds)
Cost Lease block's amount (XUSD)
Stake lease_accept block's amount (XUSD)
StartTime Median attested timestamp (unix nanos)
AccessPubKey From the lease block (ed25519 hex, for SSH access)
CertificateHash Provider's performance certificate hash
Settled false

Phase 3: Settlement (provider)

After the lease duration expires, the provider creates a lease_settle block. This earns XE emission and returns the XUSD stake.

{
  "type": "lease_settle",
  "account": "<provider pubkey>",
  "previous": "<frontier hash>",
  "balance": "<previous XE balance + emission>",
  "asset": "XE",
  "source": "<lease block hash>",
  "amount": "<XE emission>",
  "attestations": [
    {
      "public_key": "<timekeeper pubkey hex>",
      "timestamp": 1709658000000000000,
      "signature": "<attestation signature hex>"
    }
  ]
}

Settlement steps

  1. Check expiry — the settleLoop() goroutine checks every 10 seconds whether now >= startTime + duration.
  2. Gather attestations — request signed timestamps for the settle time. Attestations are mandatory.
  3. Validate duration — the ledger verifies that attested_settleTime - startTime >= duration (in nanoseconds). Self-reported timestamps are not accepted.
  4. Create block — build the lease_settle block with XE emission.
  5. Broadcast — publish to the network.
  6. Teardown VM — synchronously stop and clean up the virtual machine (not fire-and-forget).
  7. Return stake — the XUSD stake is returned to the provider's balance.
  8. Orphan cleanup — the settle loop also cleans up any VMs whose leases are settled but teardown failed.

XE emission

The XE reward uses the same formula as the XUSD cost: LeaseCost(vcpus, memoryMB, diskGB, duration). This means the provider earns an amount of XE numerically equal to the XUSD the consumer paid.

Duration limits

Limit Value Human
Minimum 60 seconds 1 minute
Maximum 31,536,000 seconds 365 days

The ledger rejects lease blocks with durations outside this range.

Automatic settlement

The provider node runs a background settleLoop() goroutine that:

  1. Ticks every 10 seconds.
  2. Queries all leases where this node is the provider.
  3. Skips leases already settled.
  4. For each expired lease (now >= startTime + duration), calls settleLease().
  5. settleLease() gathers attestations, creates the lease_settle block, and tears down the VM.

No manual intervention needed

Providers do not need to manually settle leases. The settleLoop() handles it automatically as long as the node is running.

Lease struct

The Lease struct tracks the full state of an active or settled lease:

type Lease struct {
    LeaseHash    string // hash of the lease block
    Consumer     string // consumer account (lease block creator)
    Provider     string // provider account (lease block destination)
    VCPUs        uint64
    MemoryMB     uint64
    DiskGB       uint64
    Duration     uint64 // seconds
    AccessPubKey string // ed25519 pubkey hex for SSH access
    Cost         uint64 // XUSD paid by consumer
    Stake        uint64 // XUSD staked by provider
    StartTime       int64  // unix nanos (median attested timestamp)
    CertificateHash string // provider's performance certificate
    Settled         bool
}

Sequence diagram

Consumer Node                  Network                  Provider Node
     │                           │                           │
     │  create lease block       │                           │
     │  (debit XUSD)             │                           │
     │ ─────────────────────────►│                           │
     │                           │  gossip lease block       │
     │                           │──────────────────────────►│
     │                           │                           │  detect pending send
     │                           │                           │  check resources available
     │                           │                           │  gather start attestations
     │                           │                           │  provision VM (before accept!)
     │                           │                           │  create lease_accept
     │                           │  gossip lease_accept      │  (stake XUSD + cert hash)
     │                           │◄──────────────────────────│
     │  receive VM credentials   │                           │  send credentials
     │◄──────────────────────────│───────────────────────────│
     │                           │                           │
     │       ... lease duration elapses ...                  │
     │                           │                           │
     │                           │                           │  settleLoop detects expiry
     │                           │                           │  gather settle attestations
     │                           │                           │  create lease_settle
     │                           │  gossip lease_settle      │  (earn XE, recover stake)
     │                           │◄──────────────────────────│
     │                           │                           │  teardown VM (synchronous)