Skip to main content

Operation

Operations are declared using the operation keyword, followed by a unique operation name and a list of parameters enclosed in parentheses. The parameters specify the data that the operation expects as input.

Operations have the following characteristics:

  • Can modify the data in the database
  • Doesn't return a value
  • Parameter types must be GTV-compatible
Example
operation create_user(name: text) {
create user(name = name);
}

Illustrative example: registering a channel

Make an operation that allows a user to create a new channel:

operation register_channel (user_pubkey: pubkey, channel_name: name) {
require( op_context.is_signer(user_pubkey) );
create channel (
owner = user @ {.pubkey == user_pubkey},
name = channel_name
);
}

You can go through this line by line. First we declare the operation name and a list of parameters:

operation register_channel (user_pubkey: pubkey, channel_name: name) {

It is very similar to function definitions in other languages. An operation is a function of a special kind: you can invoke it by using a blockchain transaction by its name. When invoking register_channel, the caller must provide two arguments of specified types. Otherwise, it fails.

require( op_context.is_signer(user_pubkey) );

We don't want Alice to be able to pull a prank on Bob by registering a channel with a silly name on his behalf. Thus we need to ensure that the transaction gets signed with a key corresponding to the public key specified in the first parameter. (In other words, if Bob's public key is user_pubkey, the transaction must also get signed by Bob. That's, Bob is a signer of this transaction.) it's a typical pattern in Rell -- typically, you specify an actor in an operation parameter. In the body of the operation, you verify that the actor was the signer. require fails the operation if the specified condition isn't met.

create channel creates a persistent object channel. You don't need to explicitly store it, as all created objects persist if the operation succeeds.

user @ {.pubkey=user_pubkey} -- now we retrieve a user object by its pubkey, which should be unique. If no such user exists, the operation fails. We don't need to test for that explicitly, as @ operator does this job.

Rell can automatically find attribute names corresponding to arguments using types. As user and name are different types, you can write create channel as follows:

create channel (user @ {.pubkey == user_pubkey}, channel_name);