Attributes

Attributes are a simple way of storing meta attributes specific to an entity without having to modify the entity itself or creating a fork of core and adding new attributes all over the codebase.

At the core of it all is is a collection of indexes that are associated with a key. Those keys will be things like block, wallet or transaction to signal that this index will hold meta attributes for a block or wallet based on their primary key.

An index is a collection of keys that have any possible value assigned to them, that key could be a wallet address or block ID, which then get the result of some expensive calculations stored as a meta attribute so that they can be retrieved faster later on when needed.

Architecture

The Attribute service is made up of 2 components that combined give you the ability to safely store attributes without setting unwanted properties and having to deal with resulting issues.

We will go from the highest entity to the lowest and break down what each of their responsibilities is and how they can be used to manage global and local attributes.

AttributeSet

The AttributeSet serves as the safe-guard for an AttributeMap. It holds a list of attribute names that are allowed to be set on an AttributeMap. It itself serves no other purpose than holding attribute names after which it will be used by an AttributeMap.

AttributeMap

The AttributeMap is at the heart of the attributes implementation. It is responsible for storing key-value pairs of attributes that are known to it and prevent setting unknown attributes. All attributes that it knows about come from an AttributeSet that is passed in on creation.

Prerequisites

Before we start, we need to establish what a few recurring variables and imports in this document refer to when they are used.

1import { app, Container, Services } from "@arkecosystem/core-kernel";
  • The app import refers to the application instance which grants access to the container, configurations, system information and more.
  • The Container import refers to a namespace that contains all of the container specific entities like binding symbols and interfaces.
  • The Services import refers to a namespace that contains all of the core services. This generally will only be needed for type hints as Core is responsible for service creation and maintenance.

Information

In this article we will refer to an index or indices when we talk about attribute maps.

AttributeSet

Creating an instance

1app.resolve(Services.Attributes.AttributeSet);

Get all known attributes

1attributeSet.all();

Set an attribute as known

1attributeSet.set("forgers");

Forget a known attribute

1attributeSet.forget("forgers");

Forget all known attributes

1attributeSet.flush("forgers");

Check if an attribute is known

1attributeSet.has("forgers");

AttributeMap

Creating an instance

1new Services.Attributes.AttributeMap(attributeSet);

Get the key-value pairs of all attributes

1attributeMap.all();

Get the value of an attribute

1attributeMap.get<string[]>("forgers", []);

Set the value of an attribute

1attributeMap.set<string[]>("forgers", []);

Forget the value of an attribute

1attributeMap.forget("forgers");

Check if an attribute exists

1attributeMap.has("forgers");

Things To Keep In Mind

When you are storing some data that isn’t tied to a specific entity, something like network statistics or summaries of some sorts you should bind an AttributeMap to the container with a unique identifier so that the whole application has access to that information.

When you are storing data that belongs to a specific entity you should create an AttributeMap that lives on that entity. Wallets for example have local AttributeMaps to avoid mixing up different states in the database, transaction pool and during round calculations.

Last updated 2 years ago
Edit Page
Share: