# melprot: a quick intro

## melprot::Client: a trustless light client

The most basic tool for light-client interaction in Mel is `melprot::Client`, a struct exposed by the melprot Rust crate that implements Mel's P2P protocol. `melprot::Client` is a light client that can be used to query full nodes for information about blockchain contents.

But unlike a raw RPC client (which does exist as `melprot::NodeRpcClient`), `melprot::Client` internally validates Merkle-tree proofs and staker signatures so that it *avoids trusting any full node*. Everything that `melprot::Client` returns is backed by the decentralized, incentive-based trust of the Mel blockchain, and nothing can be faked by a malicious node or RPC network.

## Basic data model

```
a picture of the whole data model, looking roughly like:

[snapshot]  ... [snapshot]
     |
 [map]  [map] ...
```

### Snapshots

The data model of `melprot::Client` is largely focused on the **state snapshot**, which is an immutable, trustless view of *the state of the blockchain at a given height*. For instance, the following code obtains snapshots of the state at different heights, and queries how many unspent coins a particular address owns at the two heights.

```rust
// get a mainnet Client
let client = melprot::Client::autoconnect(NetID::Mainnet);
// get the current snapshot
let snap_current = client.latest_snapshot().await?;
// get the snapshot at block height 10000
let snap_10000 = client.snapshot(BlockHeight(10000)).await?;
// display how many UTXOs are labeled with foobar_address now vs at block 10000
println!("address {} has {} UTXOs now but {} UTXOs at block 10000",
   foobar_address,
   snap_current.coin_count(foobar_address).await?,
   snap_10000.coin_count(foobar_address).await?
);
```

### Looking up info

Within a snapshot at a given height, there are many mappings associated with the state of the blockchain at that given height and a variety of methods for conveniently looking them up. Some of the most important ones include:

* `get_coin(id: CoinID)`: given the ID (transaction hash and index) of a particular coin, return the coin data.
* `get_transaction(txhash: TxHash)`: given a transaction hash, return the `Transaction` if it exists.

### Moving a snapshot back in time

Since snapshots commit to the state of a blockchain at a particular height — which includes the previous history — they can be used to verify older claims about blockchain contents but not later claims. This is represented in `melprot` by `Snapshot::get_older(height: BlockHeight)`, which can move snapshots backwards in time, but not forwards:

```rust
// get a snapshot at block height 100
let snap_100 = client.snapshot(BlockHeight(100)).await?;
// get a snapshot at block height 50
let snap_50 = snap_100.get_older(BlockHeight(50)).await?;
// this fails:
let snap_200 = snap_100.get_older(BlockHeight(200)).await?;
```

## Coin graph traversal

A very common task for light clients is traversing the **coin graph** of the blockchain, which is the global directed graph of all transactions spending and creating coins. For instance, this is a fragment of the coin graph centered around [a particular mainnet transaction in block 1901450](https://scan.themelio.org/blocks/1901450/674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873):

<figure><img src="https://2733178711-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfyfIKQnkuheUwyaEXngm%2Fuploads%2FWdfkgR0xzZMwtbhu63mQ%2Fimage.png?alt=media&#x26;token=5dbc2d2f-81e2-43f1-979c-ef92f28671c9" alt=""><figcaption></figcaption></figure>

Given a known starting point — a particular transaction with a known location on the blockchain — the basic snapshot model detailed above allows easy traversal:

* **Moving backwards in time**: looking up the `CoinID` of a transaction input in a snapshot *older* than the transaction itself retrieves a `CoinDataHeight` that contains the height in which the transaction input was committed to the blockchain. This gets you the location of a "parent" transaction.
* **Moving forwards in time**: to look up when an output is spent, a binary search can be done between the state in which the transaction was committed and the present, to see the exact block height at which the output was spent. Then, a snapshot at that height can be used to retrieve the "child" transaction that spent the output.

It's certainly possible to manually implement the above, but `melprot` provides to very convenient methods `Client::traverse_back` and `Client::traverse_fwd`. These functions take in a "starting" transaction (block height and transaction hash), as well as a closure to specify *which* parent or child coin to follow to the next link, and return a `Stream` of `Transaction`s:

```rust
let client = melprot::Client::autoconnect(NetID::Mainnet);

let traversal = client.traverse_back(
   BlockHeight(1901450),
   "674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873".parse()?,
   |tx| {
      // find the first input
      tx.outputs.get(0)
   }
).boxed();

while let Some(next) = traversal.next().await? {
   println!("transaction found: {:?}", next);
}
```

The above example will, starting from the [transaction mentioned previously](https://scan.themelio.org/blocks/1901450/674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873), traverse its ancestry through the first input until it hits a transaction with no inputs (the first ever transaction in the blockchain!). Graphically, it essentially does this:

<figure><img src="https://2733178711-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfyfIKQnkuheUwyaEXngm%2Fuploads%2F7feOZtH8R1e0ycOOkIkJ%2Foutput.gif?alt=media&#x26;token=540988cf-948b-4402-bb85-e773c356e345" alt=""><figcaption><p>Clicking on the first parent indefinitely</p></figcaption></figure>
