Handling events

Responding to the library's events.

Event handling

Events will be passed to the user using the callback passed to init the Vertices library, from vertex_t:

typedef struct
    provider_info_t *provider;
    (*vertices_evt_handler)(vtc_evt_t *evt);
} vertex_t;

You can see here that the handler vertices_evt_handler takes a pointer to vtc_evt_t:

/// Events contains a type and a bufid. When implementing the event handler, the `bufid`
/// should be used to retrieve the data to be processed. Data type depends on event type.
typedef struct
    vtc_evt_type_t type; ///< \see vtc_evt_type_t
    size_t bufid; ///< internal buffer ID, used to identify a pending transaction
} vtc_evt_t;

Two things are passed to the user: the event type and a bufid which is an identifier to the internal transaction being processed. In order to get the event's transaction, the user must use the function available:

vertices_event_tx_get(size_t bufid, signed_transaction_t **tx);

This function will set a local pointer to the signed_transaction_t generating the event.

Here are the different events needing the user attention:

/// Asynchronous operations can be handled using Vertices events types
typedef enum
    VTC_EVT_TX_READY_TO_SIGN = 0, ///< transaction's payload must be signed: the user must provide the signing function
    VTC_EVT_TX_SENDING, ///< transaction is being sent to the blockchain API. When the user got the event, the transaction has probably been already sent.
    VTC_EVT_TX_SUCCESS, ///< transaction has been successfully sent and executed, after that event, the buffer is freed.
} vtc_evt_type_t;

Let's go through the handling of those events.



This is the most critical event to handle: signing the payload. The payload is divided into two parts: the header and the body. Only the body part has to be signed, but with a subtility: we need to add the "TX" string before the body.

The first step is to get a pointer to the payload using vertices_event_tx_get:

typedef struct
    unsigned char payload[TX_PAYLOAD_MAX_LENGTH]; ///< Full payload, comprised of the header + body. The body part is the signed part (prepended with "TX")
        payload_header_length;  ///< Header size. Do not use for signing. Full \c payload size is: \c payload_header_length + \c payload_body_length
        payload_body_length;  ///< Body size. Length of data to be signed. if not 0, indicates that TX is pending.
    unsigned char signature[SIGNATURE_LENGTH];
    ]; ///< Unique Identifier of the transaction. It can be used to find the transaction in the ledger
} signed_transaction_t;

We now have the payload with payload_header_length and payload_body_length. In order to have the byte array to sign, we need to init a new byte array starting with "TX" and then copy the full body into that byte array.

Now that we have a buffer ready to be signed, sign it using the Ed25519 algorithm. A private key will be necessary. Put the generated signature into the signed_transaction_t, signature field.

Once done and to send the transaction, we need to emit the event VTC_EVT_TX_SENDING using:

evt->type = VTC_EVT_TX_SENDING;
err_code = vertices_event_schedule(evt);



The transaction is being sent. When the user gets that event in the event handler, the event has already been processed by the library, meaning the transaction has been sent.

We can use that event to have the full payload of the packed transaction (message pack).

Transaction success


Nice! The transaction has passed. I guess you can print a hoora message.

Event processing

Last but not least, for the Vertices SDK to process the event, we need to give the library some CPU time by calling as many times as needed the event processing routine:

/// Call this function to have the Vertices SDK process pending events. Whenever calling a Vertices
/// function, make sure to process all the events.
/// To make sure all the events are processed, this function should be called from an infinite loop or OS thread/task.
/// This function will call the user-defined callback passed when using \see vertices_new
/// \param queue_size
/// \return \c VTC_SUCCESS if event has correctly been processed
vertices_event_process(size_t *queue_size);

queue_size can give the user an indication about the queued events waiting to be processed but it is not mandatory.

Depending on whether you are using an RTOS or not, you might want to call this function from an indefinite loop.

Here is the link to our implementation of the given step.

You can use the repository as a template to get you started. 🚀

If you have more questions, don't hesitate to open an issue on the Github repository.

Last updated