# Documentation

# Background

Operate's design is heavily influenced by (and cross-compatible with) unwriter's Bitcom. If you are one of the many developers already following Bitcom's conventions to power your app, you will find Operate fits nicely into how you already reason about your application.

Operate offers some distinct advantages over native Bitcom.

# Protocols are functions

In Operate, protocols are functions, called "Ops". Anyone can write an Op and publish it to the blockchain and anyone can read the source of an Op to verify what it does. Ops are incredibly powerful and can be used to process data, perform calculations and operations, and return any computable value.

Application developers no longer need to spend time implementing protocol specifications. Operate is a decentralised repository of pre-built, ready to roll, immutable functions.

# Referencing Ops

Ops are referenced by the first 4 bytes of the SHA-256 hash of the function. This allows transaction scripts to keep a compact and succinct form, whilst retaining all the benefits of a decentralised universal naming mechanism.

(In the unlikely but possible scenario of two Ops sharing the same first 4 bytes from it's SHA-256 hash, the second function will be referred to by the first 5 bytes).

# Functional programming

Operate takes advantage of two other unwriter innovations: the Bitcom pipeline and BOB (Bitcoin OP_RETURN Bytecode).

BOB views Bitcoin input and output scripts as "tapes" made up of "cells", where each cell is a single atomic procedure call. This metaphor fits Operate like a glove. In fact it's not even a metaphor, each cell IS a procedure call, it's an Op!

Operate tape

Each Op takes a number of parameters and returns a result known as the "state". The state is passed as an argument to the next Op, along with any other parameters, and a new state is returned. Each subsequent Op returns a new state until the last Op returns result of the tape.

This approach is analogous to pure functional programming, all encapsulated in Bitcoin transactions. It is an incredibly flexible and powerful system.

# Creating a program / tape

No new tools are needed to craft a transaction that is a valid Operate program. If you are already familiar with Bitcom's conventions to construct transactions, the same conventions are used by Operate. In fact, many of these legacy transactions are already perfectly valid Operate programs! 🤯

The following example pipes together two Ops:

    "Satoshi Nakamoto"

# Using JavaScript

We can use familiar tools and libraies to help construct the above scripts. For example, using bsv.js:

chunks = [
  bsv.deps.Buffer.from('2E25B1BD', 'hex'),
  bsv.deps.Buffer.from('0CA59130', 'hex'),
  bsv.deps.Buffer.from('Satoshi Nakamoto')

script = new bsv.Script({ chunks })

# Using Elixir

Or alternatively using BSV-ex (Elixir):

chunks = [
  "Satoshi Nakamoto"

script = %BSV.Script{chunks: chunks}

In true Blue Peter style, here's one we made earlier:

# Loading and running programs

The Operate agent (Elixir) is used to load and run programs from transactions. To install the agent in your application, add it to your list of dependencies in mix.exs.


The most recent luerl package published on hex.pm is based on Lua 5.2 which is not compatible with all Ops. It is recommended to override the luerl dependency with the latest development version to benefit from Lua 5.3.

def deps do
    {:operate, "~> 0.1.0-beta"},
    {:luerl, github: "rvirding/luerl", branch: "develop", override: true}

The API for loading and running tapes is very simple:

txid = "0442b8de08b338c2fd262b2639372eaaf6d16dbf1f8e8eeb821a83ed639e75df"
{:ok, tape} = Operate.load_tape(txid)
{:ok, tape} = Operate.run_tape(tape)


# returns
  "fibs" => [
  "name" => "Satoshi Nakamoto"

# Compatibility with Bitcom protocols

Many existing transactions using Bitcom protocols are already fully compatible with Operate. By configuring the agent's aliases option, we can alias legacy protocols to Ops designed to implement that protocol.

Most applications make use of a small number of protocols, so by adding just a handful of aliases, your application is already compatible with Operate.

aliases = %{
  "19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut" => "6232de04", # b://
  "1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5" => "1fec30d4", # map
  "15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva" => "577953fb", # aip
  "1LtyME6b5AnMopQrBPLk4FGN8UBuhxKqrn" => "5ad609a8", # weatherSV

{:ok, tape} = Operate.load_tape(txid, aliases: aliases)
{:ok, tape} = Operate.run_tape(tape)

For more information on how to use and configure Operate, read the agent's full documentation.

# Writing Ops

As the public repository of Ops grows, developers may find they can use Operate without creating their own Ops. But occaisionally it may be necessary to create and publish your own bespoke Op.

# Anatomy of an Op

An Op is a function written in Lua.

Document the function
return function(state, arg1, arg2, ...)
  state = state or {}
  -- Code here
  return state

The first argument of the function is always the state. Where a function is called in the first cell of a tape, the state will default to nil so your function should handle that.

The function can receive any number of arguments, as defined by your protocol's parameters. Within the body of the function, those arguments can be used to mutate the state in any way before returning a new, modified state.

The comment block immediately prior to the function should be used to add documentation and examples. Any Markdown formatted text can be placed here.

# What can an Op do?

Most Ops will probably be simple, single purpose functions, designed to do one thing and do it well. However, the Lua VM and agent can be combined to very powerful effect.

A function can return any value, including other functions. Returned functions can then be called in your own application's code, outside of Lua. This is a great way of passing in private data such as keys, without permanently exposing them to the Lua VM.

Developers can also chose to extend the Lua VM with their own modules, even writing Elixir code in their own application that is called from within the Lua VM.

This kind of flexibility is powerful and opens up use cases limited only by your imagination.

# Publishing Ops with the CLI

The Operate CLI provides a set of tools to help create, manage and publish Ops. It can be installed using npm or yarn.

# Install with npm
> npm install -g @operate/cli

# Install with yarn
> yarn global add @operate/cli

You can list all available commands and/or get usage help for a specific command.

# List available commands
> operate --help 

# Get help on any command
> operate [command] --help

Use the init command to initialise a working directory for your Op(s). This will generate a .bit environment file in your working directory containing your publishing address and private key.

> operate init path/to/directory

You will need to fund your publishing wallet before publishing any Op. From within your working directory, use the wallet command to see your wallet address and balance.

> operate wallet

Use the new command to generate a new blank function in the src folder of your working directory.

> operate new my/function -a arg1 -a arg2

When ready (and your publishing wallet is funded), use the publish command to publish the Op to the blockchain.

> operate publish my/function

It is recommended to test functions thoroughly before publishing on the blockchain. View the operate/op_library repository for examples of setting up an Op library with an Ex-Unit test suite.