Namespace definitions

Global namespace containing types and functions accessible without any namespace prefix.

Global namespace containing types and functions accessible without any namespace prefix.

Types

Link copied to clipboard

An immutable signed integer type, supporting extremely large values (upwards of 100,000 decimal digits).

Literals of big_integer type can be written like integers, but with the suffix L, e.g. 123L or 0x123L. big_integers support the operators +, -, *, / and % with typical behavior.

Link copied to clipboard
type boolean

A data type with two possible values: true and false.

Boolean logic can be performed with the and, or and not operators, for example:

>>> true and false
false
>>> true or false
true
>>> not true
false
>>> not false
true

In addition, booleans are used in ternary expressions:

>>> if (true) 1 else 2
1
>>> if (false) 1 else 2
2

The in operator returns a boolean:

>>> 1 in list<integer>()
false
>>> 1 in [1, 2]
true

Booleans are used in if- and if/else-statements:

>>> if (false) { print("hello"); } else { print("goodbye"); }
goodbye
>>> if (false) { print("hello"); }
>>> if (true) { print("hello"); }
hello
>>>

Boolean expressions are the basis of zero-argument when-statements (each expression to the left of a '->' symbol has boolean type (and in this context else is equivalent to true)):

when {
x == 1 -> return 'One';
x >= 2 and x <= 7 -> return 'Several';
x == 11, x == 111 -> return 'Magic number';
some_value 1000 -> return 'Special case';
else -> return 'Unknown';
}

Boolean conditions are used in while loops:

while (x < 10) {
print(x);
x = x + 1;
}

Functions can have boolean return type (as can queries and operations), and indeed many functions and properties in the Rell standard library have boolean type.

function foo(x: integer): boolean {
return x >= 10;
}
Link copied to clipboard

An array of bytes. This type is immutable.

Link copied to clipboard
hidden abstract type collection<T> : iterable<T>

A generic type for mutable ordered collections of elements. Subtype of iterable<T>. Supports many standard operations such add insertion, removal, lookup and sorting.

Link copied to clipboard
hidden abstract type comparable
Link copied to clipboard
type decimal

A real number data type with high precision.

Not a complete equivalent of floating-point types, as there are a fixed maximum number of digits before the decimal point (131072, or 2^17 digits) and after the decimal point (20 digits).

Examples:

  • 123.456

  • .789

  • 7e+33

  • decimal('123456789.98765')

Link copied to clipboard
hidden abstract type entity

Parent of all entity types. An entity is a data structure that resides in the SQL database.

Entity values are created with a create statement and are persisted in the database, and are accessed with an @-expression.

Link copied to clipboard
hidden abstract type enum

An enum is a set of member constants who share a type.

The declaration enum example { A, B, C } defines a type example, with three member constants, example.A, example.B and example.C.

Enum names and member constant names follow the same rules as all identifiers in Rell. However, by convention, enum names use snake_case, and member constants use UPPER_SNAKE_CASE.

Examples:

  • enum primary_color { RED, BLUE, GREEN }

  • enum error { TIMEOUT, MALFORMED_RESPONSE, NOT_FOUND, UNAUTHORIZED, UNKNOWN }

  • enum cardinal_direction { NORTH, EAST, SOUTH, WEST }

Link copied to clipboard
type gtv

Generic Transfer Value (GTV) is a data type for the serialization and transfer of structured data, much like JSON.

GTV is used in Rell to encode operation and query arguments and results that are exchanged with clients. Unlike JSON, GTV has a stable byte serialization format and well-defined cryptographic hash, making it well-suited to this purpose. In addition, GTV supports byte arrays.

GTV supports the following types:

GTV TypeClosest Rell Equivalent
NULLnull
BYTEARRAYbyte_array
STRINGtext
INTEGERinteger
DICTmap<text, gtv>
ARRAYlist<gtv>
BIGINTEGERbig_integer

GTV does not support all Rell types, so not every value in Rell can be converted to GTV. For example, GTV has no support for non-integer numbers, and therefore the decimal type is encoded in GTV as text.

Rell types can be encoded as GTV in two modes: compact and pretty, and the distinction between the two is a real semantic difference, and is not merely a difference in whitespace when converted to text. The two modes differ in the following ways:

  • Compact GTV encode struct values as a lists of attributes, while pretty GTV encode them as a dictionaries (thus struct member names are preserved).

  • Compact GTV encode named-field tuples as a lists of attributes, while pretty GTV encode them as a dictionaries (thus tuple field names are preserved). There is no difference between the two in encoding of unnamed-field tuples.

Examples of GTV:

>>> (x = 1, y = 'a', z = true).to_gtv()
[1,"a",1]
>>> (x = 1, y = 'a', z = false).to_gtv_pretty()
{"x":1,"y":"a","z":0}
>>> [1: 'a', 2: 'b', 3: 'c'].to_gtv()
[[1,"a"],[2,"b"],[3,"c"]]
>>> [1: 'a', 2: 'b', 3: 'c'].to_gtv_pretty()
[[1,"a"],[2,"b"],[3,"c"]]
>>> set([1, 2, 3, 4]).to_gtv()
[1,2,3,4]
>>> set([1, 2, 3, 4]).to_gtv_pretty()
[1,2,3,4]
>>> struct a { x: integer; y: decimal; };
>>> a(10, 10.1).to_gtv()
[10,"10.1"]
>>> a(10, 10.1).to_gtv_pretty()
{"x":10,"y":"10.1"}

Rell operations expect their arguments as compact-encoded GTV, whereas queries expect pretty-encoded GTV arguments, hence client applications are required to use those respective formats when making operation and query calls to Rell applications.

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
alias GTXValue = gtv

Generic Transfer Value (GTV) is a data type for the serialization and transfer of structured data, much like JSON.

GTV is used in Rell to encode operation and query arguments and results that are exchanged with clients. Unlike JSON, GTV has a stable byte serialization format and well-defined cryptographic hash, making it well-suited to this purpose. In addition, GTV supports byte arrays.

GTV supports the following types:

GTV TypeClosest Rell Equivalent
NULLnull
BYTEARRAYbyte_array
STRINGtext
INTEGERinteger
DICTmap<text, gtv>
ARRAYlist<gtv>
BIGINTEGERbig_integer

GTV does not support all Rell types, so not every value in Rell can be converted to GTV. For example, GTV has no support for non-integer numbers, and therefore the decimal type is encoded in GTV as text.

Rell types can be encoded as GTV in two modes: compact and pretty, and the distinction between the two is a real semantic difference, and is not merely a difference in whitespace when converted to text. The two modes differ in the following ways:

  • Compact GTV encode struct values as a lists of attributes, while pretty GTV encode them as a dictionaries (thus struct member names are preserved).

  • Compact GTV encode named-field tuples as a lists of attributes, while pretty GTV encode them as a dictionaries (thus tuple field names are preserved). There is no difference between the two in encoding of unnamed-field tuples.

Examples of GTV:

>>> (x = 1, y = 'a', z = true).to_gtv()
[1,"a",1]
>>> (x = 1, y = 'a', z = false).to_gtv_pretty()
{"x":1,"y":"a","z":0}
>>> [1: 'a', 2: 'b', 3: 'c'].to_gtv()
[[1,"a"],[2,"b"],[3,"c"]]
>>> [1: 'a', 2: 'b', 3: 'c'].to_gtv_pretty()
[[1,"a"],[2,"b"],[3,"c"]]
>>> set([1, 2, 3, 4]).to_gtv()
[1,2,3,4]
>>> set([1, 2, 3, 4]).to_gtv_pretty()
[1,2,3,4]
>>> struct a { x: integer; y: decimal; };
>>> a(10, 10.1).to_gtv()
[10,"10.1"]
>>> a(10, 10.1).to_gtv_pretty()
{"x":10,"y":"10.1"}

Rell operations expect their arguments as compact-encoded GTV, whereas queries expect pretty-encoded GTV arguments, hence client applications are required to use those respective formats when making operation and query calls to Rell applications.

Alias
Link copied to clipboard
hidden abstract type immutable
Link copied to clipboard
hidden abstract type immutable_mirror_struct<T> : mirror_struct<T>
Link copied to clipboard
type integer

A 64-bit signed integer type, ranging from -2^63 to (2^63)-1, supporting a standard complement of numerical operations.

Link copied to clipboard
hidden abstract type iterable<T>

A generic type for sequences that can be iterated over, such as collections, ranges and maps.

Link copied to clipboard
type json

A JSON (JavaScript Object Notation) datatype.

JSON values are created from text and support conversion to GTV via gtv.from_json(). They can be stored in the database as an entity attribute.

JSON values in Rell are represented internally with text, which has been validated as legal JSON.

Link copied to clipboard
type list<T> : collection<T>

Represents a mutable array list. Subtype of collection<T>.

Link copied to clipboard
type map<K: -immutable, V> : iterable<(K, V)>

A mutable map from keys of type K to values of type V, where K is immutable, and V may be either mutable or immutable. map<K,V> is a subtype of iterable<(K,V)>`. It is implemented as a hash-map, with iteration order determined by the order in which the entries were added.

Link copied to clipboard
hidden type map_entry<K, V>

A supertype of all two-element tuples (K, V) (with named and unnamed fields), where K is an immutable type, and V may be either mutable or immutable. Generally used for iterating over maps and constructing maps from iterables.

Link copied to clipboard
hidden abstract type mirror_struct<T>
Link copied to clipboard
hidden abstract type mutable_mirror_struct<T> : mirror_struct<T>
Link copied to clipboard
alias name = text

An immutable character string data type.

Alias
Link copied to clipboard
hidden abstract type null_ext
Link copied to clipboard
hidden abstract type object

Parent of all object types. An object is a singleton data structure that resides in the SQL database.

Objects are much like entities, with the following restrictions:

  • only a single instance is allowed for each definition

  • all object attributes must have default values

  • object values cannot be created or deleted from code (they are automatically created during blockchain initialization)

Example definition:

object state {
mutable x: integer = 0;
mutable s: text = 'n/a';
}

Object attributes are accessed directly:

print(state.x);
print(state.s);

Object values can be modified directly, or with an update statement:

// Direct modification
state.x += 10;
state.s = 'Updated';

// Modification via update statement
update state ( x += 5, s = 'Updated' );
Link copied to clipboard
hidden abstract type operation
Link copied to clipboard

An array of bytes. This type is immutable.

Link copied to clipboard

A range of integer values. Ranges represent arithmetic sequences with defined start and end points, and a constant difference between consecutive elements. Ranges can be empty or contain any natural number of elements.

Range is a subtype of iterable<integer>.

Link copied to clipboard
type rowid

The primary key of a database record.

Implemented as a 64-bit integer, but requires explicit conversion to and from integer with the constructor rowid(integer) and the method rowid.to_integer(). ROWID values cannot be negative.

ROWID supports the standard complement of comparison operators (==, !=, <, >, <= and >=), and conversion to and from GTV.

Examples:

function get_rowid(username: text) {
val u = user @ { .name == username };
return u.rowid;
}

val freds_rowid: rowid = user @ { .name == "Fred" } ( .rowid );

val valid_rowids: list<rowid> = user @* { .rowid >= min_rowid };

Note that the recommended way to manipulate entity values is via typed references (e.g. u: user in the above example), as this is type-safe. Reliance on rowid is only recommended in rare cases where the standard pattern is not possible, as the compiler does not know what type of entity a given rowid value is intended to reference. Consider the example below:

entity user {}
entity company {}

val u: user = user @ {};
val c: company = company @ {};

val u2: user = c; // Bad, and the compiler tells us so.

val u_rowid: rowid = c.rowid; // Likely to lead to errors, but the compiler can't help us.
Link copied to clipboard
type set<T: -immutable> : collection<T>

A mutable set of elements of type T, where T is immutable. Subtype of collection<T>. Implemented as a hash-set, with iteration order determined by the order in which the elements were added.

Link copied to clipboard
hidden abstract type struct
Link copied to clipboard
type text

An immutable character string data type.

Link copied to clipboard

A 64-bit signed integer type, ranging from -2^63 to (2^63)-1, supporting a standard complement of numerical operations.

Alias
Link copied to clipboard
type unit

A type with no member values, much like void in other languages.

Typically used as a return type for functions where no return value is required. Indeed, when a function is declared without a specified return type, the return type is implicitly unit. In other words, the function definition:

function f(...) { ... }

is equivalent to:

function f(...): unit { ... }
Link copied to clipboard
hidden type virtual<T>
Link copied to clipboard
hidden abstract type virtual_collection<T> : iterable<T>
Link copied to clipboard
hidden type virtual_list<T, T2> : virtual_collection<T2>
Link copied to clipboard
hidden type virtual_map<K: -immutable, V0, V> : iterable<(K, V)>
Link copied to clipboard

Functions

Link copied to clipboard

Returns the absolute value of a big_integer value; i.e. the value itself if it's positive or its negation if it's negative.

function abs(a: decimal): decimal

Returns the absolute value of a decimal value; i.e. the value itself if it's positive or its negation if it's negative.

function abs(a: integer): integer

Returns the absolute value of a integer value; i.e. the value itself if it's positive or its negation if it's negative.

Link copied to clipboard
(alias) function <T> assert_equals(actual: T, expected: T)

Assert two values are equal.

Link copied to clipboard
(alias) function assert_events(expected: (text, gtv)...)

Assert that the given events were emitted during the construction of the last block, in the specified order.

Events are emitted in application code using op_context.emit_event().

Example - single event:

Application code
operation main() {
op_context.emit_event("my_message_type", "my_data".to_gtv());
}
Test code
function test_main() {
main().run();

// Assertion passes
rell.test.assert_events(("my_message_type", "my_data".to_gtv()));
}

function test_main_bad_1() {
main().run();

// Assertion fails - wrong message type
rell.test.assert_events(("other_message_type", "my_data".to_gtv()));
}

function test_main_bad_2() {
main().run();

// Assertion fails - wrong message content
rell.test.assert_events(("my_message_type", "other_data".to_gtv()));
}

Example - multiple events:

Application code
operation main() {
op_context.emit_event("my_message_type", "my_data".to_gtv());
op_context.emit_event("other_message_type", "other_data".to_gtv());
}
Test code
function test_main() {
main().run();

// Assertion passes
rell.test.assert_events(
("my_message_type", "my_data".to_gtv()),
("other_message_type", "other_data".to_gtv())
);
}

function test_main_bad() {
main().run();

// Assertion fails - event order incorrect
rell.test.assert_events(
("other_message_type", "other_data".to_gtv()),
("my_message_type", "my_data".to_gtv())
);
}

To assert a subset of events, or to assert independently of event order, use rell.test.get_events() and make assertions over elements of the returned list.

Link copied to clipboard
(alias) function <T> assert_fails(fn: () -> T): rell.test.failure

Asserts a function fails; i.e. throws an exception.

Example

Application code
// This will throw a exception.
function bad(): integer {
return [0][1];
}
Test code
// This test will pass.
function test_bad() {
rell.test.assert_fails(bad(*));
}
(alias) function <T> assert_fails(expected_message: text, fn: () -> T): rell.test.failure

Asserts a function fails; i.e. throws an exception; with a given exception message.

Verifies that the given exception message is a substring of the exception thrown by the given function (if thrown).

Example

Application code
// This will throw a exception.
function bad(): integer {
return [0][1];
}
Test code
// This test will pass.
function test_bad() {
rell.test.assert_fails("out of bounds", bad(*));
}
Link copied to clipboard
(alias) function assert_false(actual: boolean)

Assert a value is false.

Prefer other assertion functions where possible, as they provide better error messages.

Link copied to clipboard
(alias) function <T: -comparable> assert_ge(actual: T, least_expected: T)

Assert that a value is greater than or equal to a given lower bound.

Link copied to clipboard
(alias) function <T: -comparable> assert_ge_le(actual: T, least_expected: T, greatest_expected: T)

Assert that a value falls within given bounds.

Specifically, assert that the value is greater than or equal to a lower bound, and less than or equal to an upper bound.

Link copied to clipboard
(alias) function <T: -comparable> assert_ge_lt(actual: T, least_expected: T, greatest_expected: T)

Assert that a value falls within given bounds.

Specifically, assert that the value is greater than or equal to a lower bound, and less than an upper bound.

Link copied to clipboard
(alias) function <T: -comparable> assert_gt(actual: T, least_expected: T)

Assert that a value is greater than a given lower bound.

Link copied to clipboard
(alias) function <T: -comparable> assert_gt_le(actual: T, least_expected: T, greatest_expected: T)

Assert that a value falls within given bounds.

Specifically, assert that the value is greater than a lower bound, and less than or equal to an upper bound.

Link copied to clipboard
(alias) function <T: -comparable> assert_gt_lt(actual: T, least_expected: T, greatest_expected: T)

Assert that a value falls within given bounds.

Specifically, assert that the value is greater than a lower bound, and less than an upper bound.

Link copied to clipboard
(alias) function <T: -comparable> assert_le(actual: T, greatest_expected: T)

Assert that a value is less than or equal to a given upper bound.

Link copied to clipboard
(alias) function <T: -comparable> assert_lt(actual: T, greatest_expected: T)

Assert that a value is less than a given upper bound.

Link copied to clipboard
(alias) function <T> assert_not_equals(actual: T, illegal: T)

Assert two values are unequal.

Link copied to clipboard
(alias) function <T: -any> assert_not_null(actual: T?)

Assert a value is not null.

Link copied to clipboard
(alias) function assert_null(actual: anything)

Assert a value is null.

Link copied to clipboard
(alias) function assert_true(actual: boolean)

Assert a value is true.

Prefer other assertion functions where possible, as they provide better error messages.

Link copied to clipboard
function <T> empty(arg: T?): boolean

Checks if a value is absent, i.e. null or empty.

Equivalent to not exists(...).

Link copied to clipboard
(alias) function eth_ecrecover(r: byte_array, s: byte_array, rec_id: integer, data_hash: byte_array): byte_array

Compute an Ethererum public key from a signature and a hash.

Similar to Solidity's ecrecover(), though differs in that:

  • This function takes rec_id, rather than v, where rec_id == v - 27.

  • The parameter order is different.

  • This function returns a 64-byte public key, not a 20-byte address. An address can be obtained by taking the last 20 bytes of the keccak256() digest of the returned public key, e.g.:

 val address: byte_array = keccak256(eth_ecrecover(...)).sub(44);

The signature (consisting of the r, s and rec_id components) will typically be obtained with a procedure equivalent to eth_sign(data_hash, privkey), where privkey and pubkey form a keypair (pubkey being returned form this method).

The signature component rec_id is an adjusted recovery identifier, equivalent to Ethereum's recovery identifier (usually denoted as v) minus 27, i.e. rec_id == v - 27.

The given 32-byte array data_hash is typically a cryptographic hash obtained from a larger data structure using a hashing function such as hash(), sha256() or keccak256().

Example

The following is a Node.js script which uses ecrecover() (the equivalent to crypto.eth_ecrecover()) from the Ethereum Web3 library:

const Web3 = require('web3');
const web3 = new Web3();

var r = '0xcf722a47bcf1da61967ccc6405e31db4d37bce153255a6937e5cceb222caead0';
var s = '0xcf722a47bcf1da61967ccc6405e31db4d37bce153255a6937e5cceb222caead0';
var h = '0x53d7b11e61a8059aa4bc3248d24b2936436c9796dfe7f18e414c181004f79427';
var v = '0x1c';

var address = web3.eth.accounts.recover({'r':r,'s':s,'messageHash':h,'v':v});
console.log(address); // prints 0x5b0c087542D5C1E66Df0041e179c4201675B1614

An equivalent script in Rell is as follows:

val r = x'cf722a47bcf1da61967ccc6405e31db4d37bce153255a6937e5cceb222caead0';
val s = x'cf722a47bcf1da61967ccc6405e31db4d37bce153255a6937e5cceb222caead0';
val h = x'53d7b11e61a8059aa4bc3248d24b2936436c9796dfe7f18e414c181004f79427';
val v = 0x1c;

val pubkey = eth_ecrecover(r, s, v - 27, h);
val address = keccak256(pubkey).sub(12);
print(address); // prints 0x5b0c087542d5c1e66df0041e179c4201675b1614

Note that in the Rell script, v is an integer, while in the Node.js script it is an 0x-prefixed hexadecimal string.

Link copied to clipboard
function <T> exists(arg: T?): boolean

Checks if a value is present, i.e. not null and not empty.

The negation of empty().

Accepts arguments of nullable type (T?), checking that they are not null, and of collection type (collection<T>), checking that they contain at least one element. Where an argument is a nullable collection (collection<T>?), it is checked both for non-nullity and non-emptiness.

Examples:

  • val x: integer? = null; exists(x) returns false

  • val y: integer? = 1; exists(y) returns true

  • val l1: list<integer>? = null; exists(l1) returns false

  • val l2: list<integer>? = []; exists(l2) returns false

  • val l3: list<integer>? = [1]; exists(l3) returns true

Note that when exists() is used within a database at-expression, and its argument is also a database at-expression, the inner at-expression can refer to entities of the outer one, as long as the inner uses @* (as opposed to @, @+ or @?). Such expressions are efficient as they can be translated into a single nested SQL query.

Inner at-expressions can use @, @+ or @?, but in those cases, the inner expression cannot refer to entities of the outer one, and such cases are typically slow as they cannot be translated into a single nested query. They must instead be translated into multiple SQL queries, with the existence check occurring in the Rell runtime rather than in the database, where it could be done more efficiently. The translation into multiple queries also prevents the inner expression from referencing the outer expression, as this is only possible through a translation into SQL that leverages the scoping rules of nested SQL queries.

Examples:

  • user @* { exists( company @* { .city == user.city } ) } returns all users who share a city with a company.

  • user @* { exists( company @* { user.city } ) } is equivalent to the above, but uses the more concise attribute matching syntax.

Link copied to clipboard
function is_signer(pubkey: byte_array): boolean

Check if a given public key is a signer of the current transaction; i.e. if it's in the list of signers returned by op_context.get_signers().

Link copied to clipboard
(alias) function keccak256(input: byte_array): byte_array

Compute the Keccak256 digest (hash) of the given byte array.

Link copied to clipboard
function log(values: anything...)

Prints the given value(s) to the log, with a timestamp, and then terminates the line. When multiple values are provided, each is separated by a single space character.

Link copied to clipboard

Returns the greater of two big_integer values; i.e. a if a > b, or b otherwise.

function max(a: decimal, b: decimal): decimal

Returns the greater of two decimal values; i.e. a if a > b, or b otherwise.

function max(a: integer, b: integer): integer

Returns the greater of two integer values; i.e. a if a > b, or b otherwise.

Link copied to clipboard

Returns the lesser of two big_integer values; i.e. a if a < b, or b otherwise.

function min(a: decimal, b: decimal): decimal

Returns the lesser of two decimal values; i.e. a if a < b, or b otherwise.

function min(a: integer, b: integer): integer

Returns the lesser of two integer values; i.e. a if a < b, or b otherwise.

Link copied to clipboard
function print(values: anything...)

Prints the given value(s) to STDOUT, and then terminates the line. When multiple values are provided, each is separated by a single space character.

Link copied to clipboard
function <T: -any> require(value: T?, message: text): T

Asserts that a value is not null.

function require(value: boolean, message: text)

Asserts a boolean condition.

Link copied to clipboard
function <T: -any> require_not_empty(value: T?, message: text): T

Asserts that a value is non-null.

function <T> require_not_empty(value: list<T>?, message: text): list<T>

Asserts that a list is non-null and non-empty.

function <K: -immutable, V> require_not_empty(value: map<K, V>?, message: text): map<K, V>

Asserts that a map is non-null and non-empty.

function <T: -immutable> require_not_empty(value: set<T>?, message: text): set<T>

Asserts that a set is non-null and non-empty.

Link copied to clipboard
(alias) function <T: -any> requireNotEmpty(value: T?, message: text): T

Asserts that a value is non-null.

(alias) function <T> requireNotEmpty(value: list<T>?, message: text): list<T>

Asserts that a list is non-null and non-empty.

(alias) function <K: -immutable, V> requireNotEmpty(value: map<K, V>?, message: text): map<K, V>

Asserts that a map is non-null and non-empty.

(alias) function <T: -immutable> requireNotEmpty(value: set<T>?, message: text): set<T>

Asserts that a set is non-null and non-empty.

Link copied to clipboard
(alias) function sha256(input: byte_array): byte_array

Compute the SHA-256 digest (hash) of the given byte array.

Link copied to clipboard
function <T> try_call(fn: () -> T): T?

Safely call a function that may fail (i.e. that may throw an exception).

Accepts nullary function references, i.e. references to functions of type () -> T, and returns T?, i.e. the return value of the reference function, or null.

Exceptions thrown during the call are caught and logged with a stack trace.

Changes to the database that occur during the call are rolled back when an exception is thrown.

Examples:

function fails(): integer {
return list<integer>()[1]; // out of bounds
}
function succeeds(): unit { return 0; }
try_call(fails(*)) // logs an out of bounds exception message and returns null
try_call(succeeds(*)) // logs nothing, returns 0
function try_call(fn: () -> unit): boolean

Safely call a function that may fail (i.e. that may throw an exception).

Accepts nullary unit-typed function references, i.e. references to functions of type () -> unit.

Exceptions thrown during the call are caught and logged with a stack trace.

Changes to the database that occur during the call are rolled back when an exception is thrown.

Examples:

function fails(): unit {
list<integer>()[1]; // out of bounds
}
function succeeds(): unit {}
try_call(fails(*)) // logs an out of bounds exception message and returns false
try_call(succeeds(*)) // logs nothing, returns true
function <T> try_call(fn: () -> T, default: T): T

Safely call a function that may fail (i.e. that may throw an exception).

Accepts nullary function references, i.e. references to functions of type () -> T, and a default value to return if the call fails.

Exceptions thrown during the call are caught and logged with a stack trace.

Changes to the database that occur during the call are rolled back when an exception is thrown.

Examples:

function fails(): integer {
return list<integer>()[1]; // out of bounds
}
function succeeds(): unit { return 0; }
try_call(fails(*), 17) // logs an out of bounds exception message and returns 17
try_call(succeeds(*), 17) // logs nothing, returns 0
Link copied to clipboard
(alias) function verify_signature(data_hash: byte_array, pubkey: byte_array, signature: byte_array): boolean

Verify a signature against a message and public key.

More precisely, verify that signature was obtained with a procedure equivalent to get_signature(data_hash, privkey), where privkey and pubkey form a keypair.

Accepts valid public keys of size 33 or 65 bytes. Note that not all byte arrays of acceptable length constitute valid public keys.