From b7f8a40a0df367c85522b7729a3b1456d7649442 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Mon, 5 Feb 2024 20:55:29 +0000 Subject: [PATCH 1/5] Minor optimizations --- src/utils/RedBlackTreeLib.sol | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/utils/RedBlackTreeLib.sol b/src/utils/RedBlackTreeLib.sol index cea8596878..b470bdcbc2 100644 --- a/src/utils/RedBlackTreeLib.sol +++ b/src/utils/RedBlackTreeLib.sol @@ -352,7 +352,7 @@ library RedBlackTreeLib { /// @solidity memory-safe-assembly assembly { function getKey(packed_, bitpos_) -> index_ { - index_ := and(shr(bitpos_, packed_), _BITMASK_KEY) + index_ := and(_BITMASK_KEY, shr(bitpos_, packed_)) } function setKey(packed_, bitpos_, key_) -> result_ { @@ -393,8 +393,7 @@ library RedBlackTreeLib { function insertFixup(nodes_, key_) { let BR := _BITMASK_RED - for {} 1 {} { - if eq(key_, mload(0x00)) { break } + for {} iszero(eq(key_, mload(0x00))) {} { let packed_ := sload(or(nodes_, key_)) let parent_ := getKey(packed_, _BITPOS_PARENT) let parentPacked_ := sload(or(nodes_, parent_)) @@ -427,8 +426,8 @@ library RedBlackTreeLib { sstore(or(nodes_, grandParent_), or(grandParentPacked_, BR)) key_ := grandParent_ } - let root_ := mload(0x00) - sstore(or(nodes_, root_), and(sload(or(nodes_, root_)), not(BR))) + let root_ := or(nodes_, mload(0x00)) + sstore(root_, and(sload(root_), not(BR))) } function insert(nodes_, cursor_, key_, x_) -> err_ { @@ -480,8 +479,7 @@ library RedBlackTreeLib { function removeFixup(nodes_, key_) { let BR := _BITMASK_RED - for {} 1 {} { - if eq(key_, mload(0x00)) { break } + for {} iszero(eq(key_, mload(0x00))) {} { let packed_ := sload(or(nodes_, key_)) if and(BR, packed_) { break } @@ -586,9 +584,7 @@ library RedBlackTreeLib { } function remove(nodes_, key_) -> err_ { - let last_ := shr(128, mload(0x20)) - - if gt(key_, last_) { + if gt(key_, shr(128, mload(0x20))) { err_ := ERROR_POINTER_OUT_OF_BOUNDS leave } From 97ab2bffdf9a7b518ab70140af0c45612b0621d9 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Mon, 5 Feb 2024 23:32:28 +0000 Subject: [PATCH 2/5] T --- .gas-snapshot | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index d3abedaacd..e7eafcc04a 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -248,7 +248,7 @@ ERC4337Test:testValidateUserOp() (gas: 491555) ERC4337Test:test__codesize() (gas: 54768) ERC4626Test:testDepositWithNoApprovalReverts() (gas: 16371) ERC4626Test:testDepositWithNotEnoughApprovalReverts() (gas: 89884) -ERC4626Test:testDifferentialFullMulDiv(uint256,uint256,uint256) (runs: 256, μ: 3325, ~: 3185) +ERC4626Test:testDifferentialFullMulDiv(uint256,uint256,uint256) (runs: 256, μ: 3322, ~: 3185) ERC4626Test:testMetadata() (gas: 15439) ERC4626Test:testMintWithNoApprovalReverts() (gas: 16345) ERC4626Test:testMintZero() (gas: 54317) @@ -256,7 +256,7 @@ ERC4626Test:testMultipleMintDepositRedeemWithdraw() (gas: 425481) ERC4626Test:testRedeemWithNoShareAmountReverts() (gas: 10918) ERC4626Test:testRedeemWithNotEnoughShareAmountReverts() (gas: 142915) ERC4626Test:testSingleDepositWithdraw(uint128) (runs: 256, μ: 202651, ~: 202662) -ERC4626Test:testSingleMintRedeem(uint128) (runs: 256, μ: 201578, ~: 201589) +ERC4626Test:testSingleMintRedeem(uint128) (runs: 256, μ: 201579, ~: 201589) ERC4626Test:testTryGetAssetDecimals() (gas: 30466616) ERC4626Test:testUseVirtualShares() (gas: 2439368) ERC4626Test:testVaultInteractionsForSomeoneElse() (gas: 296164) @@ -922,29 +922,29 @@ ReceiverTest:testOnERC1155BatchReceived() (gas: 48975) ReceiverTest:testOnERC1155Received() (gas: 46717) ReceiverTest:testOnERC721Received() (gas: 64127) ReceiverTest:test__codesize() (gas: 3310) -RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3433600) -RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5847065) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 670224, ~: 501333) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 420510, ~: 381882) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21571156) -RedBlackTreeLibTest:testRedBlackTreeInsertBenchStep() (gas: 3709258) -RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint160() (gas: 3474876) -RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint256() (gas: 6374406) -RedBlackTreeLibTest:testRedBlackTreeInsertOneGas() (gas: 45601) -RedBlackTreeLibTest:testRedBlackTreeInsertTenGas() (gas: 283211) -RedBlackTreeLibTest:testRedBlackTreeInsertThreeGas() (gas: 96322) -RedBlackTreeLibTest:testRedBlackTreeInsertTwoGas() (gas: 69871) -RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 246019, ~: 227676) -RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 249767, ~: 249005) -RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 236444, ~: 195558) -RedBlackTreeLibTest:testRedBlackTreePointers() (gas: 91971) +RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3431797) +RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5845334) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 644465, ~: 504214) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 434126, ~: 390307) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21560698) +RedBlackTreeLibTest:testRedBlackTreeInsertBenchStep() (gas: 3707644) +RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint160() (gas: 3473262) +RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint256() (gas: 6372882) +RedBlackTreeLibTest:testRedBlackTreeInsertOneGas() (gas: 45595) +RedBlackTreeLibTest:testRedBlackTreeInsertTenGas() (gas: 283061) +RedBlackTreeLibTest:testRedBlackTreeInsertThreeGas() (gas: 96286) +RedBlackTreeLibTest:testRedBlackTreeInsertTwoGas() (gas: 69859) +RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 231594, ~: 225833) +RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 258449, ~: 248963) +RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 225201, ~: 195540) +RedBlackTreeLibTest:testRedBlackTreePointers() (gas: 91959) RedBlackTreeLibTest:testRedBlackTreeRejectsEmptyValue() (gas: 3238) -RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58295) -RedBlackTreeLibTest:testRedBlackTreeTreeFullReverts() (gas: 50372) -RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56220) -RedBlackTreeLibTest:testRedBlackTreeValues() (gas: 191728) -RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 360182, ~: 242333) -RedBlackTreeLibTest:test__codesize() (gas: 14162) +RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58271) +RedBlackTreeLibTest:testRedBlackTreeTreeFullReverts() (gas: 50366) +RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56202) +RedBlackTreeLibTest:testRedBlackTreeValues() (gas: 191692) +RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 400524, ~: 266954) +RedBlackTreeLibTest:test__codesize() (gas: 14149) ReentrancyGuardTest:testRecursiveDirectUnguardedCall() (gas: 34254) ReentrancyGuardTest:testRecursiveIndirectUnguardedCall() (gas: 47771) ReentrancyGuardTest:testRevertGuardLocked() (gas: 53917) From fec3cbed0e75e63106aba7f893342543cff7514e Mon Sep 17 00:00:00 2001 From: Vectorized Date: Tue, 6 Feb 2024 00:50:17 +0000 Subject: [PATCH 3/5] T --- .gas-snapshot | 24 +++++----- src/utils/RedBlackTreeLib.sol | 85 +++++++++++++---------------------- 2 files changed, 44 insertions(+), 65 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index e7eafcc04a..a8084fe82c 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -922,11 +922,11 @@ ReceiverTest:testOnERC1155BatchReceived() (gas: 48975) ReceiverTest:testOnERC1155Received() (gas: 46717) ReceiverTest:testOnERC721Received() (gas: 64127) ReceiverTest:test__codesize() (gas: 3310) -RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3431797) -RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5845334) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 644465, ~: 504214) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 434126, ~: 390307) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21560698) +RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3436079) +RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5849786) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 695337, ~: 518255) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 416906, ~: 379803) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21566189) RedBlackTreeLibTest:testRedBlackTreeInsertBenchStep() (gas: 3707644) RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint160() (gas: 3473262) RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint256() (gas: 6372882) @@ -934,17 +934,17 @@ RedBlackTreeLibTest:testRedBlackTreeInsertOneGas() (gas: 45595) RedBlackTreeLibTest:testRedBlackTreeInsertTenGas() (gas: 283061) RedBlackTreeLibTest:testRedBlackTreeInsertThreeGas() (gas: 96286) RedBlackTreeLibTest:testRedBlackTreeInsertTwoGas() (gas: 69859) -RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 231594, ~: 225833) -RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 258449, ~: 248963) -RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 225201, ~: 195540) +RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 236505, ~: 227132) +RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 250120, ~: 248880) +RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 219522, ~: 195540) RedBlackTreeLibTest:testRedBlackTreePointers() (gas: 91959) RedBlackTreeLibTest:testRedBlackTreeRejectsEmptyValue() (gas: 3238) -RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58271) +RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58276) RedBlackTreeLibTest:testRedBlackTreeTreeFullReverts() (gas: 50366) -RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56202) +RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56216) RedBlackTreeLibTest:testRedBlackTreeValues() (gas: 191692) -RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 400524, ~: 266954) -RedBlackTreeLibTest:test__codesize() (gas: 14149) +RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 397466, ~: 267330) +RedBlackTreeLibTest:test__codesize() (gas: 14114) ReentrancyGuardTest:testRecursiveDirectUnguardedCall() (gas: 34254) ReentrancyGuardTest:testRecursiveIndirectUnguardedCall() (gas: 47771) ReentrancyGuardTest:testRevertGuardLocked() (gas: 53917) diff --git a/src/utils/RedBlackTreeLib.sol b/src/utils/RedBlackTreeLib.sol index b470bdcbc2..3fcfef04d4 100644 --- a/src/utils/RedBlackTreeLib.sol +++ b/src/utils/RedBlackTreeLib.sol @@ -583,6 +583,17 @@ library RedBlackTreeLib { mstore(0x20, shl(128, sub(last_, 1))) } + function replaceParent(nodes_, parent_, a_, b_) { + if iszero(parent_) { + mstore(0x00, a_) + leave + } + let s_ := or(nodes_, parent_) + let p_ := sload(s_) + let t_ := iszero(eq(b_, getKey(p_, _BITPOS_LEFT))) + sstore(s_, setKey(p_, mul(t_, _BITPOS_RIGHT), a_)) + } + function remove(nodes_, key_) -> err_ { if gt(key_, shr(128, mload(0x20))) { err_ := ERROR_POINTER_OUT_OF_BOUNDS @@ -593,81 +604,49 @@ library RedBlackTreeLib { leave } - let cursor_ := 0 - - for {} 1 {} { + let cursor_ := key_ + { let packed_ := sload(or(nodes_, key_)) let left_ := getKey(packed_, _BITPOS_LEFT) let right_ := getKey(packed_, _BITPOS_RIGHT) - if iszero(mul(left_, right_)) { - cursor_ := key_ - break - } - cursor_ := right_ - for {} 1 {} { - let cursorLeft_ := getKey(sload(or(nodes_, cursor_)), _BITPOS_LEFT) - if iszero(cursorLeft_) { break } - cursor_ := cursorLeft_ + if mul(left_, right_) { + for { cursor_ := right_ } 1 {} { + let cursorLeft_ := getKey(sload(or(nodes_, cursor_)), _BITPOS_LEFT) + if iszero(cursorLeft_) { break } + cursor_ := cursorLeft_ + } } - break } let cursorPacked_ := sload(or(nodes_, cursor_)) let probe_ := getKey(cursorPacked_, _BITPOS_LEFT) - if iszero(probe_) { probe_ := getKey(cursorPacked_, _BITPOS_RIGHT) } - - for { let yParent_ := getKey(cursorPacked_, _BITPOS_PARENT) } 1 {} { - let probeSlot_ := or(nodes_, probe_) - sstore(probeSlot_, setKey(sload(probeSlot_), _BITPOS_PARENT, yParent_)) - - if iszero(yParent_) { - mstore(0x00, probe_) - break - } - let s_ := or(nodes_, yParent_) - let p_ := sload(s_) - let t_ := iszero(eq(cursor_, getKey(p_, _BITPOS_LEFT))) - sstore(s_, setKey(p_, mul(t_, _BITPOS_RIGHT), probe_)) - break - } + probe_ := getKey(cursorPacked_, mul(iszero(probe_), _BITPOS_RIGHT)) - let skipFixup_ := and(_BITMASK_RED, cursorPacked_) + let yParent_ := getKey(cursorPacked_, _BITPOS_PARENT) + let probeSlot_ := or(nodes_, probe_) + sstore(probeSlot_, setKey(sload(probeSlot_), _BITPOS_PARENT, yParent_)) + replaceParent(nodes_, yParent_, probe_, cursor_) if iszero(eq(cursor_, key_)) { let packed_ := sload(or(nodes_, key_)) - let parent_ := getKey(packed_, _BITPOS_PARENT) - for {} 1 {} { - if iszero(parent_) { - mstore(0x00, cursor_) - break - } - let s_ := or(nodes_, parent_) - let p_ := sload(s_) - let t_ := iszero(eq(key_, getKey(p_, _BITPOS_LEFT))) - sstore(s_, setKey(p_, mul(t_, _BITPOS_RIGHT), cursor_)) - break - } + replaceParent(nodes_, getKey(packed_, _BITPOS_PARENT), cursor_, key_) - let left_ := getKey(packed_, _BITPOS_LEFT) - let leftSlot_ := or(nodes_, left_) + let leftSlot_ := or(nodes_, getKey(packed_, _BITPOS_LEFT)) sstore(leftSlot_, setKey(sload(leftSlot_), _BITPOS_PARENT, cursor_)) - let right_ := getKey(packed_, _BITPOS_RIGHT) - let rightSlot_ := or(nodes_, right_) + let rightSlot_ := or(nodes_, getKey(packed_, _BITPOS_RIGHT)) sstore(rightSlot_, setKey(sload(rightSlot_), _BITPOS_PARENT, cursor_)) - let m_ := sub(shl(_BITPOS_PACKED_VALUE, 1), 1) - sstore( - or(nodes_, cursor_), - xor(cursorPacked_, and(xor(packed_, cursorPacked_), m_)) - ) + // Copy `left`, `right`, `red` from `cursor_` to `key_`. + // forgefmt: disable-next-item + sstore(or(nodes_, cursor_), xor(cursorPacked_, + and(xor(packed_, cursorPacked_), sub(shl(_BITPOS_PACKED_VALUE, 1), 1)))) let t_ := cursor_ cursor_ := key_ key_ := t_ } - if iszero(skipFixup_) { removeFixup(nodes_, probe_) } - + if iszero(and(_BITMASK_RED, cursorPacked_)) { removeFixup(nodes_, probe_) } removeLast(nodes_, cursor_) } From da851e7e55abeea3a6042cd70a75d7771309f95b Mon Sep 17 00:00:00 2001 From: Vectorized Date: Tue, 6 Feb 2024 01:00:17 +0000 Subject: [PATCH 4/5] T --- .gas-snapshot | 24 ++++---- src/utils/RedBlackTreeLib.sol | 103 +++++++++++++++++----------------- 2 files changed, 63 insertions(+), 64 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index a8084fe82c..be1df97472 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -922,11 +922,11 @@ ReceiverTest:testOnERC1155BatchReceived() (gas: 48975) ReceiverTest:testOnERC1155Received() (gas: 46717) ReceiverTest:testOnERC721Received() (gas: 64127) ReceiverTest:test__codesize() (gas: 3310) -RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3436079) -RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5849786) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 695337, ~: 518255) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 416906, ~: 379803) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21566189) +RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3432597) +RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5846304) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 686128, ~: 528349) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 423537, ~: 390377) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21559226) RedBlackTreeLibTest:testRedBlackTreeInsertBenchStep() (gas: 3707644) RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint160() (gas: 3473262) RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint256() (gas: 6372882) @@ -934,17 +934,17 @@ RedBlackTreeLibTest:testRedBlackTreeInsertOneGas() (gas: 45595) RedBlackTreeLibTest:testRedBlackTreeInsertTenGas() (gas: 283061) RedBlackTreeLibTest:testRedBlackTreeInsertThreeGas() (gas: 96286) RedBlackTreeLibTest:testRedBlackTreeInsertTwoGas() (gas: 69859) -RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 236505, ~: 227132) -RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 250120, ~: 248880) -RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 219522, ~: 195540) +RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 247471, ~: 227634) +RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 253681, ~: 248938) +RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 229243, ~: 195540) RedBlackTreeLibTest:testRedBlackTreePointers() (gas: 91959) RedBlackTreeLibTest:testRedBlackTreeRejectsEmptyValue() (gas: 3238) -RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58276) +RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58221) RedBlackTreeLibTest:testRedBlackTreeTreeFullReverts() (gas: 50366) -RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56216) +RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56188) RedBlackTreeLibTest:testRedBlackTreeValues() (gas: 191692) -RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 397466, ~: 267330) -RedBlackTreeLibTest:test__codesize() (gas: 14114) +RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 366611, ~: 266718) +RedBlackTreeLibTest:test__codesize() (gas: 14100) ReentrancyGuardTest:testRecursiveDirectUnguardedCall() (gas: 34254) ReentrancyGuardTest:testRecursiveIndirectUnguardedCall() (gas: 47771) ReentrancyGuardTest:testRevertGuardLocked() (gas: 53917) diff --git a/src/utils/RedBlackTreeLib.sol b/src/utils/RedBlackTreeLib.sol index 3fcfef04d4..eda624d7ec 100644 --- a/src/utils/RedBlackTreeLib.sol +++ b/src/utils/RedBlackTreeLib.sol @@ -532,57 +532,6 @@ library RedBlackTreeLib { sstore(or(nodes_, key_), and(sload(or(nodes_, key_)), not(BR))) } - function removeLast(nodes_, cursor_) { - let last_ := shr(128, mload(0x20)) - let lastPacked_ := sload(or(nodes_, last_)) - let lastValue_ := shr(_BITPOS_PACKED_VALUE, lastPacked_) - let lastFullValue_ := 0 - if iszero(lastValue_) { - lastValue_ := sload(or(_BIT_FULL_VALUE_SLOT, or(nodes_, last_))) - lastFullValue_ := lastValue_ - } - - let cursorPacked_ := sload(or(nodes_, cursor_)) - let cursorValue_ := shr(_BITPOS_PACKED_VALUE, cursorPacked_) - let cursorFullValue_ := 0 - if iszero(cursorValue_) { - cursorValue_ := sload(or(_BIT_FULL_VALUE_SLOT, or(nodes_, cursor_))) - cursorFullValue_ := cursorValue_ - } - - if iszero(eq(lastValue_, cursorValue_)) { - sstore(or(nodes_, cursor_), lastPacked_) - if iszero(eq(lastFullValue_, cursorFullValue_)) { - sstore(or(_BIT_FULL_VALUE_SLOT, or(nodes_, cursor_)), lastFullValue_) - } - for { let lastParent_ := getKey(lastPacked_, _BITPOS_PARENT) } 1 {} { - if iszero(lastParent_) { - mstore(0x00, cursor_) - break - } - let s_ := or(nodes_, lastParent_) - let p_ := sload(s_) - let t_ := iszero(eq(last_, getKey(p_, _BITPOS_LEFT))) - sstore(s_, setKey(p_, mul(t_, _BITPOS_RIGHT), cursor_)) - break - } - let lastRight_ := getKey(lastPacked_, _BITPOS_RIGHT) - if lastRight_ { - let s_ := or(nodes_, lastRight_) - sstore(s_, setKey(sload(s_), _BITPOS_PARENT, cursor_)) - } - let lastLeft_ := getKey(lastPacked_, _BITPOS_LEFT) - if lastLeft_ { - let s_ := or(nodes_, lastLeft_) - sstore(s_, setKey(sload(s_), _BITPOS_PARENT, cursor_)) - } - } - sstore(or(nodes_, last_), 0) - if lastFullValue_ { sstore(or(_BIT_FULL_VALUE_SLOT, or(nodes_, last_)), 0) } - - mstore(0x20, shl(128, sub(last_, 1))) - } - function replaceParent(nodes_, parent_, a_, b_) { if iszero(parent_) { mstore(0x00, a_) @@ -646,8 +595,58 @@ library RedBlackTreeLib { cursor_ := key_ key_ := t_ } + if iszero(and(_BITMASK_RED, cursorPacked_)) { removeFixup(nodes_, probe_) } - removeLast(nodes_, cursor_) + + // Remove last workflow: + + let last_ := shr(128, mload(0x20)) + let lastPacked_ := sload(or(nodes_, last_)) + let lastValue_ := shr(_BITPOS_PACKED_VALUE, lastPacked_) + let lastFullValue_ := 0 + if iszero(lastValue_) { + lastValue_ := sload(or(_BIT_FULL_VALUE_SLOT, or(nodes_, last_))) + lastFullValue_ := lastValue_ + } + + let cursorValue_ := shr(_BITPOS_PACKED_VALUE, sload(or(nodes_, cursor_))) + let cursorFullValue_ := 0 + if iszero(cursorValue_) { + cursorValue_ := sload(or(_BIT_FULL_VALUE_SLOT, or(nodes_, cursor_))) + cursorFullValue_ := cursorValue_ + } + + if iszero(eq(lastValue_, cursorValue_)) { + sstore(or(nodes_, cursor_), lastPacked_) + if iszero(eq(lastFullValue_, cursorFullValue_)) { + sstore(or(_BIT_FULL_VALUE_SLOT, or(nodes_, cursor_)), lastFullValue_) + } + for { let lastParent_ := getKey(lastPacked_, _BITPOS_PARENT) } 1 {} { + if iszero(lastParent_) { + mstore(0x00, cursor_) + break + } + let s_ := or(nodes_, lastParent_) + let p_ := sload(s_) + let t_ := iszero(eq(last_, getKey(p_, _BITPOS_LEFT))) + sstore(s_, setKey(p_, mul(t_, _BITPOS_RIGHT), cursor_)) + break + } + let lastRight_ := getKey(lastPacked_, _BITPOS_RIGHT) + if lastRight_ { + let s_ := or(nodes_, lastRight_) + sstore(s_, setKey(sload(s_), _BITPOS_PARENT, cursor_)) + } + let lastLeft_ := getKey(lastPacked_, _BITPOS_LEFT) + if lastLeft_ { + let s_ := or(nodes_, lastLeft_) + sstore(s_, setKey(sload(s_), _BITPOS_PARENT, cursor_)) + } + } + sstore(or(nodes_, last_), 0) + if lastFullValue_ { sstore(or(_BIT_FULL_VALUE_SLOT, or(nodes_, last_)), 0) } + + mstore(0x20, shl(128, sub(last_, 1))) } mstore(0x00, codesize()) // Zeroize the first 0x10 bytes. From 93fa110477f887fe47425dd565d33551fa83f536 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Tue, 6 Feb 2024 01:12:40 +0000 Subject: [PATCH 5/5] T --- .gas-snapshot | 44 +++++++------- src/utils/RedBlackTreeLib.sol | 105 +++++++++++++++++----------------- 2 files changed, 75 insertions(+), 74 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index be1df97472..cf9205e766 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -922,29 +922,29 @@ ReceiverTest:testOnERC1155BatchReceived() (gas: 48975) ReceiverTest:testOnERC1155Received() (gas: 46717) ReceiverTest:testOnERC721Received() (gas: 64127) ReceiverTest:test__codesize() (gas: 3310) -RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3432597) -RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5846304) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 686128, ~: 528349) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 423537, ~: 390377) -RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21559226) -RedBlackTreeLibTest:testRedBlackTreeInsertBenchStep() (gas: 3707644) -RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint160() (gas: 3473262) -RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint256() (gas: 6372882) -RedBlackTreeLibTest:testRedBlackTreeInsertOneGas() (gas: 45595) -RedBlackTreeLibTest:testRedBlackTreeInsertTenGas() (gas: 283061) -RedBlackTreeLibTest:testRedBlackTreeInsertThreeGas() (gas: 96286) -RedBlackTreeLibTest:testRedBlackTreeInsertTwoGas() (gas: 69859) -RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 247471, ~: 227634) -RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 253681, ~: 248938) -RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 229243, ~: 195540) -RedBlackTreeLibTest:testRedBlackTreePointers() (gas: 91959) +RedBlackTreeLibTest:testRedBlackTreeBenchUint160() (gas: 3429423) +RedBlackTreeLibTest:testRedBlackTreeBenchUint256() (gas: 5843130) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove(uint256) (runs: 256, μ: 627514, ~: 487609) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove2(uint256) (runs: 256, μ: 420920, ~: 390160) +RedBlackTreeLibTest:testRedBlackTreeInsertAndRemove3() (gas: 21546528) +RedBlackTreeLibTest:testRedBlackTreeInsertBenchStep() (gas: 3703676) +RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint160() (gas: 3469294) +RedBlackTreeLibTest:testRedBlackTreeInsertBenchUint256() (gas: 6368914) +RedBlackTreeLibTest:testRedBlackTreeInsertOneGas() (gas: 45564) +RedBlackTreeLibTest:testRedBlackTreeInsertTenGas() (gas: 282751) +RedBlackTreeLibTest:testRedBlackTreeInsertThreeGas() (gas: 96193) +RedBlackTreeLibTest:testRedBlackTreeInsertTwoGas() (gas: 69797) +RedBlackTreeLibTest:testRedBlackTreeNearest(uint256) (runs: 256, μ: 228165, ~: 224911) +RedBlackTreeLibTest:testRedBlackTreeNearestAfter(uint256) (runs: 256, μ: 251011, ~: 248814) +RedBlackTreeLibTest:testRedBlackTreeNearestBefore(uint256) (runs: 256, μ: 232084, ~: 195909) +RedBlackTreeLibTest:testRedBlackTreePointers() (gas: 91897) RedBlackTreeLibTest:testRedBlackTreeRejectsEmptyValue() (gas: 3238) -RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58221) -RedBlackTreeLibTest:testRedBlackTreeTreeFullReverts() (gas: 50366) -RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56188) -RedBlackTreeLibTest:testRedBlackTreeValues() (gas: 191692) -RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 366611, ~: 266718) -RedBlackTreeLibTest:test__codesize() (gas: 14100) +RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58172) +RedBlackTreeLibTest:testRedBlackTreeTreeFullReverts() (gas: 50335) +RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56139) +RedBlackTreeLibTest:testRedBlackTreeValues() (gas: 191599) +RedBlackTreeLibTest:testRedBlackTreeValues(uint256) (runs: 256, μ: 383999, ~: 267070) +RedBlackTreeLibTest:test__codesize() (gas: 14087) ReentrancyGuardTest:testRecursiveDirectUnguardedCall() (gas: 34254) ReentrancyGuardTest:testRecursiveIndirectUnguardedCall() (gas: 47771) ReentrancyGuardTest:testRevertGuardLocked() (gas: 53917) diff --git a/src/utils/RedBlackTreeLib.sol b/src/utils/RedBlackTreeLib.sol index eda624d7ec..2243151b1e 100644 --- a/src/utils/RedBlackTreeLib.sol +++ b/src/utils/RedBlackTreeLib.sol @@ -391,7 +391,55 @@ library RedBlackTreeLib { sstore(or(nodes_, cursor_), setKey(cursorPacked_, L, key_)) } - function insertFixup(nodes_, key_) { + function insert(nodes_, cursor_, key_, x_) -> err_ { + if key_ { + err_ := ERROR_VALUE_ALREADY_EXISTS + leave + } + + let totalNodes_ := add(shr(128, mload(0x20)), 1) + if gt(totalNodes_, _BITMASK_KEY) { + err_ := ERROR_TREE_IS_FULL + leave + } + + mstore(0x20, shl(128, totalNodes_)) + + { + let packed_ := or(_BITMASK_RED, shl(_BITPOS_PARENT, cursor_)) + let nodePointer_ := or(nodes_, totalNodes_) + + for {} 1 {} { + if iszero(gt(x_, _BITMASK_PACKED_VALUE)) { + packed_ := or(shl(_BITPOS_PACKED_VALUE, x_), packed_) + break + } + sstore(or(nodePointer_, _BIT_FULL_VALUE_SLOT), x_) + break + } + sstore(nodePointer_, packed_) + + for {} 1 {} { + if iszero(cursor_) { + mstore(0x00, totalNodes_) + break + } + let s_ := or(nodes_, cursor_) + let cPacked_ := sload(s_) + let cValue_ := shr(_BITPOS_PACKED_VALUE, cPacked_) + if iszero(cValue_) { cValue_ := sload(or(s_, _BIT_FULL_VALUE_SLOT)) } + if iszero(lt(x_, cValue_)) { + sstore(s_, setKey(cPacked_, _BITPOS_RIGHT, totalNodes_)) + break + } + sstore(s_, setKey(cPacked_, _BITPOS_LEFT, totalNodes_)) + break + } + } + + // Insert fixup workflow: + + key_ := totalNodes_ let BR := _BITMASK_RED for {} iszero(eq(key_, mload(0x00))) {} { let packed_ := sload(or(nodes_, key_)) @@ -405,9 +453,9 @@ library RedBlackTreeLib { let R := mul(eq(parent_, getKey(grandParentPacked_, 0)), _BITPOS_RIGHT) let L := xor(R, _BITPOS_RIGHT) - let cursor_ := getKey(grandParentPacked_, R) - let cursorPacked_ := sload(or(nodes_, cursor_)) - if iszero(and(BR, cursorPacked_)) { + let c_ := getKey(grandParentPacked_, R) + let cPacked_ := sload(or(nodes_, c_)) + if iszero(and(BR, cPacked_)) { if eq(key_, getKey(parentPacked_, R)) { key_ := parent_ rotate(nodes_, key_, L, R) @@ -422,7 +470,7 @@ library RedBlackTreeLib { continue } sstore(or(nodes_, parent_), and(parentPacked_, not(BR))) - sstore(or(nodes_, cursor_), and(cursorPacked_, not(BR))) + sstore(or(nodes_, c_), and(cPacked_, not(BR))) sstore(or(nodes_, grandParent_), or(grandParentPacked_, BR)) key_ := grandParent_ } @@ -430,53 +478,6 @@ library RedBlackTreeLib { sstore(root_, and(sload(root_), not(BR))) } - function insert(nodes_, cursor_, key_, x_) -> err_ { - if key_ { - err_ := ERROR_VALUE_ALREADY_EXISTS - leave - } - - let totalNodes_ := add(shr(128, mload(0x20)), 1) - - if gt(totalNodes_, _BITMASK_KEY) { - err_ := ERROR_TREE_IS_FULL - leave - } - - mstore(0x20, shl(128, totalNodes_)) - - let packed_ := or(_BITMASK_RED, shl(_BITPOS_PARENT, cursor_)) - let nodePointer_ := or(nodes_, totalNodes_) - - for {} 1 {} { - if iszero(gt(x_, _BITMASK_PACKED_VALUE)) { - packed_ := or(shl(_BITPOS_PACKED_VALUE, x_), packed_) - break - } - sstore(or(nodePointer_, _BIT_FULL_VALUE_SLOT), x_) - break - } - sstore(nodePointer_, packed_) - - for {} 1 {} { - if iszero(cursor_) { - mstore(0x00, totalNodes_) - break - } - let s_ := or(nodes_, cursor_) - let cursorPacked_ := sload(s_) - let cursorValue_ := shr(_BITPOS_PACKED_VALUE, cursorPacked_) - if iszero(cursorValue_) { cursorValue_ := sload(or(s_, _BIT_FULL_VALUE_SLOT)) } - if iszero(lt(x_, cursorValue_)) { - sstore(s_, setKey(cursorPacked_, _BITPOS_RIGHT, totalNodes_)) - break - } - sstore(s_, setKey(cursorPacked_, _BITPOS_LEFT, totalNodes_)) - break - } - insertFixup(nodes_, totalNodes_) - } - function removeFixup(nodes_, key_) { let BR := _BITMASK_RED for {} iszero(eq(key_, mload(0x00))) {} {