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
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.
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 theTransaction
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:
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:
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 aCoinDataHeight
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:
The above example will, starting from the transaction mentioned previously, 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:
Last updated