C++ Native Functions
Native functions give services the ability to print debugging messages, abort transactions on errors, access databases and event logs, and synchronously call other services. There aren't many native functions since services implement most psibase functionality.
Types For Native Functions
psibase::Action
struct psibase::Action {
AccountNumber sender; // Account sending the action
AccountNumber service; // Service to execute the action
MethodNumber method; // Service method to execute
std::vector<char> rawData; // Data for the method
};
A synchronous call.
An Action represents a synchronous call between services. It is the argument to call and can be fetched using getCurrentAction.
Transactions also contains actions requested by the transaction authorizers.
psibase::DbId
enum psibase::DbId: uint32_t {
service = 0, // Services should store their tables here
writeOnly = 1, // Data for RPC
subjective = 2, // The first 64 bits of the key match the service.
nativeConstrained = 3, // Tables used by native code
nativeUnconstrained = 4, // Tables used by native code
blockLog = 5, // Block log
historyEvent = 6, // Long-term history event storage
uiEvent = 7, // Short-term history event storage
merkleEvent = 8, // Events which go into the merkle tree
blockProof = 9, // block signatures
numDatabases = 10, // Number of defined databases
};
Identify database to operate on.
Native functions expose a set of databases which serve various purposes. This enum identifies which database to use when invoking those functions.
psibase::DbId::service
Services should store their tables here.
The first 64 bits of the key match the service.
psibase::DbId::writeOnly
Data for RPC.
Write-only during transactions, and read-only during RPC. Individual nodes may modify this database, expire data from this database, or wipe it entirely at will.
The first 64 bits of the key match the service.
psibase::DbId::subjective
The first 64 bits of the key match the service..
psibase::DbId::nativeConstrained
Tables used by native code.
This database enforces constraints during write. Only writable by privileged services, but readable by all services.
Some writes to this database indicate chain upgrades. If a privileged service writes to a table that an older node version doesn't know about, or writes new fields to an existing table that an older node doesn't know about, then that node will reject the write. If the producers accepted the write into a block, then the node will stop following the chain until it's upgraded to a newer version.
psibase::DbId::nativeUnconstrained
Tables used by native code.
This database doesn't enforce constraints during write. Only writable by privileged services, but readable by all services.
psibase::DbId::blockLog
Block log.
Transactions don't have access to this, but RPC does.
psibase::DbId::historyEvent
Long-term history event storage.
Write-only during transactions, and read-only during RPC. Individual nodes may modify this database, expire data from this database, or wipe it entirely at will.
TODO: this policy may eventually change to allow time-limited read access during transactions.
Key is an auto-incremented, 64-bit unsigned number.
Value must begin with:
- 32 bit: block number
- 64 bit: service
Only usable with these native functions:
TODO: right now the value must begin with the service. Revisit whether beginning with the block number is useful.
psibase::DbId::uiEvent
Short-term history event storage.
These events are erased once the block that produced them becomes final. They notify user interfaces which subscribe to activity.
Write-only during transactions, and read-only during RPC. Individual nodes may modify this database, expire data from this database, or wipe it entirely at will.
Key is an auto-incremented, 64-bit unsigned number.
Value must begin with:
- 32 bit: block number
- 64 bit: service
Only usable with these native functions:
TODO: right now the value must begin with the service. Revisit whether beginning with the block number is useful. TODO: consider removing UI events
psibase::DbId::merkleEvent
Events which go into the merkle tree.
TODO: read support; right now only RPC mode can read
Services may produce these events during transactions and may read them up to 1 hour (configurable) after they were produced, or they reach finality, which ever is longer.
Key is an auto-incremented, 64-bit unsigned number.
Value must begin with:
- 32 bit: block number
- 64 bit: service
Only usable with these native functions:
TODO: right now the value must begin with the service. Revisit whether beginning with the block number is useful.
psibase::DbId::blockProof
block signatures.
psibase::DbId::numDatabases
Number of defined databases.
This number may grow in the future
Wrapped Native Functions
These functions wrap the Raw Native Functions.
- psibase::abortMessage
- psibase::call
- psibase::check
- psibase::getCurrentAction
- psibase::getCurrentActionView
- psibase::getKey
- psibase::getResult
- psibase::getSequential
- psibase::getSequentialRaw
- psibase::kvGet
- psibase::kvGetOrDefault
- psibase::kvGetRaw
- psibase::kvGetSize
- psibase::kvGetSizeRaw
- psibase::kvGreaterEqual
- psibase::kvGreaterEqualRaw
- psibase::kvLessThan
- psibase::kvLessThanRaw
- psibase::kvMax
- psibase::kvMaxRaw
- psibase::kvPut
- psibase::kvPutRaw
- psibase::kvRemove
- psibase::kvRemoveRaw
- psibase::putSequential
- psibase::putSequentialRaw
- psibase::setRetval
- psibase::setRetvalBytes
- psibase::writeConsole
psibase::abortMessage
void psibase::abortMessage(
std::string_view message
);
Abort with message
.
Message should be UTF8.
psibase::call
std::vector<char> psibase::call(
const Action & action
);
Call a service and return its result.
psibase::call
std::vector<char> psibase::call(
const char * action,
uint32_t len
);
Call a service and return its result.
action
must contain a fracpacked Action.
psibase::call
std::vector<char> psibase::call(
psio::input_stream action
);
Call a service and return its result.
action
must contain a fracpacked Action.
psibase::check
void psibase::check(
bool cond,
std::string_view message
);
Abort with message if !cond
.
Message should be UTF8.
psibase::getCurrentAction
Action psibase::getCurrentAction();
Get the currently-executing action.
This function unpacks the data into the Action struct. For large data, getCurrentActionView can be more efficient.
If the service, while handling action A, calls itself with action B:
- Before the call to B,
getCurrentAction()
returns A. - After the call to B,
getCurrentAction()
returns B. - After B returns,
getCurrentAction()
returns A.
Note: The above only applies if the service uses call. Actor uses call.
psibase::getCurrentActionView
psio::shared_view_ptr<Action> psibase::getCurrentActionView();
Get the currently-executing action.
This function creates a view, which can save time for large data. For small data, getCurrentAction can be more efficient.
If the service, while handling action A, calls itself with action B:
- Before the call to B,
getCurrentAction()
returns A. - After the call to B,
getCurrentAction()
returns B. - After B returns,
getCurrentAction()
returns A.
Note: The above only applies if the service uses call. Actor uses call.
psibase::getKey
std::vector<char> psibase::getKey();
Get key.
Other functions set the key.
psibase::getResult
std::vector<char> psibase::getResult();
Get result.
Other functions set result.
psibase::getResult
std::vector<char> psibase::getResult(
uint32_t size
);
Get result when size is known.
Other functions set result.
Caution: this does not verify size.
psibase::getSequential
template<typename V, typename Type>
std::optional<V> psibase::getSequential(
DbId db,
uint64_t id,
const AccountNumber * matchService = nullptr,
const Type * matchType = nullptr,
AccountNumber * service = nullptr,
Type * type = nullptr
);
Get a sequentially-numbered record, if available.
- If
matchService
is non-null, and the record wasn't written bymatchService
, then return nullopt. This prevents a spurious abort from mismatched serialization. - If
matchType
is non-null, and the record type doesn't match, then return nullopt. This prevents a spurious abort from mismatched serialization. - If
service
is non-null, then it receives the service that wrote the record. It is left untouched if the record is not available. - If
type
is non-null, then it receives the record type. It is left untouched if either the record is not available or ifmatchService
is not null but doesn't match.
psibase::getSequentialRaw
std::optional<std::vector<char>> psibase::getSequentialRaw(
DbId db,
uint64_t id
);
Get a sequentially-numbered record, if available.
psibase::kvGet
template<typename V, typename K>
std::optional<V> psibase::kvGet(
DbId db,
const K & key
);
Get a key-value pair, if any.
psibase::kvGet
template<typename V, typename K>
std::optional<V> psibase::kvGet(
const K & key
);
Get a key-value pair, if any.
psibase::kvGetOrDefault
template<typename V, typename K>
V psibase::kvGetOrDefault(
DbId db,
const K & key
);
Get a value, or the default if not found.
psibase::kvGetOrDefault
template<typename V, typename K>
V psibase::kvGetOrDefault(
const K & key
);
Get a value, or the default if not found.
psibase::kvGetRaw
std::optional<std::vector<char>> psibase::kvGetRaw(
DbId db,
psio::input_stream key
);
Get a key-value pair, if any.
psibase::kvGetSize
template<typename K>
std::optional<uint32_t> psibase::kvGetSize(
DbId db,
const K & key
);
Get size of stored value, if any.
psibase::kvGetSize
template<typename K>
std::optional<uint32_t> psibase::kvGetSize(
const K & key
);
Get size of stored value, if any.
psibase::kvGetSizeRaw
std::optional<uint32_t> psibase::kvGetSizeRaw(
DbId db,
psio::input_stream key
);
Get size of stored value, if any.
psibase::kvGreaterEqual
template<typename V, typename K>
std::optional<V> psibase::kvGreaterEqual(
DbId db,
const K & key,
uint32_t matchKeySize
);
Get the first key-value pair which is greater than or equal to key
.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then returns the value. Use getKey to
get the found key.
psibase::kvGreaterEqual
template<typename V, typename K>
std::optional<V> psibase::kvGreaterEqual(
const K & key,
uint32_t matchKeySize
);
Get the first key-value pair which is greater than or equal to key
.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then returns the value. Use getKey to
get the found key.
psibase::kvGreaterEqualRaw
std::optional<std::vector<char>> psibase::kvGreaterEqualRaw(
DbId db,
psio::input_stream key,
uint32_t matchKeySize
);
Get the first key-value pair which is greater than or equal to key
.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then returns the value. Use getKey to
get the found key.
psibase::kvLessThan
template<typename V, typename K>
std::optional<V> psibase::kvLessThan(
DbId db,
const K & key,
uint32_t matchKeySize
);
Get the key-value pair immediately-before provided key.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then returns the value. Use getKey to
get the found key.
psibase::kvLessThan
template<typename V, typename K>
std::optional<V> psibase::kvLessThan(
const K & key,
uint32_t matchKeySize
);
Get the key-value pair immediately-before provided key.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then returns the value. Use getKey to
get the found key.
psibase::kvLessThanRaw
std::optional<std::vector<char>> psibase::kvLessThanRaw(
DbId db,
psio::input_stream key,
uint32_t matchKeySize
);
Get the key-value pair immediately-before provided key.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then returns the value. Use getKey to
get the found key.
psibase::kvMax
template<typename V, typename K>
std::optional<V> psibase::kvMax(
DbId db,
const K & key
);
Get the maximum key-value pair which has key as a prefix.
If one is found, then returns the value. Use getKey to get the found key.
psibase::kvMax
template<typename V, typename K>
std::optional<V> psibase::kvMax(
const K & key
);
Get the maximum key-value pair which has key as a prefix.
If one is found, then returns the value. Use getKey to get the found key.
psibase::kvMaxRaw
std::optional<std::vector<char>> psibase::kvMaxRaw(
DbId db,
psio::input_stream key
);
Get the maximum key-value pair which has key as a prefix.
If one is found, then returns the value. Use getKey to get the found key.
psibase::kvPut
template<typename K, NotOptional V>
void psibase::kvPut(
DbId db,
const K & key,
const V & value
);
Set a key-value pair.
If key already exists, then replace the existing value.
psibase::kvPut
template<typename K, NotOptional V>
void psibase::kvPut(
const K & key,
const V & value
);
Set a key-value pair.
If key already exists, then replace the existing value.
psibase::kvPutRaw
void psibase::kvPutRaw(
DbId db,
psio::input_stream key,
psio::input_stream value
);
Set a key-value pair.
If key already exists, then replace the existing value.
psibase::kvRemove
template<typename K>
void psibase::kvRemove(
DbId db,
const K & key
);
Remove a key-value pair if it exists.
psibase::kvRemove
template<typename K>
void psibase::kvRemove(
const K & key
);
Remove a key-value pair if it exists.
psibase::kvRemoveRaw
void psibase::kvRemoveRaw(
DbId db,
psio::input_stream key
);
Remove a key-value pair if it exists.
psibase::putSequential
template<typename Type, NotOptional V>
uint64_t psibase::putSequential(
DbId db,
AccountNumber service,
Type type,
const V & value
);
Add a sequentially-numbered record.
Returns the id.
psibase::putSequentialRaw
uint64_t psibase::putSequentialRaw(
DbId db,
psio::input_stream value
);
Add a sequentially-numbered record.
Returns the id.
psibase::setRetval
template<typename T>
void psibase::setRetval(
const T & retval
);
Set the return value of the currently-executing action.
psibase::setRetvalBytes
void psibase::setRetvalBytes(
psio::input_stream s
);
Set the return value of the currently-executing action.
psibase::writeConsole
void psibase::writeConsole(
const std::string_view & sv
);
Write message
to console.
Message should be UTF8.
Raw Native Functions
This is the set of raw native functions (wasm imports). They are available for services to use directly, but we recommend using the Wrapped Native Functions instead.
- psibase::raw::abortMessage
- psibase::raw::call
- psibase::raw::clockTimeGet
- psibase::raw::getCurrentAction
- psibase::raw::getKey
- psibase::raw::getResult
- psibase::raw::getSequential
- psibase::raw::kvGet
- psibase::raw::kvGreaterEqual
- psibase::raw::kvLessThan
- psibase::raw::kvMax
- psibase::raw::kvPut
- psibase::raw::kvRemove
- psibase::raw::putSequential
- psibase::raw::setRetval
- psibase::raw::writeConsole
psibase::raw::abortMessage
void psibase::raw::abortMessage(
const char * message,
std::uint32_t len
);
Abort with message
.
Message should be UTF8.
psibase::raw::call
uint32_t psibase::raw::call(
const char * action,
uint32_t len
);
Call a service, store the return value into result, and return the result size.
action
must contain a fracpacked Action.
Use getResult to get result.
psibase::raw::clockTimeGet
int32_t psibase::raw::clockTimeGet(
uint32_t id,
uint64_t * time
);
Gets the current value of a clock in nanoseconds..
This function is non-deterministic and is only available in subjective services.
The following clocks are supported
__WASI_CLOCKID_REALTIME
returns wall-clock time since the unix epoch.__WASI_CLOCKID_MONOTONIC
returns monotonic time since an unspecified epoch. All uses of CLOCK_MONOTONIC within the same block use the same epoch.__WASI_CLOCKID_PROCESS_CPUTIME_ID
measures CPU time spent executing the current transaction.
Returns 0 on success or an error code on failure.
Errors:
EINVAL
: the clock id is not supported
psibase::raw::getCurrentAction
uint32_t psibase::raw::getCurrentAction();
Store the currently-executing action into result and return the result size.
The result contains a fracpacked Action; use getResult to get it.
If the service, while handling action A, calls itself with action B:
- Before the call to B,
getCurrentAction()
returns A. - After the call to B,
getCurrentAction()
returns B. - After B returns,
getCurrentAction()
returns A.
Note: The above only applies if the service uses call. Actor uses call.
psibase::raw::getKey
uint32_t psibase::raw::getKey(
const char * dest,
uint32_t destSize
);
Copy min(destSize, key_size)
bytes of the most-recent key into
dest and return key_size
.
Other functions set or clear the key. getResult, getKey
, and
writeConsole are the only raw functions which leave the current
result and key intact.
psibase::raw::getResult
uint32_t psibase::raw::getResult(
const char * dest,
uint32_t destSize,
uint32_t offset
);
Copy min(destSize, resultSize - offset)
bytes from
result + offset
into dest
and return resultSize
.
If offset >= resultSize
, then skip the copy.
Other functions set or clear result. getResult
, getKey, and
writeConsole are the only raw functions which leave the current
result and key intact.
psibase::raw::getSequential
uint32_t psibase::raw::getSequential(
DbId db,
uint64_t id
);
Get a sequentially-numbered record.
If id
is available, then sets result to value and returns size. If id does
not exist, returns -1 and clears result.
psibase::raw::kvGet
uint32_t psibase::raw::kvGet(
DbId db,
const char * key,
uint32_t keyLen
);
Get a key-value pair, if any.
If key exists, then sets result to value and returns size. If key does not
exist, returns -1
and clears result. Use getResult to get result.
psibase::raw::kvGreaterEqual
uint32_t psibase::raw::kvGreaterEqual(
DbId db,
const char * key,
uint32_t keyLen,
uint32_t matchKeySize
);
Get the first key-value pair which is greater than or equal to the provided key.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then sets result to value and returns size. Also
sets key. Otherwise returns -1
and clears result. Use getResult to get
result and getKey to get found key.
psibase::raw::kvLessThan
uint32_t psibase::raw::kvLessThan(
DbId db,
const char * key,
uint32_t keyLen,
uint32_t matchKeySize
);
Get the key-value pair immediately-before provided key.
If one is found, and the first matchKeySize
bytes of the found key
matches the provided key, then sets result to value and returns size.
Also sets key. Otherwise returns -1
and clears result. Use getResult
to get result and getKey to get found key.
psibase::raw::kvMax
uint32_t psibase::raw::kvMax(
DbId db,
const char * key,
uint32_t keyLen
);
Get the maximum key-value pair which has key as a prefix.
If one is found, then sets result to value and returns size. Also sets key.
Otherwise returns -1
and clears result. Use getResult to get result
and getKey to get found key.
psibase::raw::kvPut
void psibase::raw::kvPut(
DbId db,
const char * key,
uint32_t keyLen,
const char * value,
uint32_t valueLen
);
Set a key-value pair.
If key already exists, then replace the existing value.
psibase::raw::kvRemove
void psibase::raw::kvRemove(
DbId db,
const char * key,
uint32_t keyLen
);
Remove a key-value pair if it exists.
psibase::raw::putSequential
uint64_t psibase::raw::putSequential(
DbId db,
const char * value,
uint32_t valueLen
);
Add a sequentially-numbered record.
Returns the id.
psibase::raw::setRetval
void psibase::raw::setRetval(
const char * retval,
uint32_t len
);
Set the return value of the currently-executing action.
psibase::raw::writeConsole
void psibase::raw::writeConsole(
const char * message,
uint32_t len
);
Write message
to console.
Message should be UTF8.