While implementing my chain logic I was wondering whether to use events at all since they might cost the node extra storage for the event logs. What is the actual storage cost involved here? Do the logs get purged automatically at some point?
Runtime events are handled by the System module. Within your own module, you normally implement the default deposit_event
function:
From the in-code documentation:
deposit_event
: Helper function for depositing an event. The default behavior is to calldeposit_event
from the System module. However, you can write your own implementation for events in your runtime. To use the default behavior, addfn deposit_event<T>() = default;
to yourModule
.
If you look at the System module code, you will find that ultimately a helper function is called which stores the event:
/// Deposits an event into this block's event record adding this event
/// to the corresponding topic indexes.
///
/// This will update storage entries that correspond to the specified topics.
/// It is expected that light-clients could subscribe to this topics.
pub fn deposit_event_indexed(topics: &[T::Hash], event: T::Event) { ... }
This function modifies three storage items which you can find in the decl_storage
for the System module:
/// Events deposited for the current block.
Events get(events): Vec<EventRecord<T::Event, T::Hash>>;
/// The number of events in the `Events<T>` list.
EventCount get(event_count): EventIndex;
/// Mapping between a topic (represented by T::Hash) and a vector of indexes
/// of events in the `<Events<T>>` list.
EventTopics get(event_topics): double_map hasher(blake2_256) (), blake2_256(T::Hash)
=> Vec<(T::BlockNumber, EventIndex)>;
The final part of the event story can be found in the initialize
function in the System module, where all three of these items are "cleaned up":
pub fn initialize( ... ) {
...
<Events<T>>::kill();
EventCount::kill();
<EventTopics<T>>::remove_prefix(&());
}
This initialize
function is called in the Executive module at the beginning of every block, before on_initialize
is called for any module:
fn initialize_block_impl(
block_number: &System::BlockNumber,
parent_hash: &System::Hash,
extrinsics_root: &System::Hash,
digest: &Digest<System::Hash>,
) {
<system::Module<System>>::initialize(block_number, parent_hash, extrinsics_root, digest);
<AllModules as OnInitialize<System::BlockNumber>>::on_initialize(*block_number);
}
In conclusion, the cost of adding a single Event in the runtime is:
- Running the
deposit_event_indexed
function. - Adding a new item to two vectors in runtime storage.
- ... which are cleaned up at the beginning of the next block so the storage cost is not compounding.
Events are created the same as any other storage item and consume the same amount of storage, based on the type of the inner data being emitted.
© 2022 - 2024 — McMap. All rights reserved.
[substrate]
tag). You just need to remove other tags. – Borodino