44
44
from chia .consensus .cost_calculator import NPCResult
45
45
from chia .consensus .default_constants import DEFAULT_CONSTANTS
46
46
from chia .full_node .bitcoin_fee_estimator import create_bitcoin_fee_estimator
47
- from chia .full_node .eligible_coin_spends import run_for_cost
48
47
from chia .full_node .fee_estimation import EmptyMempoolInfo , MempoolInfo
49
48
from chia .full_node .full_node_api import FullNodeAPI
50
49
from chia .full_node .mempool import Mempool
@@ -2909,14 +2908,7 @@ async def test_invalid_coin_spend_coin(
2909
2908
],
2910
2909
)
2911
2910
def test_items_by_feerate (items : list [MempoolItem ], expected : list [Coin ]) -> None :
2912
- fee_estimator = create_bitcoin_fee_estimator (uint64 (11000000000 ))
2913
-
2914
- mempool_info = MempoolInfo (
2915
- CLVMCost (uint64 (11000000000 * 3 )),
2916
- FeeRate (uint64 (1000000 )),
2917
- CLVMCost (uint64 (11000000000 )),
2918
- )
2919
- mempool = Mempool (mempool_info , fee_estimator )
2911
+ mempool = construct_mempool ()
2920
2912
for i in items :
2921
2913
mempool .add_to_pool (i )
2922
2914
@@ -2934,13 +2926,7 @@ def test_items_by_feerate(items: list[MempoolItem], expected: list[Coin]) -> Non
2934
2926
2935
2927
@pytest .mark .parametrize ("old" , [True , False ])
2936
2928
def test_timeout (old : bool ) -> None :
2937
- fee_estimator = create_bitcoin_fee_estimator (uint64 (11000000000 ))
2938
- mempool_info = MempoolInfo (
2939
- CLVMCost (uint64 (11000000000 * 3 )),
2940
- FeeRate (uint64 (1000000 )),
2941
- CLVMCost (uint64 (11000000000 )),
2942
- )
2943
- mempool = Mempool (mempool_info , fee_estimator )
2929
+ mempool = construct_mempool ()
2944
2930
2945
2931
for i in range (50 ):
2946
2932
item = mk_item (coins [i : i + 1 ], flags = [0 ], fee = 0 , cost = 50 )
@@ -3107,13 +3093,7 @@ def test_limit_expiring_transactions(height: bool, items: list[int], expected: l
3107
3093
],
3108
3094
)
3109
3095
def test_get_items_by_coin_ids (items : list [MempoolItem ], coin_ids : list [bytes32 ], expected : list [MempoolItem ]) -> None :
3110
- fee_estimator = create_bitcoin_fee_estimator (uint64 (11000000000 ))
3111
- mempool_info = MempoolInfo (
3112
- CLVMCost (uint64 (11000000000 * 3 )),
3113
- FeeRate (uint64 (1000000 )),
3114
- CLVMCost (uint64 (11000000000 )),
3115
- )
3116
- mempool = Mempool (mempool_info , fee_estimator )
3096
+ mempool = construct_mempool ()
3117
3097
for i in items :
3118
3098
mempool .add_to_pool (i )
3119
3099
invariant_check_mempool (mempool )
@@ -3127,69 +3107,92 @@ def make_test_spendbundle(coin: Coin, *, fee: int = 0, with_higher_cost: bool =
3127
3107
if with_higher_cost :
3128
3108
conditions .extend ([[ConditionOpcode .CREATE_COIN , IDENTITY_PUZZLE_HASH , i ] for i in range (3 )])
3129
3109
actual_fee += 3
3130
- conditions .append ([ConditionOpcode .CREATE_COIN , IDENTITY_PUZZLE_HASH , coin .amount - actual_fee ])
3110
+ conditions .append ([ConditionOpcode .CREATE_COIN , IDENTITY_PUZZLE_HASH , uint64 ( coin .amount - actual_fee ) ])
3131
3111
sb = spend_bundle_from_conditions (conditions , coin )
3132
3112
return sb
3133
3113
3134
3114
3135
- def test_aggregating_on_a_solution_then_a_more_cost_saving_one_appears () -> None :
3136
- def agg_and_add_sb_returning_cost_info (mempool : Mempool , spend_bundles : list [SpendBundle ]) -> uint64 :
3115
+ def construct_mempool () -> Mempool :
3116
+ fee_estimator = create_bitcoin_fee_estimator (test_constants .MAX_BLOCK_COST_CLVM )
3117
+ mempool_info = MempoolInfo (
3118
+ CLVMCost (uint64 (test_constants .MAX_BLOCK_COST_CLVM * 3 )),
3119
+ FeeRate (uint64 (1000000 )),
3120
+ CLVMCost (test_constants .MAX_BLOCK_COST_CLVM ),
3121
+ )
3122
+ return Mempool (mempool_info , fee_estimator )
3123
+
3124
+
3125
+ def make_coin (idx : int ) -> Coin :
3126
+ return Coin (IDENTITY_PUZZLE_HASH , IDENTITY_PUZZLE_HASH , uint64 (2_000_000_000 + idx * 2 ))
3127
+
3128
+
3129
+ @pytest .mark .parametrize ("old" , [True , False ])
3130
+ def test_dedup_by_fee (old : bool ) -> None :
3131
+ """
3132
+ We pick the solution to use for dedup based on the spendbundle with the highest
3133
+ fee per cost, not based on which one would give the overall best fee per cost
3134
+ """
3135
+ mempool = construct_mempool ()
3136
+
3137
+ def add_spend_bundles (spend_bundles : list [SpendBundle ]) -> None :
3137
3138
sb = SpendBundle .aggregate (spend_bundles )
3138
3139
mi = mempool_item_from_spendbundle (sb )
3139
3140
mempool .add_to_pool (mi )
3140
3141
invariant_check_mempool (mempool )
3141
- saved_cost = run_for_cost (
3142
- sb .coin_spends [0 ].puzzle_reveal , sb .coin_spends [0 ].solution , len (mi .additions ), mi .cost
3143
- )
3144
- return saved_cost
3145
3142
3146
- fee_estimator = create_bitcoin_fee_estimator (uint64 (11000000000 ))
3147
- mempool_info = MempoolInfo (
3148
- CLVMCost (uint64 (11000000000 * 3 )),
3149
- FeeRate (uint64 (1000000 )),
3150
- CLVMCost (uint64 (11000000000 )),
3151
- )
3152
- mempool = Mempool (mempool_info , fee_estimator )
3153
- coins = [
3154
- Coin (IDENTITY_PUZZLE_HASH , IDENTITY_PUZZLE_HASH , uint64 (amount )) for amount in range (2000000000 , 2000000020 , 2 )
3155
- ]
3156
- # Create a ~10 FPC item that spends the eligible coin[0]
3157
- sb_A = make_test_spendbundle (coins [0 ])
3158
- highest_fee = 58282830
3159
- sb_high_rate = make_test_spendbundle (coins [1 ], fee = highest_fee )
3160
- agg_and_add_sb_returning_cost_info (mempool , [sb_A , sb_high_rate ])
3161
- invariant_check_mempool (mempool )
3162
- # Create a ~2 FPC item that spends the eligible coin using the same solution A
3163
- sb_low_rate = make_test_spendbundle (coins [2 ], fee = highest_fee // 5 )
3164
- saved_cost_on_solution_A = agg_and_add_sb_returning_cost_info (mempool , [sb_A , sb_low_rate ])
3165
- invariant_check_mempool (mempool )
3166
- result = mempool .create_bundle_from_mempool_items (test_constants , uint32 (0 ))
3143
+ DEDUP_COIN = make_coin (0 )
3144
+ COIN_A1 = make_coin (1 )
3145
+ COIN_A2 = make_coin (2 )
3146
+ # all other coins belong to solution B, the dedup alternative to solution A
3147
+
3148
+ # Create a spend bundle with a high fee, spending sb_A, which supports dedup
3149
+ sb_A = make_test_spendbundle (DEDUP_COIN )
3150
+ sb_high_rate = make_test_spendbundle (COIN_A1 , fee = 10 )
3151
+ add_spend_bundles ([sb_A , sb_high_rate ])
3152
+
3153
+ # Create a spend bundle, with a low fee, that spends the dedup coin using the same solution A
3154
+ sb_low_rate = make_test_spendbundle (COIN_A2 , fee = 10 )
3155
+ add_spend_bundles ([sb_A , sb_low_rate ])
3156
+
3157
+ create_block = mempool .create_block_generator if old else mempool .create_block_generator2
3158
+ # validate that dedup happens at all for sb_A
3159
+ result = create_block (test_constants , uint32 (0 ), 5.0 )
3167
3160
assert result is not None
3168
- agg , _ = result
3169
3161
# Make sure both items would be processed
3170
- assert [c .coin for c in agg .coin_spends ] == [coins [0 ], coins [1 ], coins [2 ]]
3171
- # Now let's add 3 x ~3 FPC items that spend the eligible coin differently
3172
- # (solution B). It creates a higher (saved) cost than solution A
3173
- sb_B = make_test_spendbundle (coins [0 ], with_higher_cost = True )
3174
- for i in range (3 , 6 ):
3175
- # We're picking this fee to get a ~3 FPC, and get picked after sb_A1
3176
- # (which has ~10 FPC) but before sb_A2 (which has ~2 FPC)
3177
- sb_mid_rate = make_test_spendbundle (coins [i ], fee = 38004852 - i )
3178
- saved_cost_on_solution_B = agg_and_add_sb_returning_cost_info (mempool , [sb_B , sb_mid_rate ])
3179
- invariant_check_mempool (mempool )
3180
- # We'd save more cost if we went with solution B instead of A
3181
- assert saved_cost_on_solution_B > saved_cost_on_solution_A
3182
- # If we process everything now, the 3 x ~3 FPC items get skipped because
3183
- # sb_A1 gets picked before them (~10 FPC), so from then on only sb_A2 (~2 FPC)
3184
- # would get picked
3185
- result = mempool .create_bundle_from_mempool_items (test_constants , uint32 (0 ))
3162
+ assert result .removals == [DEDUP_COIN , COIN_A1 , COIN_A2 ]
3163
+
3164
+ # Now we add a bunch of alternative spends for coin 0, with lower fees
3165
+ # Even though the total fee would be higher if we deduped on this solution,
3166
+ # we won't.
3167
+ sb_B = make_test_spendbundle (DEDUP_COIN , with_higher_cost = True )
3168
+ for i in range (3 , 600 ):
3169
+ sb_high_rate = make_test_spendbundle (make_coin (i ), fee = 10 )
3170
+ add_spend_bundles ([sb_B , sb_high_rate ])
3171
+
3172
+ result = create_block (test_constants , uint32 (0 ), 5.0 )
3186
3173
assert result is not None
3187
- agg , _ = result
3188
- # The 3 items got skipped here
3189
3174
# We ran with solution A and missed bigger savings on solution B
3190
- assert mempool .size () == 5
3191
- assert [c .coin for c in agg .coin_spends ] == [coins [0 ], coins [1 ], coins [2 ]]
3192
- invariant_check_mempool (mempool )
3175
+ # we've added 599 spend bundles now. 2 with solution A and 598 with solution B
3176
+ assert mempool .size () == 599
3177
+ assert result .removals == [DEDUP_COIN , COIN_A1 , COIN_A2 ]
3178
+
3179
+ # Now, if we add a high fee per-cost-for sb_B, it should be picked
3180
+ sb_high_rate = make_test_spendbundle (make_coin (600 ), fee = 1_000_000_000 )
3181
+ add_spend_bundles ([sb_B , sb_high_rate ])
3182
+
3183
+ result = create_block (test_constants , uint32 (0 ), 5.0 )
3184
+ assert result is not None
3185
+ # The 3 items got skipped here
3186
+ # We ran with solution B
3187
+ # we've added 600 spend bundles now. 2 with solution A and 599 with solution B
3188
+ assert mempool .size () == 600
3189
+ spends_in_block = set (result .removals )
3190
+ assert DEDUP_COIN in spends_in_block
3191
+ assert COIN_A1 not in spends_in_block
3192
+ assert COIN_A2 not in spends_in_block
3193
+
3194
+ for i in range (3 , 601 ):
3195
+ assert make_coin (i ) in spends_in_block
3193
3196
3194
3197
3195
3198
def test_get_puzzle_and_solution_for_coin_failure () -> None :
@@ -3210,14 +3213,7 @@ def test_get_puzzle_and_solution_for_coin_failure() -> None:
3210
3213
3211
3214
@pytest .mark .parametrize ("old" , [True , False ])
3212
3215
def test_create_block_generator (old : bool ) -> None :
3213
- mempool_info = MempoolInfo (
3214
- CLVMCost (uint64 (11000000000 * 3 )),
3215
- FeeRate (uint64 (1000000 )),
3216
- CLVMCost (uint64 (11000000000 )),
3217
- )
3218
-
3219
- fee_estimator = create_bitcoin_fee_estimator (test_constants .MAX_BLOCK_COST_CLVM )
3220
- mempool = Mempool (mempool_info , fee_estimator )
3216
+ mempool = construct_mempool ()
3221
3217
coins = [
3222
3218
Coin (IDENTITY_PUZZLE_HASH , IDENTITY_PUZZLE_HASH , uint64 (amount )) for amount in range (2000000000 , 2000000020 , 2 )
3223
3219
]
0 commit comments