Menu

How a payment travels

A payment in Dassie is not one transfer. It is many small packets, each passed from node to node and either paid or refused on the way. This page follows them from your node to the person you pay.

On this page
  1. Three kinds of packet
  2. One payment, many packets
  3. Hop by hop
  4. Limits along the way
  5. Settling up
  6. Watch it happen

Three kinds of packet

Dassie speaks Interledger, and every payment travels in Interledger packets. There are three kinds.

  • Prepare asks the next node to pass some money on. It carries an amount, the address it is for, a time it expires, and a lock: the SHA-256 hash of a 32-byte secret. In effect it says: "I will pay you this much if you show me the secret that opens this lock before this time."
  • Fulfill is the answer that carries the secret. Whoever holds it can prove the packet arrived.
  • Reject is the answer that says no. It carries a code and the address of the node that refused. A code starting with F means the packet will never get through as it is, T means try again later, and R means it ran short on the way, most often of time. Error codes lists the ones Dassie sends.

Only the two ends of a payment can make the secret. The nodes in between cannot make one up, so a Fulfill is proof that the packet reached the person you pay.

One payment, many packets

Your node does not send the whole amount in one packet. It uses STREAM, the Interledger protocol that splits a payment into packets, encrypts what travels in them, and has the receiver report what arrived. Each payment gets a STREAM connection of its own.

  1. You ask to pay. The other wallet hands your node what it needs to reach the receiver, usually through Open Payments: an address and a secret the two ends share.
  2. Your node quotes. It sends a few probes, packets the receiver refuses on purpose, to measure how much arrives at the other end. That shows you the rate and the fees before any money moves.
  3. Your node sends. It keeps several packets in flight at once, sends faster while they get through and slows down when they are refused. Every packet must deliver at least the rate of the quote, or it fails.
  4. The receiver reports back. Every answer from the receiver, Fulfill or Reject, tells your node how much the receiver has taken so far and how much more it will take. A refusal from a node along the way says only why it refused.
  5. The payment ends once the receiver has what it asked for, within a tiny tolerance for rounding, or once your node has sent the amount you set, or at the payment's deadline. It ends only once none of its packets is still in flight, so what it says it sent is final.

A refused packet costs nothing but time: its money goes again in a later packet, which may take another path. Small packets keep what any one node can lose small, and many of them spread a payment over many paths.

Hop by hop

Between your node and the receiver's are the peers in between, each of them someone else's node. A packet goes like this.

  1. Your node sends a Prepare to one of its peers. In its books, the amount is now pending: set aside, not yet gone.
  2. The peer checks the packet: that it has not expired, is not too large, fits what you may owe it, and still carries money after its fee. Then it books pending transfers of its own and sends a Prepare on to the next node, expiring a little earlier than the one it took, so the answer has time to come back.
  3. This repeats until the packet reaches the receiver's node, whose STREAM receiver takes it if it belongs to a payment that is still open, and answers with a Fulfill.
  4. The Fulfill travels back the way the Prepare came. As it passes, each node posts its pending transfers: now the money has moved, in that node's books.
  5. A Reject, or no answer before the packet expires, voids them instead. Nothing moved.

Each node keeps its own books and decides from them alone. It never waits for its neighbors to agree, and a Fulfill it booked stays booked, whatever happens upstream.

Why it works this way and why a Fulfill is final: own Fulfills

Which way a packet goes

A node picks each packet's next hop among the peers that lead toward its destination, drawn at random and weighted by the fees each has earned it lately, with a small share of draws spread evenly so that new peers get a chance. Nothing ties a payment to one path. A node never sends a packet back to the peer it came from.

Fees and conversion

A node charges a fee only on what passes from one peer to another. Your own node never charges you for your own payments. Fees round down, so a packet too small to carry one passes free.

Where a packet arrives in one asset and leaves in another, such as XRP in and test dollars out, the node in the middle converts it at its own rates. Your own packets never convert at your node: a payment leaves on the ledger you pay from. Exchange rates says how a node prices that.

Peers also trade with each other this way. In a swap, a node sends its peer a packet over one hub, and the peer converts it at its own rates and sends it straight back over another, so the node gets one asset for the other. A core node swaps by itself when a peer's prices bring it back toward balance and pay for the swap. A node without a hostname swaps by itself only toward the targets you set, none by default, and any node swaps when you ask it to.

Limits along the way

Each node protects itself with a few limits. When a packet hits one, it is refused, and STREAM adjusts.

Limit What it bounds When a packet hits it
The largest packet The most one packet may carry F08, with the most it takes, and the sender makes its packets smaller
Money in flight What packets in flight with one peer carry, on each hub the two share and each way: two and a half of the largest packets T05, and the sender backs off
Room What a peer may owe the node: the credit it gives that peer T04, and the sender backs off until the peers settle

The cap on money in flight is there because a node that crashes with packets in flight never learns which of them were paid. Each one can leave two peers' books apart by its amount, so the cap bounds what a crash can cost.

Why it works this way

Settling up

Packets move money in the nodes' books, not on a ledger. After a while one peer owes another. Before what it owes reaches the credit it was given, the peer it owes asks it to settle, and it pays through the settlement hub of that asset that the two share. How that works is on Settlement hubs, and how peers find each other and how much they let each other owe is on Peers and holds.

Watch it happen

The STREAM Toy runs a payment across a simulated network in your browser, packet by packet, with Dassie's own STREAM code. To send and receive STREAM payments from your own app, read STREAM on Dassie.

The connector in the spec and STREAM in the spec hold every rule

A kopje of granite blocks against the sun, in veld grass; one dassie climbs its slab, one keeps lookout on top inside the sun, and one sleeps on the next rock; on a wide screen, a pair sits on a kopje to the left