You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In this previous discussion, it introduces a fix that puts AdjustedTarget in NewPoolSimulator and UpdateBalance. However, that was a non-backwards-compatible update. Scenarios: the AdjustedTarget is valid in the 1st call, then panic in the 2nd call.
Correct behaviour: Still allow to call 1st CalcAmountOut and UpdateBalance, fails in 2nd CalcAmountOut call.
Behavior in the discussion: 1st CalcAmountOut is still successful, but 1st UpdateBalance will fail.
The current PR keeps the same current behavior, by only removing the mutex (still keeps the AdjustedTarget in CalcAmountOut call). It needs to clone the state into a different object to avoid data race (even when different threads write the same data into the shared object).
Below is a summary of compliance checks for this PR:
Security Compliance
⚪
Concurrency data race
Description: Removing the mutex from PoolSimulator and eliminating locking in getPMMState() can introduce concurrent read/write data races on p.PMMState (and potentially other shared fields), which may lead to undefined behavior or panics (DoS) when the simulator is accessed concurrently (e.g., during routing / quote computation). storage.go [11-15]
Generic: Robust Error Handling and Edge Case Management
Objective: Ensure comprehensive error handling that provides meaningful context and graceful degradation
Status: Concurrency safety: Removing locking around p.PMMState access may introduce data races or inconsistent state under concurrent reads/writes, which requires verification that all callers guarantee single-threaded access or otherwise ensure safety.
Description: Removing the sync.RWMutex from PoolSimulator and the locking in getPMMState() introduces potential data races on shared mutable state (p.PMMState), which could lead to inconsistent pricing/route computation and unintended outcomes if pool simulators are accessed concurrently (also applies to pkg/liquidity-source/dodo/dsp/storage.go and pkg/liquidity-source/dodo/dvm/storage.go, plus the corresponding pool_simulator.go changes). storage.go [11-14]
Generic: Robust Error Handling and Edge Case Management
Objective: Ensure comprehensive error handling that provides meaningful context and graceful degradation
Status: Concurrency safety risk: getPMMState() now mutates and returns p.PMMState without any synchronization, which may introduce data races or inconsistent state if PoolSimulator is accessed concurrently.
Description: The intended panic recovery in NewPoolSimulator is ineffective because libv2.AdjustedTarget(&poolState) is invoked before the defer recover is registered, so a panic triggered by malformed/hostile pool data can crash the process (denial-of-service) instead of being converted to an error. pool_simulator.go [72-82]
Generic: Robust Error Handling and Edge Case Management
Objective: Ensure comprehensive error handling that provides meaningful context and graceful degradation
Status: Panic recovery misordered: libv2.AdjustedTarget(&poolState) is invoked before the defer-based recover() is registered, so panics from AdjustedTarget will not be caught as intended.
Deep-copy the p.PMMState struct before modification to prevent data races and unintended mutation of the original pool state. The current shallow copy is insufficient as PMMState contains pointer fields.
Why: The suggestion correctly identifies a critical data race condition introduced by the PR, where a shallow copy of a struct with pointer fields leads to unintended mutation of the original state in a concurrent environment.
High
Avoid shared pointer state mutation
Deep-copy the p.PMMState struct before modification to prevent data races and unintended mutation of the original pool state. The current shallow copy is insufficient as PMMState contains pointer fields.
Why: The suggestion correctly identifies a critical data race condition introduced by the PR, where a shallow copy of a struct with pointer fields leads to unintended mutation of the original state in a concurrent environment.
High
Make PMM state copy truly independent
Deep-copy the p.PMMState struct before modification to prevent data races and unintended mutation of the original pool state. The current shallow copy is insufficient as PMMState contains pointer fields.
Why: The suggestion correctly identifies a critical data race condition introduced by the PR, where a shallow copy of a struct with pointer fields leads to unintended mutation of the original state in a concurrent environment.
High
Possible issue
Deep-copy state in clones
Deep-copy the PMMState fields within CloneState() to ensure that cloned simulators have a fully independent state from the original. This prevents state corruption between the original and cloned pool instances during simulations.
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 9
__
Why: The suggestion correctly identifies a critical bug where CloneState performs a shallow copy, causing the cloned and original simulators to share state, which would lead to incorrect simulation results.
High
Prevent shared mutable clone state
Deep-copy the PMMState fields within CloneState() to ensure that cloned simulators have a fully independent state from the original. This prevents state corruption between the original and cloned pool instances during simulations.
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 9
__
Why: The suggestion correctly identifies a critical bug where CloneState performs a shallow copy, causing the cloned and original simulators to share state, which would lead to incorrect simulation results.
High
Make cloned state independent
Deep-copy the PMMState fields within CloneState() to ensure that cloned simulators have a fully independent state from the original. This prevents state corruption between the original and cloned pool instances during simulations.
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 9
__
Why: The suggestion correctly identifies a critical bug where CloneState performs a shallow copy, causing the cloned and original simulators to share state, which would lead to incorrect simulation results.
- libv2.AdjustedTarget(&poolState)-
defer func() {
if r := recover(); r != nil {
if recoveredError, ok := r.(error); ok {
err = recoveredError
} else {
err = shared.ErrPanicAdjustedTarget
}
}
}()
+ libv2.AdjustedTarget(&poolState)+
Suggestion importance[1-10]: 9
__
Why: The suggestion correctly identifies a critical bug in the PR's new panic recovery logic, where the defer statement is placed after the function call it is supposed to protect, rendering it ineffective.
High
Add panic recovery to prevent crashes
Add a defer with recover to the UpdateBalance method to handle potential panics from the libv2.AdjustedTarget call and prevent the application from crashing.
Why: The suggestion correctly points out that the new call to libv2.AdjustedTarget in UpdateBalance can panic, and proposes adding a recovery mechanism to prevent potential application crashes, which is a significant reliability improvement.
Medium
Possible issue
Preserve deferred error propagation
In NewPoolSimulator, the error handling for panics is flawed because the final return statement overwrites the recovered error with nil. Use a naked return to ensure the error is correctly propagated.
Why: The suggestion correctly identifies a bug where the error recovered from a panic is discarded because the function explicitly returns a nil error, defeating the purpose of the new defer-recover block.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why did we need it?
To remove locking when simulation (seems to be unnecessary).
Related thread from previous update: https://team-kyber.slack.com/archives/C061UNZDUVC/p1724213576872309
In this previous discussion, it introduces a fix that puts
AdjustedTargetinNewPoolSimulatorandUpdateBalance. However, that was a non-backwards-compatible update. Scenarios: theAdjustedTargetis valid in the 1st call, then panic in the 2nd call.The current PR keeps the same current behavior, by only removing the mutex (still keeps the
AdjustedTargetinCalcAmountOutcall). It needs to clone the state into a different object to avoid data race (even when different threads write the same data into the shared object).Related Issue
Release Note
How Has This Been Tested?
Screenshots (if appropriate):