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);