Emergency Withdrawal (guest requirements)
Emergency withdrawal lets users recover their in-app balances directly from the base layer after an application is foreclosed. For that to work, the on-chain contracts need a way to read each account's balance from the settled machine state. This page describes what the guest application (the code running inside the Cartesi Machine) must do to support it.
The accounts drive
The application keeps a dedicated region of machine memory called the accounts drive. It is the withdrawable-balance ledger: a list of account records, where each record holds an owner and that owner's balance. After foreclosure, the contracts prove this drive against the settled machine state and pay each account out from it.
An application supports emergency withdrawal only if:
- It maintains an accounts drive, and
- The drive's layout matches the
WithdrawalConfigthe application was deployed with. - The WithdrawalOutputBuilder contract configured in the application can decode the account and build a valid output to withdraw the assets
If the layout the guest writes and the config the contract was given disagree, proofs will not validate and funds cannot be withdrawn.
Matching the layout
The WithdrawalConfig describes the drive with three values, and the guest must write records that match them:
accountsDriveStartIndexpositions the drive in machine memory;log2MaxNumOfAccountssets how many accounts fit (the tree depth);log2LeavesPerAccountsets each record's size, which is2^(5 + log2LeavesPerAccount)bytes.
For the single-token case (see UsdWithdrawalOutputBuilder), each record is 32 bytes: an 8-byte little-endian balance, followed by the 20-byte owner address, followed by padding.
Creating the accounts drive
The accounts drive is a standard Cartesi Machine drive, declared in your project's cartesi.toml alongside every other drive. The Advanced configuration guide covers how drives are defined and built in general; the accounts drive is distinctive only in that it is left raw, so the guest can write balance records into it directly.
Declare it next to the root drive as an empty, raw, unmounted flash drive, and set final_hash = true so the build produces the machine hash that on-chain deployment requires:
[machine]
# ...your existing machine settings...
final_hash = true
# The application and OS, built from your Dockerfile.
[drives.root]
builder = "docker"
dockerfile = "Dockerfile"
format = "ext2"
# The accounts drive: a raw, unformatted flash drive for the balance ledger.
[drives.accounts]
builder = "empty"
format = "raw"
size = 4194304 # size in bytes
mount = false
user = "dapp"
Leaving the drive raw and unmounted is deliberate. Rather than layering a filesystem on top, the guest opens the block device directly (for example /dev/pmem1) and writes fixed-size records at deterministic offsets. That predictable layout is precisely what allows the drive to be Merkle-proven against the machine state after foreclosure. The Common drive options reference explains each field used above.
Two properties of the drive must agree with the WithdrawalConfig:
- Size. The drive must be large enough to hold the entire account tree, which spans
2^(5 + log2MaxNumOfAccounts + log2LeavesPerAccount)bytes. A single-token ledger withlog2LeavesPerAccount = 0andlog2MaxNumOfAccounts = 12, for example, occupies2^17bytes (128 KiB), well within the drive declared above. - Position.
accountsDriveStartIndexrecords where the drive begins in machine memory, expressed as its start address divided by that account-tree size. You do not compute it by hand:cartesi buildplaces the drive, and you read the assigned position from.cartesi/image/config.json. That value is theaccountsDriveStartIndexyou supply in theWithdrawalConfigat deploy time.
With the drive declared and sized, the guest fills it with balance records, as described next.
Keeping the balances
You rarely need to write the drive by hand. A ledger library maintains the accounts drive for you: it credits deposits, debits withdrawals and transfers, and stores every balance in the drive so it stays provable from the machine state. See the Asset Management Library for how to store and manage balances this way.
The account encoding must round-trip
The bytes the guest writes for an account must be the same bytes the on-chain withdrawal output builder decodes at withdrawal time. For the USD builder, that means the (owner, balance) encoding the guest produces must match what the builder reads back to build the transfer.
Emergency withdrawal relies on four descriptions of the accounts drive agreeing: the layout the guest writes, the WithdrawalConfig on-chain, the parameters used to generate proofs off-chain, and the account encoding the output builder decodes. Choose these together at deploy time. See Withdrawal Contracts Overview.