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

Mitigate issues with missing awaits in state method calls #253

Open
wants to merge 28 commits into
base: develop
Choose a base branch
from

Conversation

joaosreis
Copy link
Collaborator

This PR creates a queue-like mechanism for the state methods with a method that can be awaited until all the queued promises are resolved. This method is then called after a runtime method executes, which makes is so that these state operations are executed in the proper runtime moment (and in the order they are queued) even if the user misses to await them.
This helps mitigate the issue of missing awaits to state methods (#199), ensuring these are properly executed if they are runtime methods top level calls, but not if the runtime method calls some other method with state calls and this method is not awaited, because then the runtime method execution can finish before the other method had the chance to queue the operations. An example of such behavior would be:

@runtimeMethod()
  public async addBalance(
    tokenId: TokenId,
    address: PublicKey,
    amount: Balance
  ): Promise<void> {
    const circulatingSupply = await this.circulatingSupply.get();
    const newCirculatingSupply = Balance.from(circulatingSupply.value).add(
      amount
    );
    assert(
      newCirculatingSupply.lessThanOrEqual(this.config.totalSupply),
      "Circulating supply would be higher than total supply"
    );
    this.circulatingSupply.set(newCirculatingSupply);
    this.mint(tokenId, address, amount); // missing await in a method that calls state methods
}

However, if we deconstruct the mint method into

const key = new BalancesKey({ tokenId, address });
const balanceOption = await this.balances.get(key);
const balance = Balance.Unsafe.fromField(balanceOption.value.value);
const newBalance = balance.add(amount);
this.balances.set(key, newBalance);

this code will now work despite the missing awaits in the state set calls.

I also tested adding a 50ms delay timeout to the queue onCompleted method in an attempt to help these other missing awaits catchup, but ended up not adding it as I felt that it might not work if the complexity of the runtime methods increases as well because this doesn't ensure the linearity of these calls.

joaosreis and others added 28 commits November 26, 2024 09:47
… in get() and set() methods; remove GlobalExecutionContext class
…ration handling; replace promise chaining with a queue system for better management of pending operations
…e class; refactor get() and set() methods to utilize the new queue system
@joaosreis joaosreis self-assigned this Jan 10, 2025
@joaosreis joaosreis requested a review from rpanic January 10, 2025 11:01
@joaosreis joaosreis requested review from maht0rz, rpanic and ejMina226 and removed request for rpanic January 10, 2025 11:01
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.

2 participants