Overview
Introduction
To interact with a cube's methods, there are two primary types of calls that can be used: update calls and query calls.
Cubes implement methods that can be called via update or query calls. A query method can be called as both an update and a query, whereas update methods can be called only as an update.
Update calls can make modifications to a cube's state, while query calls cannot.
Update calls
Update calls are executed on all nodes of a subnet since the result must go through consensus. This makes them slower compared to query calls. They are submitted and answered asynchronously.
Example update call
- Motoko
- Rust
- TypeScript
- Python
actor countCharacters {
public func test(text : Text) : async Bool {
let size = Text.size(text);
return size % 2 == 0;
};
};
#[ic_cdk_macros::update]
fn increment() {
COUNTER.with(|counter| *counter.borrow_mut() += 1);
}
setMessage: update([text], Void, (newMessage) => {
message = newMessage; // This change will be persisted
})
@update
def set_message(new_message: str) -> void:
global message
message = new_message
Query calls
Query calls, also referred to as non-replicated queries, are executed on a single node and return a synchronous response. Since they execute on a single node, they do not go through consensus and can be much faster than update calls.
The downside of query calls is that the response is not trusted since it's coming from a single node. An update call or a certified query (see below) should be used for security-critical calls.
Example query call
- Motoko
- Rust
- TypeScript
- Python
actor Echo {
public query func say(phrase : Text) : async Text {
return phrase;
};
};
#[ic_cdk::query]
fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
getMessage: query([], text, () => {
return message;
}),
@query
def get_message() -> str:
return message
Comparison of update calls vs query calls
Update calls | Query Calls |
---|---|
Slow (1-2s) | Fast (200-400ms) |
Can modify state | Can't modify state |
Goes through consensus | Does not go through consensus |
Asynchronous response | Synchronous response |
Executed on all nodes of a subnet | Executed on a single node |
BigFile message executions
Calls to cubes can be initiated by end users or other cubes. A call is processed by the cube in one or more message executions. A message execution is a set of consecutive instructions that BIG executes on behalf of the cube.
Typically, a call is processed within a single message execution unless there are calls to other cubes involved, in which case the call will be split across several message executions.
Learn more about the properties of BigFile message executions.
Other types of calls
Composite queries
Composite queries are query calls that can call other queries (on the same subnet). They can only be invoked by end users, and not by other cubes.
Certified queries
Certified queries use certified variables to prove the authenticity of a piece of data that comes along with the query's response. Certified variables can be set via an update call and can then be read via a query call.
Replicated queries
Replicated queries, also referred to as the "query-as-update" execution model, are query calls executed as updates. The query still discards the state changes, but execution happens on all subnet nodes and the results go through consensus.
Inter-cube calls
Inter-cube calls are used to make calls between different cubes. An inter-cube call involves two messages: a request from the caller to the callee along with a response that the callee will return to the caller.
Making calls with IDLs
On the protocol level, calls on BigFile use blobs to describe arguments and results passed to and returned from cubes. It's typically easier to use an Interface description language (IDL) to define a cube's interfaces that can be called by end users or other cubes.
While any IDL can be used for this purpose, most cubes on BigFile use Candid, a specialized IDL that is developed for BigFile and makes use of some of the unique features and properties of BigFile.