Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: optimize middleware querying #126

Merged
merged 12 commits into from
May 8, 2023

Conversation

lukeromanowicz
Copy link
Contributor

@lukeromanowicz lukeromanowicz commented Apr 17, 2023

Description

Resolves #12

Instead of querying all blockchain stats from REST API every time a new transaction message arrives from websocket, it calculates most of the statistics dynamically based on websocket data and syncs back with REST API only upon minting a new keyblock to correct possible misalignment caused by microforks. This implementation is utilizing message buffer because transactions and macroblock messages tend to arrive before the keyblock message. If there will be a hiccup in data transfer, the message buffer will reset itself after hitting 30 messages and resync everything through the REST API.

Breaking change: using middleware websocket v2 instead of v1. Change NUXT_PUBLIC_WEBSOCKET_URL value from wss://mainnet.aeternity.io/mdw/websocket to wss://mainnet.aeternity.io/mdw/v2/websocket.

Demo

The online demo might not work due to a change in the WebSocket environmental variable to use v2 websocket instead of v1

2023-04-18.10-52-19.mp4

Checklist:

  • I have read and followed the Contributing Guide
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly. (.env.example file)

@github-actions
Copy link

Deployed to https://pr-126-aescan.stg.aepps.com

@lukeromanowicz lukeromanowicz marked this pull request as ready for review April 18, 2023 09:34
Copy link
Collaborator

@janmichek janmichek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, seems like a lot of work 🥇 the change looks promising.
Could you also provide some measurements before and after change? How was the optimization successful?

src/stores/recentBlocks.js Show resolved Hide resolved
src/stores/recentBlocks.js Outdated Show resolved Hide resolved
src/stores/recentBlocks.js Outdated Show resolved Hide resolved
}

function processKeyblockUpdate(keyblock) {
if (keyblocks.value?.[0].hash !== keyblock.prev_key_hash) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would better read it in some human readable form of what's going on in here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, I think this function should be more readable or at least have some comments. It's hard to understand what's going on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just like in other process* functions, updating stuff fully, partially, or skipping the update entirely depends on multiple variables that represent given scenario. I'm struggling to split it into smaller chunks without going into advanced programming patterns we haven't used in the project and producing a few times more code around it.

I added the comments where the code isn't very obvious. Please, let me know if it helps or I missed some spots.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I am not satisfied with the outcome. The function is long and has many comments and it's hard to read for me

src/stores/recentBlocks.js Show resolved Hide resolved
Copy link
Collaborator

@michele-franchi michele-franchi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hard work, this will optimise the app a lot.
Please have a look at my comments, some things are not clear to me and in general I understand the issues about handling websocket data so I would suggest to add some comments to some parts which could be hard to understand.

src/stores/recentBlocks.js Outdated Show resolved Hide resolved
src/stores/recentBlocks.js Outdated Show resolved Hide resolved
@@ -44,5 +44,8 @@ export const useBlockchainStatsStore = defineStore('blockchainStats', {
const { data } = await axios.get(`${useRuntimeConfig().public.MIDDLEWARE_URL}/v2/txs/count`)
this.transactionsCount = data
},
increaseTotalTransactionsCounter() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rename this to increaseTransactionsCount but It's just a preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your suggestion, adjusted.

...keyblock,
})

if (keyblocks.value.length > 18) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are keblocks removed if the total length is > 18?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the limit of visibility, added a constant to make the value self-explanatory 👍

}

function processKeyblockUpdate(keyblock) {
if (keyblocks.value?.[0].hash !== keyblock.prev_key_hash) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, I think this function should be more readable or at least have some comments. It's hard to understand what's going on.

...microblock,
})

if (selectedKeyblockMicroblocks.value.length > 30) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here, I'm wondering why 30

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the limit of visibility, added a constant to make the value self-explanatory 👍

@lukeromanowicz
Copy link
Contributor Author

lukeromanowicz commented Apr 20, 2023

Demo showing the result:

Before (a few requests every time a new microblock is minted):
image

After (requests to REST API only when a new keyblock is minted):
image

Copy link
Collaborator

@janmichek janmichek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes, providing measurements and explanation. 🕵️ I wish there could be done something with the implementation. Some parts feel heavyweight and hard to read what's going on

src/stores/recentBlocks.js Outdated Show resolved Hide resolved
}

function processKeyblockUpdate(keyblock) {
if (keyblocks.value?.[0].hash !== keyblock.prev_key_hash) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I am not satisfied with the outcome. The function is long and has many comments and it's hard to read for me

src/stores/recentBlocks.js Show resolved Hide resolved
src/stores/recentBlocks.js Show resolved Hide resolved
src/pages/index.vue Outdated Show resolved Hide resolved
@lukeromanowicz
Copy link
Contributor Author

Thanks @janmichek I'll try to restructure the code right after I finish Oracle details page

@lukeromanowicz
Copy link
Contributor Author

@janmichek @michele-franchi I've improved reliability and readability. Please let me know what you think

Copy link
Collaborator

@janmichek janmichek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good edit ⚡ Hope you see the same value in code readability, even tho it was not easy to achieve given the fact of directing data from different sources. A long step forward I would say.
I would still like to see some nicely named constants of what's going on in some if expressions, but giving it the green light anyway 😺

src/stores/recentBlocks.js Show resolved Hide resolved
src/stores/recentBlocks.js Show resolved Hide resolved
@lukeromanowicz
Copy link
Contributor Author

@janmichek I do, thanks for pushing for that. I had a brain lock when I tried to refactor it the first time and didn't know how to tackle it

@michele-franchi
Copy link
Collaborator

@csiarab could you check it?

@CharisSiarampalis
Copy link

@lukeromanowicz Is this normal ?
image

@lukeromanowicz
Copy link
Contributor Author

@csiarab no, that's not normal. 👀 but also this part has not been touched in this PR and I'm not able to reproduce it. Please give it another try

Copy link
Collaborator

@michele-franchi michele-franchi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice!

I noticed a difference between transaction count from the current dev:

Screen.Recording.2023-05-02.at.13.15.02.mov

and if you check the total transactions at the beginning of the video by a sum of all numbers inside microblocks you'll see it's not correct. Could you verify it? Thanks

@lukeromanowicz
Copy link
Contributor Author

lukeromanowicz commented May 3, 2023

@michele-franchi I'm afraid it's an issue that can be tackled only on the mdw side. There isn't much we can do about it right now. The current implementation we have on the develop branch is pretty much never accurate, while after changes in this PR it's accurate when a new keyblock gets minted. e.g.

image

I described the issues I found in a dedicated issue on the mdw side: aeternity/ae_mdw#1291
And created a follow-up ticket to improve our implementation once the backend side provides us with some tools to handle the issue in the frontend.

@michele-franchi
Copy link
Collaborator

@lukeromanowicz how is it accurate? In the screenshot I see Total transactions in the selected keyblock: 0 but there are two transactions. Is this still part of the issue?

@lukeromanowicz
Copy link
Contributor Author

lukeromanowicz commented May 4, 2023

@michele-franchi There are two scenarios:

  1. when you just open the page
    both current solution and the new one are more or less equally inaccurate by approximately the amount of transactions that were added in the latest microblock
  2. when you keep the page running until a new keyblock is minted
    current solution is not accurate while websocket gets 100% accurate.

The screenshot I've sent above is proof that the current solution is not accurate. I'm discussing with the mdw team the possibility to fix this inaccuracy in the linked mdw issue

Copy link
Collaborator

@michele-franchi michele-franchi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job! I guess we can then merge this and followup incorrect transactions count.

@lukeromanowicz lukeromanowicz merged commit 9fe8b35 into develop May 8, 2023
@lukeromanowicz lukeromanowicz deleted the feat/optimize-data-querying branch May 8, 2023 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Optimize the querying done in the dashboard
4 participants