Trie API
Here we provide a specification of trie API. After this NEP is merged, the cases where our current implementation does not follow the specification are considered to be bugs that need to be fixed.
storage_write
#![allow(unused)] fn main() { storage_write(key_len: u64, key_ptr: u64, value_len: u64, value_ptr: u64, register_id: u64) -> u64 }
Writes key-value into storage.
Normal operation
- If key is not in use it inserts the key-value pair and does not modify the register;
- If key is in use it inserts the key-value and copies the old value into the
register_id.
Returns
- If key was not used returns
0; - If key was used returns
1.
Panics
- If
key_len + key_ptrorvalue_len + value_ptrexceeds the memory container or points to an unused register it panics withMemoryAccessViolation. (When we say that something panics with the given error we mean that we use Wasmer API to create this error and terminate the execution of VM. For mocks of the host that would only cause a non-name panic.) - If returning the preempted value into the registers exceed the memory container it panics with
MemoryAccessViolation;
Current bugs
External::storage_settrait can return an error which is then converted to a generic non-descriptiveStorageUpdateError, here however the actual implementation does not return error at all, see;- Does not return into the registers.
storage_read
#![allow(unused)] fn main() { storage_read(key_len: u64, key_ptr: u64, register_id: u64) -> u64 }
Reads the value stored under the given key.
Normal operation
- If key is used copies the content of the value into the
register_id, even if the content is zero bytes; - If key is not present then does not modify the register.
Returns
- If key was not present returns
0; - If key was present returns
1.
Panics
- If
key_len + key_ptrexceeds the memory container or points to an unused register it panics withMemoryAccessViolation; - If returning the preempted value into the registers exceed the memory container it panics with
MemoryAccessViolation;
Current bugs
- This function currently does not exist.
storage_remove
#![allow(unused)] fn main() { storage_remove(key_len: u64, key_ptr: u64, register_id: u64) -> u64 }
Removes the value stored under the given key.
Normal operation
Very similar to storage_read:
- If key is used, removes the key-value from the trie and copies the content of the value into the
register_id, even if the content is zero bytes. - If key is not present then does not modify the register.
Returns
- If key was not present returns
0; - If key was present returns
1.
Panics
- If
key_len + key_ptrexceeds the memory container or points to an unused register it panics withMemoryAccessViolation; - If the registers exceed the memory limit panics with
MemoryAccessViolation; - If returning the preempted value into the registers exceed the memory container it panics with
MemoryAccessViolation;
Current bugs
- Does not return into the registers.
storage_has_key
#![allow(unused)] fn main() { storage_has_key(key_len: u64, key_ptr: u64) -> u64 }
Checks if there is a key-value pair.
Normal operation
- If key is used returns
1, even if the value is zero bytes; - Otherwise returns
0.
Panics
- If
key_len + key_ptrexceeds the memory container it panics withMemoryAccessViolation;
storage_iter_prefix
#![allow(unused)] fn main() { storage_iter_prefix(prefix_len: u64, prefix_ptr: u64) -> u64 }
DEPRECATED, calling it will result in HostError::Deprecated error.
Creates an iterator object inside the host.
Returns the identifier that uniquely differentiates the given iterator from other iterators that can be simultaneously
created.
Normal operation
- It iterates over the keys that have the provided prefix. The order of iteration is defined by the lexicographic order of the bytes in the keys. If there are no keys, it creates an empty iterator, see below on empty iterators;
Panics
- If
prefix_len + prefix_ptrexceeds the memory container it panics withMemoryAccessViolation;
storage_iter_range
#![allow(unused)] fn main() { storage_iter_range(start_len: u64, start_ptr: u64, end_len: u64, end_ptr: u64) -> u64 }
DEPRECATED, calling it will result in HostError::Deprecated error.
Similarly to storage_iter_prefix
creates an iterator object inside the host.
Normal operation
Unless lexicographically start < end, it creates an empty iterator.
Iterates over all key-values such that keys are between start and end, where start is inclusive and end is exclusive.
Note, this definition allows for start or end keys to not actually exist on the given trie.
Panics
- If
start_len + start_ptrorend_len + end_ptrexceeds the memory container or points to an unused register it panics withMemoryAccessViolation;
storage_iter_next
#![allow(unused)] fn main() { storage_iter_next(iterator_id: u64, key_register_id: u64, value_register_id: u64) -> u64 }
DEPRECATED, calling it will result in HostError::Deprecated error.
Advances iterator and saves the next key and value in the register.
Normal operation
- If iterator is not empty (after calling next it points to a key-value), copies the key into
key_register_idand value intovalue_register_idand returns1; - If iterator is empty returns
0.
This allows us to iterate over the keys that have zero bytes stored in values.
Panics
- If
key_register_id == value_register_idpanics withMemoryAccessViolation; - If the registers exceed the memory limit panics with
MemoryAccessViolation; - If
iterator_iddoes not correspond to an existing iterator panics withInvalidIteratorId - If between the creation of the iterator and calling
storage_iter_nextany modification to storage was done throughstorage_writeorstorage_removethe iterator is invalidated and the error message isIteratorWasInvalidated.
Current bugs
- Not implemented, currently we have
storage_iter_nextanddata_read+DATA_TYPE_STORAGE_ITERthat together fulfill the purpose, but have unspecified behavior.