From d392a52308aab04d78274b090ad93d8a38ae223b Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:24:47 -0400 Subject: [PATCH 1/8] Setup debug env --- curvesim/pool/cryptoswap/calcs/tricrypto_ng.py | 15 ++++++++++++++- test/fixtures/curve/tricrypto_math.vy | 10 ++++++++++ test/unit/test_tricrypto.py | 4 +++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py index df6002eb7..eec47e67a 100644 --- a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py +++ b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py @@ -145,13 +145,19 @@ def get_y( # noqa: complexity: 18 d = d // additional_prec // divider if b_is_neg: b *= -1 + print("python:", a) + print("python:", b) + print("python:", c) # 3*a*c/b - b - _3ac: int = 3 * a * c + _3ac: int = (3 * a) * c + print("python:", _3ac) + # if sign(_3ac) != sign(b): if b_is_neg: delta0: int = -(_3ac // -b) - b else: delta0 = _3ac // b - b + print("python:", delta0) # 9*a*c/b - 2*b - 27*a**2/b*d/b if b_is_neg: @@ -167,8 +173,10 @@ def get_y( # noqa: complexity: 18 sqrt_val: int = 0 if sqrt_arg > 0: + print("not falling back") sqrt_val = isqrt(sqrt_arg) else: + print("sqrt_arg is negative... falling back to newton_y") return [_newton_y(ANN, gamma, x, D, i), 0] b_cbrt: int = 0 @@ -176,27 +184,32 @@ def get_y( # noqa: complexity: 18 b_cbrt = _cbrt(b) else: b_cbrt = -_cbrt(-b) + print("python:", b_cbrt) second_cbrt: int = 0 if delta1 > 0: second_cbrt = _cbrt((delta1 + sqrt_val) // 2) else: second_cbrt = -_cbrt(-(delta1 - sqrt_val) // 2) + print("python:", second_cbrt) # b_cbrt*b_cbrt/10**18*second_cbrt/10**18 if second_cbrt < 0: C1: int = -(b_cbrt * b_cbrt // 10**18 * -second_cbrt // 10**18) else: C1 = b_cbrt * b_cbrt // 10**18 * second_cbrt // 10**18 + print("python:", C1) # (b + b*delta0/C1 - C1)/3 if sign(b * delta0) != sign(C1): root_K0: int = (b + -(b * delta0 // -C1) - C1) // 3 else: root_K0 = (b + b * delta0 // C1 - C1) // 3 + print("python:", root_K0) # D*D/27/x_k*D/x_j*root_K0/a root: int = D * D // 27 // x_k * D // x_j * root_K0 // a + print("python:", root) out: List[int] = [int(root), int(10**18 * root_K0 // a)] diff --git a/test/fixtures/curve/tricrypto_math.vy b/test/fixtures/curve/tricrypto_math.vy index 85ea1f35c..5ed1b6b64 100644 --- a/test/fixtures/curve/tricrypto_math.vy +++ b/test/fixtures/curve/tricrypto_math.vy @@ -156,10 +156,15 @@ def get_y( b = unsafe_div(unsafe_div(b, additional_prec), divider) c = unsafe_div(unsafe_div(c, additional_prec), divider) d = unsafe_div(unsafe_div(d, additional_prec), divider) + print("vyper:", a) + print("vyper:", b) + print("vyper:", c) # 3*a*c/b - b _3ac: int256 = unsafe_mul(3, a) * c + print("vyper:", _3ac) delta0: int256 = unsafe_div(_3ac, b) - b + print("vyper:", delta0) # 9*a*c/b - 2*b - 27*a**2/b*d/b delta1: int256 = ( @@ -185,6 +190,7 @@ def get_y( b_cbrt = convert(self._cbrt(convert(b, uint256)), int256) else: b_cbrt = -convert(self._cbrt(convert(-b, uint256)), int256) + print("vyper:", b_cbrt) second_cbrt: int256 = 0 if delta1 > 0: @@ -198,15 +204,18 @@ def get_y( self._cbrt(unsafe_div(convert(-(delta1 - sqrt_val), uint256), 2)), int256 ) + print("vyper:", second_cbrt) # b_cbrt*b_cbrt/10**18*second_cbrt/10**18 C1: int256 = unsafe_div( unsafe_div(b_cbrt * b_cbrt, 10**18) * second_cbrt, 10**18 ) + print("vyper:", C1) # (b + b*delta0/C1 - C1)/3 root_K0: int256 = unsafe_div(b + b * delta0 / C1 - C1, 3) + print("vyper:", root_K0) # D*D/27/x_k*D/x_j*root_K0/a root: int256 = unsafe_div( @@ -216,6 +225,7 @@ def get_y( ) * root_K0, a ) + print("vyper:", root) out: uint256[2] = [ convert(root, uint256), diff --git a/test/unit/test_tricrypto.py b/test/unit/test_tricrypto.py index c49cb1180..0bc63180a 100644 --- a/test/unit/test_tricrypto.py +++ b/test/unit/test_tricrypto.py @@ -6,7 +6,7 @@ from itertools import permutations import boa -from hypothesis import HealthCheck, assume, given, settings +from hypothesis import HealthCheck, assume, given, reproduce_failure, settings from hypothesis import strategies as st from curvesim.pool import CurveCryptoPool @@ -20,6 +20,7 @@ _newton_y, wad_exp, ) + from ..fixtures.pool import pack_prices, unpack_prices @@ -295,6 +296,7 @@ def test_get_p(tricrypto_math, A, gamma, x0, x1, x2): assert p == expected_p +@reproduce_failure("6.54.6", b"AXicY2BgYGAEQjAFIxh8GDlZGBmBbD5G5v8ABlUBcw==") @given( amplification_coefficient, gamma_coefficient, From ffefdeec8cbade3ee2c654cc98808f022885d5e1 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:25:01 -0400 Subject: [PATCH 2/8] Fix the bug --- curvesim/pool/cryptoswap/calcs/tricrypto_ng.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py index eec47e67a..29f33d9db 100644 --- a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py +++ b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py @@ -101,6 +101,7 @@ def get_y( # noqa: complexity: 18 else: _c = gamma2 * _c_neg // D * ANN // 27 // A_MULTIPLIER c += _c + c_is_neg = c < 0 # (10**18 + gamma)**2/27 d: int = (10**18 + gamma) ** 2 // 27 @@ -131,6 +132,8 @@ def get_y( # noqa: complexity: 18 additional_prec: int = 0 if b_is_neg: b *= -1 + if c_is_neg: + c *= -1 if abs(a) > abs(b): additional_prec = abs(a // b) a = a * additional_prec // divider @@ -145,6 +148,8 @@ def get_y( # noqa: complexity: 18 d = d // additional_prec // divider if b_is_neg: b *= -1 + if c_is_neg: + c *= -1 print("python:", a) print("python:", b) print("python:", c) From 66e1f441b716daee372e1394d15aad4b3c2041aa Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:26:19 -0400 Subject: [PATCH 3/8] Fix hidden bug --- curvesim/pool/cryptoswap/calcs/tricrypto_ng.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py index 29f33d9db..3f4634cce 100644 --- a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py +++ b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py @@ -157,8 +157,7 @@ def get_y( # noqa: complexity: 18 # 3*a*c/b - b _3ac: int = (3 * a) * c print("python:", _3ac) - # if sign(_3ac) != sign(b): - if b_is_neg: + if sign(_3ac) != sign(b): delta0: int = -(_3ac // -b) - b else: delta0 = _3ac // b - b From 638088f85b9079883252123fb695808be08a7e63 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:35:51 -0400 Subject: [PATCH 4/8] Fix another hidden bug --- curvesim/pool/cryptoswap/calcs/tricrypto_ng.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py index 3f4634cce..17d1b54a5 100644 --- a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py +++ b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py @@ -164,10 +164,14 @@ def get_y( # noqa: complexity: 18 print("python:", delta0) # 9*a*c/b - 2*b - 27*a**2/b*d/b + if sign(_3ac) != sign(b): + delta1: int = -(3 * _3ac // -b) - 2 * b + else: + delta1 = 3 * _3ac // b - 2 * b if b_is_neg: - delta1: int = -(3 * _3ac // -b) - 2 * b - 27 * a**2 // -b * d // -b + delta1 -= 27 * a**2 // -b * d // -b else: - delta1 = 3 * _3ac // b - 2 * b - 27 * a**2 // b * d // b + delta1 -= 27 * a**2 // b * d // b # delta1**2 + 4*delta0**2/b*delta0 if b_is_neg: From fdf60b5b4acff2d53e7896451101ee8171be53d9 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:36:07 -0400 Subject: [PATCH 5/8] Remove prints --- curvesim/pool/cryptoswap/calcs/tricrypto_ng.py | 12 ------------ test/fixtures/curve/tricrypto_math.vy | 10 ---------- 2 files changed, 22 deletions(-) diff --git a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py index 17d1b54a5..de775e164 100644 --- a/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py +++ b/curvesim/pool/cryptoswap/calcs/tricrypto_ng.py @@ -150,18 +150,13 @@ def get_y( # noqa: complexity: 18 b *= -1 if c_is_neg: c *= -1 - print("python:", a) - print("python:", b) - print("python:", c) # 3*a*c/b - b _3ac: int = (3 * a) * c - print("python:", _3ac) if sign(_3ac) != sign(b): delta0: int = -(_3ac // -b) - b else: delta0 = _3ac // b - b - print("python:", delta0) # 9*a*c/b - 2*b - 27*a**2/b*d/b if sign(_3ac) != sign(b): @@ -181,10 +176,8 @@ def get_y( # noqa: complexity: 18 sqrt_val: int = 0 if sqrt_arg > 0: - print("not falling back") sqrt_val = isqrt(sqrt_arg) else: - print("sqrt_arg is negative... falling back to newton_y") return [_newton_y(ANN, gamma, x, D, i), 0] b_cbrt: int = 0 @@ -192,32 +185,27 @@ def get_y( # noqa: complexity: 18 b_cbrt = _cbrt(b) else: b_cbrt = -_cbrt(-b) - print("python:", b_cbrt) second_cbrt: int = 0 if delta1 > 0: second_cbrt = _cbrt((delta1 + sqrt_val) // 2) else: second_cbrt = -_cbrt(-(delta1 - sqrt_val) // 2) - print("python:", second_cbrt) # b_cbrt*b_cbrt/10**18*second_cbrt/10**18 if second_cbrt < 0: C1: int = -(b_cbrt * b_cbrt // 10**18 * -second_cbrt // 10**18) else: C1 = b_cbrt * b_cbrt // 10**18 * second_cbrt // 10**18 - print("python:", C1) # (b + b*delta0/C1 - C1)/3 if sign(b * delta0) != sign(C1): root_K0: int = (b + -(b * delta0 // -C1) - C1) // 3 else: root_K0 = (b + b * delta0 // C1 - C1) // 3 - print("python:", root_K0) # D*D/27/x_k*D/x_j*root_K0/a root: int = D * D // 27 // x_k * D // x_j * root_K0 // a - print("python:", root) out: List[int] = [int(root), int(10**18 * root_K0 // a)] diff --git a/test/fixtures/curve/tricrypto_math.vy b/test/fixtures/curve/tricrypto_math.vy index 5ed1b6b64..85ea1f35c 100644 --- a/test/fixtures/curve/tricrypto_math.vy +++ b/test/fixtures/curve/tricrypto_math.vy @@ -156,15 +156,10 @@ def get_y( b = unsafe_div(unsafe_div(b, additional_prec), divider) c = unsafe_div(unsafe_div(c, additional_prec), divider) d = unsafe_div(unsafe_div(d, additional_prec), divider) - print("vyper:", a) - print("vyper:", b) - print("vyper:", c) # 3*a*c/b - b _3ac: int256 = unsafe_mul(3, a) * c - print("vyper:", _3ac) delta0: int256 = unsafe_div(_3ac, b) - b - print("vyper:", delta0) # 9*a*c/b - 2*b - 27*a**2/b*d/b delta1: int256 = ( @@ -190,7 +185,6 @@ def get_y( b_cbrt = convert(self._cbrt(convert(b, uint256)), int256) else: b_cbrt = -convert(self._cbrt(convert(-b, uint256)), int256) - print("vyper:", b_cbrt) second_cbrt: int256 = 0 if delta1 > 0: @@ -204,18 +198,15 @@ def get_y( self._cbrt(unsafe_div(convert(-(delta1 - sqrt_val), uint256), 2)), int256 ) - print("vyper:", second_cbrt) # b_cbrt*b_cbrt/10**18*second_cbrt/10**18 C1: int256 = unsafe_div( unsafe_div(b_cbrt * b_cbrt, 10**18) * second_cbrt, 10**18 ) - print("vyper:", C1) # (b + b*delta0/C1 - C1)/3 root_K0: int256 = unsafe_div(b + b * delta0 / C1 - C1, 3) - print("vyper:", root_K0) # D*D/27/x_k*D/x_j*root_K0/a root: int256 = unsafe_div( @@ -225,7 +216,6 @@ def get_y( ) * root_K0, a ) - print("vyper:", root) out: uint256[2] = [ convert(root, uint256), From 3a8947c6542da817c80335f29b1c1d24fb1d8410 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:36:53 -0400 Subject: [PATCH 6/8] Wrapped up testing with fixes Ran hypothesis with 1000s of cases to double-check fixes did not lead to regressions. --- test/unit/test_tricrypto.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/test_tricrypto.py b/test/unit/test_tricrypto.py index 0bc63180a..1fb2d0fa5 100644 --- a/test/unit/test_tricrypto.py +++ b/test/unit/test_tricrypto.py @@ -6,7 +6,7 @@ from itertools import permutations import boa -from hypothesis import HealthCheck, assume, given, reproduce_failure, settings +from hypothesis import HealthCheck, assume, given, settings from hypothesis import strategies as st from curvesim.pool import CurveCryptoPool @@ -296,7 +296,6 @@ def test_get_p(tricrypto_math, A, gamma, x0, x1, x2): assert p == expected_p -@reproduce_failure("6.54.6", b"AXicY2BgYGAEQjAFIxh8GDlZGBmBbD5G5v8ABlUBcw==") @given( amplification_coefficient, gamma_coefficient, From b557d99bfe9361197b1a524ba3a01d18b8c6b046 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:51:54 -0400 Subject: [PATCH 7/8] Reduce test param to avoid unsafe value error --- test/unit/test_tricrypto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_tricrypto.py b/test/unit/test_tricrypto.py index 1fb2d0fa5..9a94563bd 100644 --- a/test/unit/test_tricrypto.py +++ b/test/unit/test_tricrypto.py @@ -306,7 +306,7 @@ def test_get_p(tricrypto_math, A, gamma, x0, x1, x2): st.integers(min_value=0, max_value=2), st.integers(min_value=0, max_value=2), ).filter(lambda x: x[0] != x[1]), - st.integers(min_value=1, max_value=10000), + st.integers(min_value=1, max_value=5500), ) @settings( suppress_health_check=[HealthCheck.function_scoped_fixture], From 06df80710823d7653d884b99e8830895c4ac8a11 Mon Sep 17 00:00:00 2001 From: Chan-Ho Suh Date: Fri, 3 Nov 2023 11:57:27 -0400 Subject: [PATCH 8/8] Add changelog entry --- changelog.d/20231103_115610_chanhosuh_fix_calc_diff.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/20231103_115610_chanhosuh_fix_calc_diff.rst diff --git a/changelog.d/20231103_115610_chanhosuh_fix_calc_diff.rst b/changelog.d/20231103_115610_chanhosuh_fix_calc_diff.rst new file mode 100644 index 000000000..a00d141a7 --- /dev/null +++ b/changelog.d/20231103_115610_chanhosuh_fix_calc_diff.rst @@ -0,0 +1,4 @@ +Fixed +----- + +- Fixed handling of integer signed division in Tricrypto-NG's `get_y` calc.