/api/transactions/locker/download
GETDownload CloudCoins from a RAIDA locker using a 32-character hexadecimal locker key. Executes two-phase protocol: Peek to view coins, then Remove to download with new ANs.
Description
The /api/transactions/locker/download endpoint downloads CloudCoins from a RAIDA locker and automatically grades them into the appropriate folder (Bank, Fracked, or Counterfeit). This endpoint implements a secure two-phase protocol:
- Peek Phase (0x0853): Queries all 25 RAIDA servers to retrieve the list of coins stored in the locker (denomination + serial number pairs). Requires 13+ successful responses for cloud consensus.
- Remove Phase (0x0854): Downloads the coins from the locker with newly generated random Authenticity Numbers (ANs). The old locker ANs are discarded, transferring ownership to the downloader.
Downloaded coins are automatically graded and moved to the appropriate folder (Bank, Fracked, or Counterfeit) based on POWN results from the Remove operation.
Important: Downloading coins from a locker is a destructive operation. Once downloaded, the coins are removed from the locker and transferred with new ANs. The sender cannot recover the coins after download.
This endpoint is essential for:
- Receiving CloudCoins sent via locker by another user
- Transferring coins between your own wallets
- Collecting coins from a shared locker after out-of-band key exchange
- Automated locker monitoring and coin retrieval
The locker key is NOT the same as coin ANs. It's a 16-byte password/secret shared out-of-band between sender and receiver. Anyone with the locker key can download the coins, so keep it secret and share only via secure channels.
Parameters
This endpoint requires one query parameter:
| Parameter | Type | Required | Description |
|---|---|---|---|
locker_key |
string | Yes | 32 hexadecimal characters (16 bytes) representing the locker password. Must match the key used when uploading coins to the locker. |
Parameter Validation
- Must be exactly 32 characters long
- Must contain only hexadecimal characters (0-9, a-f, A-F)
- Case-insensitive (0A1B2C3D = 0a1b2c3d)
Two-Phase Protocol
Phase 1: Locker Peek (0x0853)
The Peek phase queries all 25 RAIDA servers to retrieve the list of coins in the locker without downloading them.
Request Structure:
- Challenge: 16 bytes (random + CRC32)
- Locker Key: 16 bytes
- Terminator: 0x3E3E (2 bytes)
Response Structure:
- ALL_PASS (0xF1): Returns list of DN+SN pairs for all coins
- ALL_FAIL (0xF2): Wrong locker key or locker doesn't exist
- Error codes: RAIDA server errors
Consensus Requirements:
- Minimum 13 successful Peek responses required (out of 25 RAIDAs)
- If <13 RAIDAs respond: Network issues (503 error)
- If <13 successful peeks: Wrong key or locker doesn't exist (404 error)
Phase 2: Locker Remove (0x0854)
The Remove phase downloads the coins from the locker with newly generated random ANs, transferring ownership.
Request Structure:
- Challenge: 16 bytes (random + CRC32)
- Locker Key: 16 bytes
- For each coin:
- Denomination: 1 byte
- Serial Number: 4 bytes
- New AN: 16 bytes (randomly generated)
- Terminator: 0x3E3E (2 bytes)
Response Structure:
- ALL_PASS (0xF1): All coins successfully removed and updated
- ALL_FAIL (0xF2): All coins failed (wrong key or expired)
- MIXED (0xF3): Some coins succeeded, some failed (bitfield response)
- Error codes: RAIDA server errors
POWN String Update:
Based on each RAIDA's response, the coin's POWN string is updated:
- 'p' (0x0A): Pass - coin successfully downloaded from this RAIDA
- 'f' (0x0F): Fail - authentication failed
- 'e' (0x0E): Error - RAIDA error occurred
- 'n' (0x0C): No reply - timeout
Response
Returns a JSON object with download results and coin details.
Success Response Properties
Success Response Example
{
"status": "success",
"operation": "locker_download",
"coins_found": 5,
"coins_saved": 5,
"graded_to_bank": 4,
"graded_to_fracked": 1,
"graded_to_counterfeit": 0,
"locker_key": "0123456789abcdef0123456789abcdef"
}
Error Responses
400 Bad Request - Invalid locker_key
{
"status": "error",
"error": "Invalid locker_key (must be 32 hex characters)",
"http_code": 400
}
404 Not Found - Locker not found or wrong key
{
"status": "error",
"error": "Locker not found",
"http_code": 404
}
This error occurs when fewer than 13 RAIDAs successfully peek the locker, indicating either a wrong locker key or the locker doesn't exist.
404 Not Found - Locker is empty
{
"status": "error",
"error": "Locker is empty",
"http_code": 404
}
The locker was found and peeked successfully, but contains no coins.
500 Internal Server Error - Request generation failed
{
"status": "error",
"error": "Failed to generate RAIDA requests",
"http_code": 500
}
500 Internal Server Error - Memory allocation failed
{
"status": "error",
"error": "Memory allocation failed",
"http_code": 500
}
503 Service Unavailable - Insufficient RAIDA responses
{
"status": "error",
"error": "Insufficient RAIDA responses",
"http_code": 503
}
Fewer than 13 RAIDAs responded at all (network connectivity issues). Try again later.
Downloaded Coin Files
Downloaded coins are automatically graded and saved to the appropriate folder (Bank, Fracked, or Counterfeit) based on POWN results. Files use the following filename format:
{value} CloudCoin #{serial} '{pown_string}'.bin
Filename Components:
- {value}: Coin denomination value (e.g., 1, 5, 25, 100, 250)
- {serial}: Coin serial number (0-16777215)
- {pown_string}: 25-character POWN string showing download status per RAIDA
Example Filenames:
250 CloudCoin #1234567 'ppppppppppppppppppppppppp'.bin
100 CloudCoin #8901234 'pppppppppppppnfpppppppppp'.bin
1 CloudCoin #5678901 'pppppppppppppeepppppppnpp'.bin
- 25 passes (all 'p'): Fully authenticated coin - move to Bank
- 13-24 passes: Authentic but fracked - move to Fracked folder, run Fix command
- <13 passes: Counterfeit or failed - move to Counterfeit folder
Post-Download Workflow
The locker download endpoint now handles grading automatically. After downloading:
Download Coins (Automatic)
Call /api/transactions/locker/download with your locker key. The endpoint automatically:
- Peeks at locker contents
- Downloads coins with new ANs
- Grades coins based on POWN results
- Moves coins to Bank, Fracked, or Counterfeit folders
Fix Fracked Coins (optional)
If any coins ended up in the Fracked folder, run /api/coins/fix to heal them and move to Bank. The auto-healer will also attempt to fix fracked coins periodically.
Unlike the previous version which required manual authentication and grading steps, the updated locker download automatically grades coins based on the Remove operation's POWN results. This reduces the workflow from 5 steps to just 1-2 steps.
Examples
JavaScript (fetch)
const API_HOST = 'http://localhost:8080';
async function downloadFromLocker(lockerKey) {
try {
const response = await fetch(
`${API_HOST}/api/transactions/locker/download?locker_key=${lockerKey}`
);
const result = await response.json();
if (result.status === 'success') {
console.log(`Downloaded and graded ${result.coins_saved} coins`);
console.log(`Total coins found: ${result.coins_found}`);
console.log(`Graded to Bank: ${result.graded_to_bank}`);
console.log(`Graded to Fracked: ${result.graded_to_fracked}`);
console.log(`Graded to Counterfeit: ${result.graded_to_counterfeit}`);
// Optional: Fix fracked coins if any
if (result.graded_to_fracked > 0) {
console.log('Running fix for fracked coins...');
await fixFrackedCoins();
}
} else {
console.error(`Error: ${result.error} (HTTP ${result.http_code})`);
}
} catch (error) {
console.error('Network error:', error);
}
}
async function fixFrackedCoins() {
const response = await fetch(`${API_HOST}/api/coins/fix`);
const result = await response.json();
console.log('Fix complete:', result);
}
// Example: Download coins from locker
const lockerKey = '0123456789abcdef0123456789abcdef';
downloadFromLocker(lockerKey);
cURL
# Download coins from locker (automatically grades to Bank/Fracked/Counterfeit)
curl -X GET "http://localhost:8080/api/transactions/locker/download?locker_key=0123456789abcdef0123456789abcdef"
# Example output:
# {
# "status": "success",
# "operation": "locker_download",
# "coins_found": 5,
# "coins_saved": 5,
# "graded_to_bank": 4,
# "graded_to_fracked": 1,
# "graded_to_counterfeit": 0,
# "locker_key": "0123456789abcdef0123456789abcdef"
# }
# Optional: Fix fracked coins if any were downloaded
curl -X GET "http://localhost:8080/api/coins/fix"
Go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
const ApiHost = "http://localhost:8080"
type LockerDownloadResponse struct {
Status string `json:"status"`
Operation string `json:"operation"`
CoinsFound int `json:"coins_found"`
CoinsSaved int `json:"coins_saved"`
GradedToBank int `json:"graded_to_bank"`
GradedToFracked int `json:"graded_to_fracked"`
GradedToCounterfeit int `json:"graded_to_counterfeit"`
LockerKey string `json:"locker_key"`
}
type ErrorResponse struct {
Status string `json:"status"`
Error string `json:"error"`
HTTPCode int `json:"http_code"`
}
func downloadFromLocker(lockerKey string) error {
url := fmt.Sprintf("%s/api/transactions/locker/download?locker_key=%s",
ApiHost, lockerKey)
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var result LockerDownloadResponse
if err := json.Unmarshal(body, &result); err != nil {
return err
}
fmt.Printf("Success! Downloaded and graded %d coins\n", result.CoinsSaved)
fmt.Printf("Total coins found: %d\n", result.CoinsFound)
fmt.Printf("Graded to Bank: %d\n", result.GradedToBank)
fmt.Printf("Graded to Fracked: %d\n", result.GradedToFracked)
fmt.Printf("Graded to Counterfeit: %d\n", result.GradedToCounterfeit)
// Optional: Fix fracked coins if any
if result.GradedToFracked > 0 {
fmt.Println("Running fix for fracked coins...")
fixFrackedCoins()
}
return nil
} else {
var errResp ErrorResponse
if err := json.Unmarshal(body, &errResp); err != nil {
return err
}
return fmt.Errorf("Error %d: %s", errResp.HTTPCode, errResp.Error)
}
}
func fixFrackedCoins() error {
resp, err := http.Get(fmt.Sprintf("%s/api/coins/fix", ApiHost))
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Println("Fix complete")
return nil
}
func main() {
lockerKey := "0123456789abcdef0123456789abcdef"
if err := downloadFromLocker(lockerKey); err != nil {
fmt.Printf("Error: %v\n", err)
}
}
Technical Details
RAIDA Protocol
Command Codes:
- 0x0853: Locker Peek - Query locker contents
- 0x0854: Locker Remove - Download and remove coins
Timeout Configuration:
- Per-RAIDA timeout: 10 seconds (10000ms)
- Parallel execution: All 25 RAIDAs queried simultaneously
- Total operation time: ~10-15 seconds (single timeout period)
Cloud Consensus Algorithm:
- Send Peek requests to all 25 RAIDAs in parallel
- Count successful responses (status = ALL_PASS)
- If <13 RAIDAs respond at all → Network error (503)
- If <13 successful peeks → Wrong key or no locker (404)
- If ≥13 successful peeks → Use first RAIDA's coin list (all should match)
- Proceed to Remove phase with consensus coin list
New AN Generation:
For security, new random ANs are generated for each coin during download:
- Each coin gets 25 new 16-byte random ANs (one per RAIDA)
- Random source: BCrypt (Windows) or /dev/urandom (Unix)
- Old locker ANs are discarded and cannot be recovered
- Sender has no knowledge of the new ANs after download
File Format
Binary File Structure (CloudCoin v3, Format 9):
- File Header: 32 bytes
- Format ID: 9 (1 byte)
- Coin ID: 0x0006 (2 bytes)
- Encryption: 0 (1 byte - unencrypted)
- Password hash: 7 bytes (empty for unencrypted)
- POWN string: 12.5 bytes (25 nibbles, 4-bit packed)
- Reserved: 8 bytes
- Token count: 1 (2 bytes - single coin file)
- Coin Header: 7 bytes
- Split: 0 (1 byte)
- Shard: 0 (1 byte)
- Denomination: -8 to +11 (1 byte)
- Serial Number: 0-16777215 (4 bytes)
- Coin Body: 400 bytes
- 25 Authenticity Numbers × 16 bytes each
- Each AN is a random 128-bit value
- Total file size: 439 bytes per coin
Related Endpoints
/api/raida/lockers/peek
Peek at locker contents without downloading. View which coins are available before committing to download.
/api/raida/locker/upload
Upload CloudCoins to a locker for transfer to another user or wallet.
/api/coins/import
Import coins from various file formats (binary, JSON, PNG, JPEG) into the active wallet.
/api/coins/authenticate
Authenticate coins by checking with all 25 RAIDA servers and updating POWN strings.
/api/coins/grade
Sort coins into Bank, Fracked, or Counterfeit folders based on POWN string authentication results.
/api/coins/fix
Heal fracked coins (13-24 passes) using RAIDA ticket-based repair protocol.