UTXO-based token system

As an exercise, we can also implement a Bitcoin-style token system.

We first define an unspent transaction output structure:

class utxo {
    pubkey;
    amount: integer;
}

Then define the transfer operation that roughly follows Bitcoin transaction structure – it has a list of inputs and outputs:

operation transfer (inputs: list<utxo>, output_pubkeys: list<pubkey>, output_amounts: list<integer>) {
      var input_sum = 0;
      for (an_utxo in inputs) {
          require(is_signer(an_utxo.pubkey));
          input_sum += an_utxo.amount;
          delete utxo@{utxo == an_utxo};
      }
      var output_sum = 0;
      require(output_pubkeys.size() == output_amounts.size());
      for (out_index in range(output_pubkeys.size())) {
          output_sum += output_amounts[out_index];
          create utxo (output_pubkeys[out_index],
                       output_amounts[out_index]);
      }
      require(output_sum <= input_sum);
}

There are quite a lot of new constructs used in this example:

  • list<...> is, obviously, a collection. Besides lists, Rell also supports set and map, see languagespec_collectiontypes for syntax.
  • in list<utxo> utxo object references are physically implemented using integer identifiers which are used interally
  • an_utxo.pubkey accesses an attribute of an object, which is a database query identical to utxo@{utxo==an_utxo} (pubkey)
  • variable type is automatically inferred from expression used for initialization. One can also write it like var output_sum : integer = 0;
  • delete operation accepts a relational expression which identifies object(s)
  • .size() method can be used get the size of a collection
  • for (... in ...) works both for collections and for ranges of integer values
  • [] is used to refer to an element of a collection

Note that we perform checks as we go. This is OK because Rell is transactional: if a requirement fails or an error is generated, the whole operation (in fact, the whole transaction) is rolled back. Rell is typically used with a GTX transaction format which supports multiple signers and multiple operations per transaction. Thus it can easily support Bitcoin-style multi-input transactions, atomic token swaps, multi-sig etc.

Now a bit about delete operator. Isn’t it strange to enable deletion of data from a blockchain?!

Here we aren’t deleting data “from a blockchain”, we are removing entries from the current blockchain state. This is exactly how it works in a Bitcoin node – once entries in an unspent transaction output set are spent, they are deleted. A typical Bitcoin node doesn’t keep track of spent transaction outputs.

A system based on Rell (e.g. Postchain or Chromia) works in exactly the same way: raw information about transactions and operations is preserved in a blockchain. The database contains both raw blockchain transactions and processed current state. The current state is what a Rell programmer can work with: he is allowed to do destructive updates and delete entries. These operations do not affect the raw blockchain.