Implement
In this page, we go over the details of actually implementing a Gibbername library in Rust.
π¨βπ» Follow along on GitHub!
Project setup
The first step of implementing Gibbername is to create a new Rust library with the melprot dependency:
cargo new --lib gibbername
cd gibbernameWe'll also be adding some dependencies. These will show up in the Cargo.toml:
cargo add futures-util anyhow gibbercode hex melprot melstructs stdcode tmelcryptLooking up names
The easiest part of Gibbername is looking up the names. This consists of three parts:
Decoding the Gibbername into a blockchain location identifying the start of the Catena chain. This means a block height and a transaction hash.
Obtaining and validating the start transaction by obtaining a snapshot at the given block height, retrieving the start transaction, and making sure that its
datafield says"gibbername-v1".Traversing the Catena chain, following all the custom-token coins, traverse the Catena chain to the most recent element. We'll then have our binding!
The Gibbername encoding
How can we squeeze a blockchain location β which identifies a transaction and its location β into a short "gibberish string" like xoxqax-lobteh? After all, unique transaction hashes are very long and unwieldy.
Instead, we encode a unique blockchain location as two numbers: the block height and the transaction position. This position is the 0-indexed position of the transaction within all the transactions in that block sorted by hash.
This lets us represent any transaction in the blockchain uniquely with two smallish numbers. For instance, the transaction with the "smallest" hash in block 100000 would be represented as 100000,0.
We then need to represent this pair of numbers as a friendly Gibbername. Fortunately, we can use gibbercode, a crate that encodes a pair of numbers into a gibberish string using the consonants for the first number and the vowels for the second.
Validating the start transaction
Once we have the blockchain location, we need to retrieve the start transaction. This can be done using melprot's Snapshot::get_transaction_by_posn() function.
The start transaction should have a data field that says "gibbername-v1", as well as one, and just one, output with denomination Denom::NewCustom, and that output must have value 1. This is the way we ensure that a given Gibbername is actually valid.
Traversing the Catena chain
Finally, we can traverse the Catena chain to get the coin containing the final binding:
We can now easily build the gibbername lookup function!
Registering names
Registering names is a little different: we need to send a transaction into the blockchain rather than just reading existing data.
One possible way is to craft a transaction inside our library and send it by directly calling an RPC method on a full node (through something like melprot::Client::raw_rpc()). But this is hard, because we must somehow get hold of $MEL to pay transaction fees (possibly by asking the user to send money to some address?). Furthermore, even once we have $MEL, managing the money and the private keys securing it difficult, security-critical task.
Instead, we ask the user's wallet to send a transaction for us, and we simply wait until the user finishes doing so. In summary, here are the steps to register a new gibbername:
Prompt and wait for the transaction
We can now write a function to send the transaction and wait for it to commit in the blockchain.
When this function is called, the user will be prompted to manually send a transaction with our wallet CLI: melwallet-cli. We will continuously stream incoming transactions until we find the one we sent. We are now able to register a name with an arbitrary binding! π
Transferring names
Transferring names is left as an exercise to the reader.
Last updated