My Unikname App - Why @unikname activation was broken?

@unikname activation was broken. Here’s why.

Middle of december 2020 :santa:, we released the @unikname activation feature (what is it)
But that feature was broken and some of you were blocked on the following screen :

We wanted to write you a post to explain, from a technical/developer point of view, the cause and how we fixed it.


:stopwatch: TLDR;

A wrong algorithm based on long-time cached data.
:point_right: UPDATE YOUR APP


:open_book: The story

As explained in the doc, to be able to activate your @unikname you have to meet 3 conditions.
The blocking (and broken) condition was the first one :

The @unikname must have been created at least 23 blocks ago

To understand the cause we must first describe how that condition is verified.

:scroll: I. The first algorithm

To know if a @unikname has been created at least 23 blocks ago we:

:one: Get the mint transaction of the @unikname

For that, we use the uniks/{id} endpoint of the public node api: https://api.uns.network/api/uniks/e0cfffdef2f776c7273f265e4b1c2b08d5e5daca6597a2d83519e960a68402da

Which answers with the following data:

{
  "data": {
    "id": "e0cfffdef2f776c7273f265e4b1c2b08d5e5daca6597a2d83519e960a68402da",
    "ownerId": "UN3pY1rn2M32HMT4AiosCoqaTGWrp8hEhU",
    "transactions": {
      "first": { "id": "c2cd7fccaa685b82526d32567ddde66288ea873ad7f73ea78fe4b09e5661764a" },
      "last": { "id": "619c0d2ce78e24058cf84c8801ea1420e53d971fa025787e6c00ebaa583e2a21" }
    },
    "type": "2",
    "explicitValues": ["Unikname-Forum"],
    "defaultExplicitValue": "Unikname-Forum"
    },
  }
}

What we want, the mint transaction id, is data.transactions.first.id

:two: Get confirmation numbers of the mint transaction

Transaction’s confirmation is the number of blocks forged above the block containing that transaction. It tells us how deep the transaction is in the uns.network blockchain history. The deeper it is, the harder it is to falsify or rollback the transaction.

We choose an arbitrary value of 24 blocks. It means that every @unikname owner must wait for at least 3mn before they are able to activate their @unikname. It slows down bots and reduces @unikname creation spamming interest.

To get that info (the number of confirmation), we use the transactions/{id} endpoint of the public node api:
https://api.uns.network/apitransactions/c2cd7fccaa685b82526d32567ddde66288ea873ad7f73ea78fe4b09e5661764a

Which answers with the following (partial) data:

{
  "data": {
    "id": "c2cd7fccaa685b82526d32567ddde66288ea873ad7f73ea78fe4b09e5661764a",
    "blockId": "d93394259e7e00b13533cd2540705d86e85b4e774f1ec01b8ba9069c9d6c95cb",
    "type": 3,
    "typeGroup": 2001,
    "asset": {...},
    "confirmations": 2781890,
    "timestamp": {
        "epoch": 97638360,
        "unix": 1587739560,
        "human": "2020-04-24T14:46:00.000Z"
    }
  }
}

From that, what we want, the number of confirmations, is data.confirmations

:three: Check the criteria is met

For that it was just :

mintTransaction.confirmations >= 24

:bug: II. The cache

After the development of the activation feature, we enhanced the app with new features like getting information about your @unikname (e.g creation date). To get that info, we also query the transactions/{id} endpoint and with the same id than for the check in activation feature (i.e the @unikname mint transaction).

Like any other apps, in order to reduce network traffic and increase reactivity, we chose to put some network responses in browser cache. And that’s the case of the transactions endpoint.

But… I think that you guess the point… UNS.network transactions resources aren’t immutable :sweat_smile:

That endpoint response contains both static and dynamic properties that we use - timestamp and confirmations. And behind “dynamic” there is “updated every 8 seconds”.

During new feature development (i.e show creation date), we choose to cache endpoint for a long time (7 days).

So, dynamic properties (here confirmations ) were unchanged until 7 days after the first query.

The first time we do that query is during the waiting phase of the @unikname creation process. We’re waiting for one confirmation before continuing and validating the process. It means that mint transaction is cached with 1 confirmation for 7 days.

That’s why if a user goes to the activation process before 7 days after @unikname creation, he/she is stuck on the activation check screen.

The only ways a user could avoid the bug are:

  • try activation after 7 days
  • clear website cache manually
  • use any other feature which sends a new transaction (@unikname creation, add properties, send UNS,…) because of a mechanism that invalidates the cache when posting new transactions.

:adhesive_bandage: III. The fix

Ok, we quickly identified the bug, but how did we fix it?

We changed the way we get mint transaction confirmations.

We still use the transactions/{id} endpoint, but instead of reading confirmations property, we read a static property: timestamp.

That property is written on-chain when a transaction is included in a block during its forging process. It means that it’ll never update in the future.

Finally, the response to “was the @unikname minted at least 24 blocks ago ?” is :

(mintTransaction.timestamp.unix + 8 * 24) * 1000 < Date.now()

with :

  • mintTransaction.timestamp.unix : mint transaction unix timestamp in seconds
  • 8*24 : duration of 24 blocks creation
  • *1000: to convert seconds in milliseconds
  • Date.now() : current unix timestamp in milliseconds (doc)

That’s all folks :wave:

The fix was released on 2021-01-20 in commit 3cf695b.

:point_right: UPDATE YOUR APP

Then make sure you have those values in Settings > About screen :

4 Likes

When it’s not DNS, it might be the caching layer! :face_with_hand_over_mouth:
Thank you for this detailed report :smile:

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.