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

Implement caching for parameters and identity storage contracts #2834

Merged
merged 11 commits into from
Dec 25, 2023

Conversation

milosstanisavljevic
Copy link
Contributor

@milosstanisavljevic milosstanisavljevic commented Dec 11, 2023

Description

Added listener for Parameters storage contract. Implemented caching for functions inside parameters storage.

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Tested in the local env, creating assets locally.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Copy link
Member

@0xbraindevd 0xbraindevd left a comment

Choose a reason for hiding this comment

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

Looks good, but there are other ways how to reduce number of calls. Just to name a few:

  • In the ValidationService we're separately checking assertionSize, assertionTriplesNumber and assertionChunksNumber. We're using 3 calls here. Instead, we can just use 1 call getAssertion, which would return all the data
  • callScoreFunction can be replaced with local implementation of the score function (same as we did for hashing) [Now as I see we don't use this function]
  • One more idea, maybe we can validate bid on publisher node before sending requests instead of validating on every node?
  • Potentially we could also cache getLog2PLDSFParams, but we need to add events for that contract

There could be more optimizations, just ran through the code quickly

P.S. Looks like we're missing validateAssertion for update receiver. Not related to the topic, but adding it here just not to forget later

@@ -406,10 +416,16 @@ class Web3Service {

async callContractFunction(contractInstance, functionName, args) {
Copy link
Member

Choose a reason for hiding this comment

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

Since we're using this function for identityId, old logic for getIdentityId function should be removed and we can add it to cached parameters since it's immutable

@0xbraindevd
Copy link
Member

One more idea we should consider, what if we use MySQL as a key-value store instead of caching in memory?

@@ -586,3 +588,16 @@ export const BLOCK_TIME_MILLIS = {
};

export const TRANSACTION_CONFIRMATIONS = 1;

export const CACHED_FUNCTIONS = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you also please move the cached values from the scoring function ?

try {
// eslint-disable-next-line no-await-in-loop
result = await contractInstance[functionName](...args);
if (CACHED_FUNCTIONS.ParametersStorage.includes(functionName)) {
this.cacheParameter(functionName, result);
}
} catch (error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason why we don't call "handleError" in the catch block anymore ? This was previously used to switch RPCs in case the error was due to RPC being down.
If this is intended, then the while loop is not necessary and can be removed.

Copy link
Member

Choose a reason for hiding this comment

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

We switched to a new provider implementation in the ethers.js that automatically hits different RPC after defined timeout, while loop probably can be removed as we're not retrying the call anyway (because of throwing new error)

@@ -589,15 +589,19 @@ export const BLOCK_TIME_MILLIS = {

export const TRANSACTION_CONFIRMATIONS = 1;

export const CACHE_DATA_TYPES = {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure I get why would we need this

Copy link
Member

Choose a reason for hiding this comment

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

Still don't think it's needed, for the specific events we have predefined types in the ABI

e.g. for ParametersStorage it can't be anything else except Number, so I would just cast values based on the types in the ABI
image

@@ -272,11 +273,28 @@ class Web3Service {
}

cacheParameter(parameterName, parameterValue) {
resultCache[parameterName] = parameterValue;
console.log('PARAMETER IME', parameterName);
const found = Object.values(CACHED_FUNCTIONS)
Copy link
Member

Choose a reason for hiding this comment

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

Why not just add contractName as argument for the function?

}

getCachedValue(parameterName) {
return resultCache[parameterName];
if (CACHED_FUNCTIONS.ParametersStorage.some((item) => item.name === parameterName)) {
Copy link
Member

Choose a reason for hiding this comment

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

Why not just add contractName as argument for the function?

};

export const CACHED_FUNCTIONS = {
ParametersStorage: [
Copy link
Member

Choose a reason for hiding this comment

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

Let's make it an object, with parameterName as key and type as value, then we don't need to iterate through all parameters every time.

If we remove types as I suggested in the comment above, we can just make it a Set with constant O(1) lookup

cacheParameter(contractName, parameterName, parameterValue) {
const found =
CACHED_FUNCTIONS[contractName] &&
CACHED_FUNCTIONS[contractName].find((item) => item.name === parameterName);
Copy link
Member

Choose a reason for hiding this comment

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

This is not needed if CACHED_FUNCTIONS is an object/Set instead of array

@@ -589,15 +589,19 @@ export const BLOCK_TIME_MILLIS = {

export const TRANSACTION_CONFIRMATIONS = 1;

export const CACHE_DATA_TYPES = {
Copy link
Member

Choose a reason for hiding this comment

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

Still don't think it's needed, for the specific events we have predefined types in the ABI

e.g. for ParametersStorage it can't be anything else except Number, so I would just cast values based on the types in the ABI
image

CACHED_FUNCTIONS[contractName].find((item) => item.name === parameterName);
if (found) {
const { type } = found;
switch (type) {
Copy link
Member

Choose a reason for hiding this comment

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

Following the suggestion to remove types from constants, I would make it a separate function somewhere in the services or even utils for casting based on types of the event arguments in the ABI and cast it directly in the event handler instead of doing it here

getCachedValue(contractName, parameterName) {
if (
CACHED_FUNCTIONS[contractName] &&
CACHED_FUNCTIONS[contractName].some((item) => item.name === parameterName)
Copy link
Member

Choose a reason for hiding this comment

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

This is not needed if CACHED_FUNCTIONS is an object/Set instead of array

while (result === undefined) {
result = this.getCachedValue(contractName, functionName);

while (!result) {
Copy link
Member

Choose a reason for hiding this comment

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

while loop here is redundant, we won't ever reiterate here

@@ -404,12 +432,15 @@ class Web3Service {
}
}

async callContractFunction(contractInstance, functionName, args) {
async callContractFunction(contractInstance, functionName, args, contractName = null) {
Copy link
Member

Choose a reason for hiding this comment

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

Can't we add name field to the contractInstance during initialization?

Co-authored-by: Nikola Todorovic <nikolaztodorovic26@gmail.com>
@NZT48 NZT48 changed the title V6/improvement/reduce rpc calls Implement caching for parameters and identity storage contracts Dec 25, 2023
@djordjekovac djordjekovac merged commit 864fc31 into v6/develop Dec 25, 2023
3 checks passed
@djordjekovac djordjekovac deleted the v6/improvement/reduce-rpc-calls branch December 25, 2023 11:54
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.

5 participants