# MesharePay

Java 8 wallet for Meshare points. A public key's points come from how often that key was found on the servers (the ranking produced by [`MeshareRank`](README_MeshareRank.md)). With MesharePay you can see your balance and **send points to other keys** using signed transactions. Nodes exchange everything with plain HTTP GET requests, and every node checks for double spending on its own.

It runs as a local web page: it starts a web server, opens your browser, and the same server is this node's address for other nodes.

## Requirements

- Java 8 or newer
- A web browser (optional: you can also open the address by hand)
- **Your own P-256 (secp256r1) key pair.** MesharePay does not create keys. You can paste them as PEM or plain Base64, or put them in `public_key.txt` and `private_key.txt`. To make a pair with OpenSSL:

  ```
  openssl ecparam -name prime256v1 -genkey -noout -out ec.pem
  openssl pkcs8 -topk8 -nocrypt -in ec.pem -out private_key.txt
  openssl pkey -in ec.pem -pubout -out public_key.txt
  ```

- A `consensus.txt` (from `MeshareRank`) on this machine, or servers that publish one, so your key has earned points.

## Compile and run

Run it from the folder that holds your files:

```
javac MesharePay.java
java MesharePay             # web page on port 8097
java MesharePay 9000        # or choose the port
```

- It prints `MesharePay is running at http://localhost:<port>/` and tries to open that address in your browser. On a machine without a desktop, open the address yourself.
- If the port is busy, it uses the next free one (up to 49 ports higher). The console shows the port it used.
- Press **Ctrl+C** in the console to stop.
- **It does not sync at start-up.** It works from the files on disk until you press **Sync**.
- The log is shown in the web page only; the console prints just the start-up lines.

## Files

| File or folder | Role |
|----------------|------|
| `servers.txt` | **Input.** The other nodes to sync with, one URL per line. Blank lines and lines starting with `#` are ignored. Editable from the web page. |
| `consensus.txt` | **Input, and served to others.** `<key>:<count>` per line, made by `MeshareRank`. Read at start-up and on every Sync. |
| `public_key.txt`, `private_key.txt` | **Input.** Your keys. Loaded at start-up if `public_key.txt` exists (`private_key.txt` is optional). Written only if you tick the save box. |
| `blocks/*.json` | **Input, optional.** Confirmed blocks with a `public_key` field (from `MeshareChain`, which is not part of these files). Used as a minimum for earned points. |
| `transactions/<id>.json` | **Output.** One file per known transaction. Created once and never overwritten. |
| `transactions.txt` | **Output.** Index of the transaction files. |
| `points/<sha256(key)>.json` | **Output.** A snapshot of each key's earned, spent and balance. |
| `points.txt` | **Output.** Index of the snapshot files. |

## Concepts

### Address

A key's address is the Base64 of its X.509 public key bytes. A key pasted as PEM (with headers) or as wrapped Base64 is converted to this form, so the same key always has the same address. Only P-256 keys are accepted.

### Balance

```
balance = max(0, earned - spent)
```

- **Earned** is the highest of:
  - the highest count for the key in any `consensus.txt` (yours or a server's),
  - the highest `earned` value in any server's `points/` snapshot,
  - the number of times the key appears as `public_key` in your local `blocks/` folder.
- **Spent** is the higher of:
  - the total of this key's transactions that this node accepts,
  - the highest `spent` value any server reports for the key. This protects a node that is behind on updates from letting someone spend twice.

### Transaction

A small JSON file with these fields:

| Field | Meaning |
|-------|---------|
| `id` | SHA-256 (hex) of the text `from\|to\|amount\|nonce\|timestamp` |
| `from`, `to` | Sender and receiver addresses |
| `amount` | Whole number of points, greater than 0 |
| `nonce` | Random value, so two identical transfers are different |
| `timestamp` | Time in milliseconds, set by the sender |
| `signature` | ECDSA (SHA-256) signature of that same text, made with the sender's private key |
| `date` | The timestamp as readable text |

Anyone can check a transaction without trusting who sent it: the `id` must match the content, and the signature must match the `from` key.

### Double-spend guard

Every node takes all transactions it knows, groups them by sender and replays them in order of `timestamp` (then `id`). A transaction is **accepted** while the sender's running total stays within their earned points. Otherwise it is marked `rejected: exceeds available points (double-spend guard)`. This is a calculation each node does for itself. Rejected transactions stay on disk and are shown with their status.

## Using the web page

1. **Wallet.** Paste the public key (and the private key, only if you want to send), or press **Load from files**. Tick *save to public_key.txt / private_key.txt* to write the keys to disk. Without a private key you can only look at balances.
2. **Balance.** Shows *Earned*, *Spent* and *Available* for your key.
3. **Sync** (top of the page) fetches data from the servers in `servers.txt`. **Stop** ends it after the server it is working on. The **servers.txt** button edits the server list.
4. **Send funds.** Enter the recipient's public key and a whole number of points, then press **Send**.
5. **Transactions.** Lists your transactions (or recent activity if no wallet is loaded), with their status.

### Example

`consensus.txt` says your key was found 5 times. You send 2 points to another key:

| | Earned | Spent | Available |
|-|--------|-------|-----------|
| Before | 5 | 0 | 5 |
| After | 5 | 2 | 3 |

Sending 10 more is refused: `Insufficient balance: have 3 point(s), tried to send 10`.

### Messages when sending

| Message | Reason |
|---------|--------|
| `Load a wallet with a private key before sending` | No private key is loaded |
| `Amount must be a positive whole number of points` | Amount is 0, negative or not a whole number |
| `Invalid recipient public key: ...` | The recipient is not a valid P-256 public key |
| `Cannot send to your own key` | Recipient is your own address |
| `Insufficient balance: have N point(s), tried to send M` | Not enough available points |
| `Failed to record transaction (id collision or already known)` | Usually means **the private key does not belong to the public key**. The program does not check that the two match when you load them, and a signature that does not verify is rejected with this unclear message. |

## Sending and syncing between nodes

**Nothing is pushed to other nodes.** Sending a transaction only saves it in `transactions/` and lists it in `transactions.txt`. Other nodes get it when they press Sync and this node is in their `servers.txt`. So every node that should see your transactions needs your address in its `servers.txt`, for example `http://your-host:8097/`.

**Sync** goes through `servers.txt` from top to bottom. For each server it sends GET requests for:

1. `consensus.txt`. Each key keeps the highest count seen.
2. `transactions.txt`, then every `transactions/<id>.json` it does not already have. A transaction is stored only if it is complete, the `id` matches, the sender is a valid P-256 key, the signature is valid, the amount is above 0 and sender and receiver differ.
3. `points.txt`, then every `points/<file>.json`. Each key keeps the highest `earned` and the highest `spent`.

A server that does not have these files is skipped without an error, so `servers.txt` can also list servers that are not MesharePay nodes. When all servers are done, the node re-reads `blocks/`, recalculates every balance and rewrites its own `points/` and index files.

## Web addresses served

These are the addresses other nodes read (GET only). The private key is never served.

| Address | Content |
|---------|---------|
| `/consensus.txt` | This node's `consensus.txt` (404 if there is none) |
| `/transactions.txt` | Index of the transaction files (empty if none) |
| `/transactions/<id>.json` | One transaction |
| `/points.txt` | Index of the points snapshots (empty if none) |
| `/points/<sha256(key)>.json` | One key's `public_key`, `earned`, `spent`, `balance`, `updated` |

The web page and its own controls use `/`, `/api/state`, `/api/events`, `/api/run`, `/api/stop`, `/api/servers/reload`, `/api/file`, `/api/wallet/keys`, `/api/wallet/keys/load`, `/api/wallet/keys/clear`, `/api/wallet/balance`, `/api/wallet/transactions` and `/api/send`.

## Trust and limits

- **The servers in `servers.txt` are trusted.** The highest `earned` and the highest `spent` reported by any of them are used. A dishonest server could therefore raise someone's earned points, or report a high `spent` to lower someone's balance.
- Each node decides accepted or rejected by itself. Nodes can disagree until they have synced the same data.
- Sync is manual: there is no automatic or periodic sync.
- Transaction order for the double-spend guard uses the timestamp the sender wrote.
- Timeouts: 10 s to connect, 20 s per read.

## Security

- The web server listens on **all network interfaces** and has **no password**. While a wallet with a private key is loaded, anyone who can reach the port can call `/api/send` to spend your points, replace the keys, or edit `servers.txt`.
- Peers need to reach the same port to read your data, so the web page and the node address cannot be separated by the program. If the node must be reachable from outside, put a reverse proxy or firewall in front that lets the network see only the five GET addresses in the table above.
- If you tick the save box, `private_key.txt` is written as **plain, unencrypted text** and the program does not restrict who can read it. Pasting a private key into the page sends it over plain HTTP to the program, so do that only on `localhost`.
- Use **Clear** in the Wallet card to remove the keys from memory. It does not delete `public_key.txt` or `private_key.txt`, and they are loaded again the next time the program starts.

## Related programs

[`MeshareRank`](README_MeshareRank.md) produces the `consensus.txt` that MesharePay uses as earned points.
