Mempool private implementation (#14593)

* fix test asserts to not require the same object, just the same value

* make Mempool's implementation private and give it a public interface

* fixup test that used to count fee *levels* but now count transactions
This commit is contained in:
Arvid Norberg 2023-02-22 19:26:04 +01:00 committed by GitHub
parent 1a722be39b
commit ed8cee2b4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 163 additions and 141 deletions

View File

@ -14,6 +14,7 @@ from chia.consensus.cost_calculator import NPCResult
from chia.consensus.default_constants import DEFAULT_CONSTANTS
from chia.full_node.bundle_tools import simple_solution_generator
from chia.full_node.coin_store import CoinStore
from chia.full_node.mempool import Mempool
from chia.full_node.mempool_check_conditions import get_name_puzzle_conditions, get_puzzle_and_solution_for_coin
from chia.full_node.mempool_manager import MempoolManager
from chia.types.blockchain_format.coin import Coin
@ -225,9 +226,8 @@ class SpendSim:
) -> Tuple[List[Coin], List[Coin]]:
# Fees get calculated
fees = uint64(0)
if self.mempool_manager.mempool.spends:
for _, item in self.mempool_manager.mempool.spends.items():
fees = uint64(fees + item.spend_bundle.fees())
for item in self.mempool_manager.mempool.all_spends():
fees = uint64(fees + item.fee)
# Rewards get created
next_block_height: uint32 = uint32(self.block_height + 1) if len(self.block_records) > 0 else self.block_height
@ -251,7 +251,7 @@ class SpendSim:
generator_bundle: Optional[SpendBundle] = None
return_additions: List[Coin] = []
return_removals: List[Coin] = []
if (len(self.block_records) > 0) and (self.mempool_manager.mempool.spends):
if (len(self.block_records) > 0) and (self.mempool_manager.mempool.size() > 0):
peak = self.mempool_manager.peak
if peak is not None:
result = self.mempool_manager.create_bundle_from_mempool(peak.header_hash, item_inclusion_filter)
@ -300,7 +300,8 @@ class SpendSim:
self.block_records = new_br_list
self.blocks = new_block_list
await self.coin_store.rollback_to_block(block_height)
self.mempool_manager.mempool.spends = {}
old_pool = self.mempool_manager.mempool
self.mempool_manager.mempool = Mempool(old_pool.mempool_info, old_pool.fee_estimator)
self.block_height = block_height
if new_br_list:
self.timestamp = new_br_list[-1].timestamp
@ -429,12 +430,12 @@ class SimClient:
return CoinSpend(coin_record.coin, puzzle, solution)
async def get_all_mempool_tx_ids(self) -> List[bytes32]:
return list(self.service.mempool_manager.mempool.spends.keys())
return self.service.mempool_manager.mempool.all_spend_ids()
async def get_all_mempool_items(self) -> Dict[bytes32, MempoolItem]:
spends = {}
for tx_id, item in self.service.mempool_manager.mempool.spends.items():
spends[tx_id] = item
for item in self.service.mempool_manager.mempool.all_spends():
spends[item.name] = item
return spends
async def get_mempool_item_by_tx_id(self, tx_id: bytes32) -> Optional[Dict[str, Any]]:

View File

@ -2238,8 +2238,8 @@ class FullNode:
if status == MempoolInclusionStatus.SUCCESS:
self.log.debug(
f"Added transaction to mempool: {spend_name} mempool size: "
f"{self.mempool_manager.mempool.total_mempool_cost} normalized "
f"{self.mempool_manager.mempool.total_mempool_cost / 5000000}"
f"{self.mempool_manager.mempool.total_mempool_cost()} normalized "
f"{self.mempool_manager.mempool.total_mempool_cost() / 5000000}"
)
# Only broadcast successful transactions, not pending ones. Otherwise it's a DOS

View File

@ -1,6 +1,5 @@
from __future__ import annotations
import logging
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional
@ -24,14 +23,46 @@ class MempoolRemoveReason(Enum):
class Mempool:
def __init__(self, mempool_info: MempoolInfo, fee_estimator: FeeEstimatorInterface):
self.log: logging.Logger = logging.getLogger(__name__)
self.spends: Dict[bytes32, MempoolItem] = {}
self.sorted_spends: SortedDict = SortedDict()
self._spends: Dict[bytes32, MempoolItem] = {}
self._sorted_spends: SortedDict = SortedDict()
self.mempool_info: MempoolInfo = mempool_info
self.fee_estimator: FeeEstimatorInterface = fee_estimator
self.removal_coin_id_to_spendbundle_ids: Dict[bytes32, List[bytes32]] = {}
self.total_mempool_cost: CLVMCost = CLVMCost(uint64(0))
self.total_mempool_fees: int = 0
self._removal_coin_id_to_spendbundle_ids: Dict[bytes32, List[bytes32]] = {}
self._total_mempool_cost: CLVMCost = CLVMCost(uint64(0))
self._total_mempool_fees: int = 0
def total_mempool_fees(self) -> int:
return self._total_mempool_fees
def total_mempool_cost(self) -> CLVMCost:
return self._total_mempool_cost
def all_spends(self) -> List[MempoolItem]:
return list(self._spends.values())
def all_spend_ids(self) -> List[bytes32]:
return list(self._spends.keys())
def spends_by_feerate(self) -> List[MempoolItem]:
ret: List[MempoolItem] = []
for spends_with_fpc in reversed(self._sorted_spends.values()):
ret.extend(spends_with_fpc.values())
return ret
def size(self) -> int:
return len(self._spends)
def get_spend_by_id(self, spend_bundle_id: bytes32) -> Optional[MempoolItem]:
return self._spends.get(spend_bundle_id, None)
def get_spends_by_coin_id(self, spent_coin_id: bytes32) -> List[MempoolItem]:
spend_bundle_ids = self._removal_coin_id_to_spendbundle_ids.get(spent_coin_id)
if spend_bundle_ids is None:
return []
ret: List[MempoolItem] = []
for spend_bundle_id in spend_bundle_ids:
ret.append(self._spends[spend_bundle_id])
return ret
def get_min_fee_rate(self, cost: int) -> float:
"""
@ -39,11 +70,11 @@ class Mempool:
"""
if self.at_full_capacity(cost):
current_cost = self.total_mempool_cost
current_cost = self._total_mempool_cost
# Iterates through all spends in increasing fee per cost
fee_per_cost: float
for fee_per_cost, spends_with_fpc in self.sorted_spends.items():
for fee_per_cost, spends_with_fpc in self._sorted_spends.items():
for spend_name, item in spends_with_fpc.items():
current_cost -= item.cost
# Removing one at a time, until our transaction of size cost fits
@ -60,25 +91,25 @@ class Mempool:
Removes an item from the mempool.
"""
for spend_bundle_id in items:
item: Optional[MempoolItem] = self.spends.get(spend_bundle_id)
item: Optional[MempoolItem] = self._spends.get(spend_bundle_id)
if item is None:
continue
assert item.name == spend_bundle_id
removals: List[Coin] = item.removals
for rem in removals:
rem_name: bytes32 = rem.name()
self.removal_coin_id_to_spendbundle_ids[rem_name].remove(spend_bundle_id)
if len(self.removal_coin_id_to_spendbundle_ids[rem_name]) == 0:
del self.removal_coin_id_to_spendbundle_ids[rem_name]
del self.spends[item.name]
del self.sorted_spends[item.fee_per_cost][item.name]
dic = self.sorted_spends[item.fee_per_cost]
self._removal_coin_id_to_spendbundle_ids[rem_name].remove(spend_bundle_id)
if len(self._removal_coin_id_to_spendbundle_ids[rem_name]) == 0:
del self._removal_coin_id_to_spendbundle_ids[rem_name]
del self._spends[item.name]
del self._sorted_spends[item.fee_per_cost][item.name]
dic = self._sorted_spends[item.fee_per_cost]
if len(dic.values()) == 0:
del self.sorted_spends[item.fee_per_cost]
self.total_mempool_cost = CLVMCost(uint64(self.total_mempool_cost - item.cost))
self.total_mempool_fees = self.total_mempool_fees - item.fee
assert self.total_mempool_cost >= 0
info = FeeMempoolInfo(self.mempool_info, self.total_mempool_cost, self.total_mempool_fees, datetime.now())
del self._sorted_spends[item.fee_per_cost]
self._total_mempool_cost = CLVMCost(uint64(self._total_mempool_cost - item.cost))
self._total_mempool_fees = self._total_mempool_fees - item.fee
assert self._total_mempool_cost >= 0
info = FeeMempoolInfo(self.mempool_info, self._total_mempool_cost, self._total_mempool_fees, datetime.now())
if reason != MempoolRemoveReason.BLOCK_INCLUSION:
self.fee_estimator.remove_mempool_item(info, item)
@ -91,27 +122,27 @@ class Mempool:
while self.at_full_capacity(item.cost):
# Val is Dict[hash, MempoolItem]
fee_per_cost, val = self.sorted_spends.peekitem(index=0)
fee_per_cost, val = self._sorted_spends.peekitem(index=0)
to_remove: MempoolItem = list(val.values())[0]
self.remove_from_pool([to_remove.name], MempoolRemoveReason.POOL_FULL)
self.spends[item.name] = item
self._spends[item.name] = item
# sorted_spends is Dict[float, Dict[bytes32, MempoolItem]]
if item.fee_per_cost not in self.sorted_spends:
self.sorted_spends[item.fee_per_cost] = {}
# _sorted_spends is Dict[float, Dict[bytes32, MempoolItem]]
if item.fee_per_cost not in self._sorted_spends:
self._sorted_spends[item.fee_per_cost] = {}
self.sorted_spends[item.fee_per_cost][item.name] = item
self._sorted_spends[item.fee_per_cost][item.name] = item
for coin in item.removals:
coin_id = coin.name()
if coin_id not in self.removal_coin_id_to_spendbundle_ids:
self.removal_coin_id_to_spendbundle_ids[coin_id] = []
self.removal_coin_id_to_spendbundle_ids[coin_id].append(item.name)
if coin_id not in self._removal_coin_id_to_spendbundle_ids:
self._removal_coin_id_to_spendbundle_ids[coin_id] = []
self._removal_coin_id_to_spendbundle_ids[coin_id].append(item.name)
self.total_mempool_cost = CLVMCost(uint64(self.total_mempool_cost + item.cost))
self.total_mempool_fees = self.total_mempool_fees + item.fee
info = FeeMempoolInfo(self.mempool_info, self.total_mempool_cost, self.total_mempool_fees, datetime.now())
self._total_mempool_cost = CLVMCost(uint64(self._total_mempool_cost + item.cost))
self._total_mempool_fees = self._total_mempool_fees + item.fee
info = FeeMempoolInfo(self.mempool_info, self._total_mempool_cost, self._total_mempool_fees, datetime.now())
self.fee_estimator.add_mempool_item(info, item)
def at_full_capacity(self, cost: int) -> bool:
@ -119,4 +150,4 @@ class Mempool:
Checks whether the mempool is at full capacity and cannot accept a transaction with size cost.
"""
return self.total_mempool_cost + cost > self.mempool_info.max_size_in_cost
return self._total_mempool_cost + cost > self.mempool_info.max_size_in_cost

View File

@ -177,21 +177,17 @@ class MempoolManager:
spend_bundles: List[SpendBundle] = []
removals: List[Coin] = []
additions: List[Coin] = []
for dic in reversed(self.mempool.sorted_spends.values()):
for item in dic.values():
if not item_inclusion_filter(self, item):
continue
log.info(f"Cumulative cost: {cost_sum}, fee per cost: {item.fee / item.cost}")
if (
item.cost + cost_sum > self.max_block_clvm_cost
or item.fee + fee_sum > self.constants.MAX_COIN_AMOUNT
):
return (spend_bundles, uint64(cost_sum), additions, removals)
spend_bundles.append(item.spend_bundle)
cost_sum += item.cost
fee_sum += item.fee
removals.extend(item.removals)
additions.extend(item.additions)
for item in self.mempool.spends_by_feerate():
if not item_inclusion_filter(self, item):
continue
log.info(f"Cumulative cost: {cost_sum}, fee per cost: {item.fee / item.cost}")
if item.cost + cost_sum > self.max_block_clvm_cost or item.fee + fee_sum > self.constants.MAX_COIN_AMOUNT:
return (spend_bundles, uint64(cost_sum), additions, removals)
spend_bundles.append(item.spend_bundle)
cost_sum += item.cost
fee_sum += item.fee
removals.extend(item.removals)
additions.extend(item.additions)
return (spend_bundles, uint64(cost_sum), additions, removals)
def create_bundle_from_mempool(
@ -227,7 +223,7 @@ class MempoolManager:
def get_filter(self) -> bytes:
all_transactions: Set[bytes32] = set()
byte_array_list = []
for key, _ in self.mempool.spends.items():
for key in self.mempool.all_spend_ids():
if key not in all_transactions:
all_transactions.add(key)
byte_array_list.append(bytearray(key))
@ -366,10 +362,9 @@ class MempoolManager:
"""
# Skip if already added
if spend_name in self.mempool.spends:
cost: Optional[uint64] = self.mempool.spends[spend_name].cost
assert cost is not None
return uint64(cost), MempoolInclusionStatus.SUCCESS, None
existing_item = self.mempool.get_spend_by_id(spend_name)
if existing_item is not None:
return existing_item.cost, MempoolInclusionStatus.SUCCESS, None
err, item, remove_items = await self.validate_spend_bundle(
new_spend, npc_result, spend_name, first_added_height
@ -529,9 +524,8 @@ class MempoolManager:
if fail_reason is Err.MEMPOOL_CONFLICT:
for conflicting in conflicts:
for c_sb_id in self.mempool.removal_coin_id_to_spendbundle_ids[conflicting.name()]:
sb: MempoolItem = self.mempool.spends[c_sb_id]
conflicting_pool_items[sb.name] = sb
for item in self.mempool.get_spends_by_coin_id(conflicting.name()):
conflicting_pool_items[item.name] = item
log.debug(f"Replace attempted. number of MempoolItems: {len(conflicting_pool_items)}")
if not self.can_replace(conflicting_pool_items, removal_record_dict, fees, fees_per_cost):
return Err.MEMPOOL_CONFLICT, potential, []
@ -562,7 +556,8 @@ class MempoolManager:
if record.spent:
return Err.DOUBLE_SPEND, []
# 2. Checks if there's a mempool conflict
if removal.name() in self.mempool.removal_coin_id_to_spendbundle_ids:
items: List[MempoolItem] = self.mempool.get_spends_by_coin_id(removal.name())
if len(items) > 0:
conflicts.append(removal)
if len(conflicts) > 0:
@ -572,8 +567,9 @@ class MempoolManager:
def get_spendbundle(self, bundle_hash: bytes32) -> Optional[SpendBundle]:
"""Returns a full SpendBundle if it's inside one the mempools"""
if bundle_hash in self.mempool.spends:
return self.mempool.spends[bundle_hash].spend_bundle
item: Optional[MempoolItem] = self.mempool.get_spend_by_id(bundle_hash)
if item is not None:
return item.spend_bundle
return None
def get_mempool_item(self, bundle_hash: bytes32, include_pending: bool = False) -> Optional[MempoolItem]:
@ -583,7 +579,7 @@ class MempoolManager:
If include_pending is specified, also check the PENDING cache.
"""
item = self.mempool.spends.get(bundle_hash, None)
item = self.mempool.get_spend_by_id(bundle_hash)
if not item and include_pending:
# no async lock needed since we're not mutating the pending_cache
item = self._pending_cache.get(bundle_hash)
@ -614,24 +610,19 @@ class MempoolManager:
if use_optimization and last_npc_result is not None:
# We don't reinitialize a mempool, just kick removed items
if last_npc_result.conds is not None:
spendbundle_ids_to_remove = []
spendbundle_ids_to_remove: List[bytes32] = []
for spend in last_npc_result.conds.spends:
if spend.coin_id in self.mempool.removal_coin_id_to_spendbundle_ids:
spendbundle_ids: List[bytes32] = self.mempool.removal_coin_id_to_spendbundle_ids[
bytes32(spend.coin_id)
]
spendbundle_ids_to_remove.extend(spendbundle_ids)
for spendbundle_id in spendbundle_ids:
item = self.mempool.spends.get(spendbundle_id)
if item:
included_items.append(item)
self.remove_seen(spendbundle_id)
items: List[MempoolItem] = self.mempool.get_spends_by_coin_id(bytes32(spend.coin_id))
for item in items:
included_items.append(item)
self.remove_seen(item.name)
spendbundle_ids_to_remove.append(item.name)
self.mempool.remove_from_pool(spendbundle_ids_to_remove, MempoolRemoveReason.BLOCK_INCLUSION)
else:
old_pool = self.mempool
self.mempool = Mempool(old_pool.mempool_info, old_pool.fee_estimator)
self.seen_bundle_hashes = {}
for item in old_pool.spends.values():
for item in old_pool.all_spends():
_, result, err = await self.add_spend_bundle(
item.spend_bundle, item.npc_result, item.spend_bundle_name, item.height_added_to_mempool
)
@ -655,8 +646,8 @@ class MempoolManager:
if status == MempoolInclusionStatus.SUCCESS:
txs_added.append((item.spend_bundle, item.npc_result, item.spend_bundle_name))
log.info(
f"Size of mempool: {len(self.mempool.spends)} spends, "
f"cost: {self.mempool.total_mempool_cost} "
f"Size of mempool: {self.mempool.size()} spends, "
f"cost: {self.mempool.total_mempool_cost()} "
f"minimum fee rate (in FPC) to get in for 5M cost tx: {self.mempool.get_min_fee_rate(5000000)}"
)
self.mempool.fee_estimator.new_block(FeeBlockInfo(new_peak.height, included_items))
@ -668,11 +659,11 @@ class MempoolManager:
assert limit > 0
# Send 100 with the highest fee per cost
for dic in reversed(self.mempool.sorted_spends.values()):
for item in dic.values():
if len(items) == limit:
return items
if mempool_filter.Match(bytearray(item.spend_bundle_name)):
continue
items.append(item.spend_bundle)
for item in self.mempool.spends_by_feerate():
if len(items) >= limit:
return items
if mempool_filter.Match(bytearray(item.spend_bundle_name)):
continue
items.append(item.spend_bundle)
return items

View File

@ -179,9 +179,9 @@ class FullNodeRpcApi:
space = {"space": uint128(0)}
if self.service.mempool_manager is not None:
mempool_size = len(self.service.mempool_manager.mempool.spends)
mempool_cost = self.service.mempool_manager.mempool.total_mempool_cost
mempool_fees = self.service.mempool_manager.mempool.total_mempool_fees
mempool_size = self.service.mempool_manager.mempool.size()
mempool_cost = self.service.mempool_manager.mempool.total_mempool_cost()
mempool_fees = self.service.mempool_manager.mempool.total_mempool_fees()
mempool_min_fee_5m = self.service.mempool_manager.mempool.get_min_fee_rate(5000000)
mempool_max_total_cost = self.service.mempool_manager.mempool_max_total_cost
else:
@ -725,13 +725,13 @@ class FullNodeRpcApi:
}
async def get_all_mempool_tx_ids(self, request: Dict) -> EndpointResult:
ids = list(self.service.mempool_manager.mempool.spends.keys())
ids = list(self.service.mempool_manager.mempool.all_spend_ids())
return {"tx_ids": ids}
async def get_all_mempool_items(self, request: Dict) -> EndpointResult:
spends = {}
for tx_id, item in self.service.mempool_manager.mempool.spends.items():
spends[tx_id.hex()] = item
for item in self.service.mempool_manager.mempool.all_spends():
spends[item.name.hex()] = item
return {"mempool_items": spends}
async def get_mempool_item_by_tx_id(self, request: Dict) -> EndpointResult:
@ -812,9 +812,9 @@ class FullNodeRpcApi:
# such as estimating a higher fee for a longer transaction time.
estimates = make_monotonically_decreasing(estimates)
current_fee_rate = estimator.estimate_fee_rate(time_offset_seconds=1)
mempool_size = self.service.mempool_manager.mempool.total_mempool_cost
mempool_fees = self.service.mempool_manager.mempool.total_mempool_fees
num_mempool_spends = len(self.service.mempool_manager.mempool.spends)
mempool_size = self.service.mempool_manager.mempool.total_mempool_cost()
mempool_fees = self.service.mempool_manager.mempool.total_mempool_fees()
num_mempool_spends = self.service.mempool_manager.mempool.size()
mempool_max_size = estimator.mempool_max_size()
blockchain_state = await self.get_blockchain_state({})
synced = blockchain_state["blockchain_state"]["sync"]["synced"]

View File

@ -131,7 +131,7 @@ class FullNodeSimulator(FullNodeAPI):
config["simulator"]["auto_farm"] = self.auto_farm
save_config(self.bt.root_path, "config.yaml", config)
self.config = config
if self.auto_farm is True and self.full_node.mempool_manager.mempool.total_mempool_cost > 0:
if self.auto_farm is True and self.full_node.mempool_manager.mempool.total_mempool_cost() > 0:
# if mempool is not empty and auto farm was just enabled, farm a block
await self.farm_new_transaction_block(FarmNewBlockProtocol(self.bt.farmer_ph))
return self.auto_farm

View File

@ -55,7 +55,7 @@ class TestBlockchainTransactions:
await full_node_api_1.send_transaction(tx)
sb = full_node_1.mempool_manager.get_spendbundle(spend_bundle.name())
assert sb is spend_bundle
assert sb == spend_bundle
last_block = blocks[-1]
next_spendbundle, additions, removals = full_node_1.mempool_manager.create_bundle_from_mempool(

View File

@ -116,7 +116,7 @@ async def farm_block_with_spend(
def check_mempool_spend_count(full_node_api: FullNodeSimulator, num_of_spends: int) -> bool:
return len(full_node_api.full_node.mempool_manager.mempool.sorted_spends) == num_of_spends
return full_node_api.full_node.mempool_manager.mempool.size() == num_of_spends
async def check_singleton_confirmed(dl: DataLayer, tree_id: bytes32) -> bool:
@ -591,7 +591,7 @@ async def test_get_owned_stores(
launcher_id = bytes32.from_hexstr(res["id"])
expected_store_ids.append(launcher_id)
await time_out_assert(4, check_mempool_spend_count, True, full_node_api, 1)
await time_out_assert(4, check_mempool_spend_count, True, full_node_api, 3)
for i in range(0, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
await asyncio.sleep(0.5)

View File

@ -419,7 +419,7 @@ class TestMempoolManager:
assert status == expected
if expected == MempoolInclusionStatus.SUCCESS:
assert mempool_bundle is bundle
assert mempool_bundle == bundle
assert err is None
else:
assert mempool_bundle is None
@ -446,7 +446,7 @@ class TestMempoolManager:
mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(bundle.name())
assert err is None
assert mempool_bundle is bundle
assert mempool_bundle == bundle
assert status == MempoolInclusionStatus.SUCCESS
# this test makes sure that one spend successfully asserts the announce from
@ -470,7 +470,7 @@ class TestMempoolManager:
mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(bundle.name())
assert err is None
assert mempool_bundle is bundle
assert mempool_bundle == bundle
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -763,7 +763,7 @@ class TestMempoolManager:
blocks, spend_bundle1, peer, status, err = await self.condition_tester(one_node_one_block, wallet_a, dic)
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -789,7 +789,7 @@ class TestMempoolManager:
blocks, spend_bundle1, peer, status, err = await self.condition_tester(one_node_one_block, wallet_a, dic)
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -830,7 +830,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -862,7 +862,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -881,7 +881,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -950,7 +950,7 @@ class TestMempoolManager:
blocks, spend_bundle1, peer, status, err = await self.condition_tester(one_node_one_block, wallet_a, dic)
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -993,7 +993,7 @@ class TestMempoolManager:
blocks, spend_bundle1, peer, status, err = await self.condition_tester(one_node_one_block, wallet_a, dic)
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -1049,7 +1049,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -1095,7 +1095,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
# ensure one spend can assert a coin announcement from another spend
@ -1118,7 +1118,7 @@ class TestMempoolManager:
mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(bundle.name())
assert err is None
assert mempool_bundle is bundle
assert mempool_bundle == bundle
assert status == MempoolInclusionStatus.SUCCESS
# ensure one spend can assert a coin announcement from another spend, even
@ -1163,7 +1163,7 @@ class TestMempoolManager:
assert status == expected_included
if status == MempoolInclusionStatus.SUCCESS:
mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(bundle.name())
assert mempool_bundle is bundle
assert mempool_bundle == bundle
@pytest.mark.asyncio
async def test_coin_announcement_missing_arg(self, one_node_one_block, wallet_a):
@ -1321,7 +1321,7 @@ class TestMempoolManager:
mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(bundle.name())
assert err is None
assert mempool_bundle is bundle
assert mempool_bundle == bundle
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -1365,7 +1365,7 @@ class TestMempoolManager:
assert status == expected_included
if status == MempoolInclusionStatus.SUCCESS:
mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle(bundle.name())
assert mempool_bundle is bundle
assert mempool_bundle == bundle
@pytest.mark.asyncio
async def test_puzzle_announcement_missing_arg(self, one_node_one_block, wallet_a):
@ -1741,7 +1741,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -1818,7 +1818,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio
@ -1893,7 +1893,7 @@ class TestMempoolManager:
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert err is None
assert sb1 is spend_bundle1
assert sb1 == spend_bundle1
assert status == MempoolInclusionStatus.SUCCESS
@pytest.mark.asyncio

View File

@ -162,4 +162,4 @@ async def test_total_mempool_fees() -> None:
assert result[1] == MempoolInclusionStatus.SUCCESS
# Total fees should be coin1's amount plus coin2's amount minus two mojos
# for the created coins
assert mempool_manager.mempool.total_mempool_fees == 0xFFFFFFFFFFFFFFFF + 3 - 2
assert mempool_manager.mempool.total_mempool_fees() == 0xFFFFFFFFFFFFFFFF + 3 - 2

View File

@ -81,11 +81,11 @@ async def init_test(
async def test_mempool_inclusion_filter_basic() -> None:
async with sim_and_client(defaults=NEW_DEFAULT_CONSTANTS, pass_prefarm=False) as (sim, cli):
estimator, spend_coins, fee_coins = await init_test(sim, cli, the_puzzle_hash, 1)
assert len(sim.mempool_manager.mempool.spends) == 0
assert sim.mempool_manager.mempool.size() == 0
spend_bundle: SpendBundle = make_tx_sb(spend_coins[0])
status, error = await cli.push_tx(spend_bundle)
assert len(sim.mempool_manager.mempool.spends) == 1
assert sim.mempool_manager.mempool.size() == 1
assert error is None
mempool_item = sim.mempool_manager.get_mempool_item(spend_bundle.name())
@ -98,11 +98,11 @@ async def test_mempool_inclusion_filter_basic() -> None:
return True
additions, removals = await sim.farm_block(the_puzzle_hash, item_inclusion_filter=include_none)
assert len(sim.mempool_manager.mempool.spends) == 1
assert sim.mempool_manager.mempool.size() == 1
assert removals == []
additions, removals = await sim.farm_block(the_puzzle_hash, item_inclusion_filter=include_all)
assert len(sim.mempool_manager.mempool.spends) == 0
assert sim.mempool_manager.mempool.size() == 0
removal_ids = [c.name() for c in removals]
assert mempool_item.name not in removal_ids
@ -111,12 +111,12 @@ async def test_mempool_inclusion_filter_basic() -> None:
async def test_mempoolitem_height_added(db_version: int) -> None:
async with sim_and_client(defaults=NEW_DEFAULT_CONSTANTS, pass_prefarm=False) as (sim, cli):
estimator, spend_coins, fee_coins = await init_test(sim, cli, the_puzzle_hash, 1)
assert len(sim.mempool_manager.mempool.spends) == 0
assert sim.mempool_manager.mempool.size() == 0
spend_bundle: SpendBundle = make_tx_sb(spend_coins[0])
status, error = await cli.push_tx(spend_bundle)
assert len(sim.mempool_manager.mempool.spends) == 1
assert sim.mempool_manager.mempool.size() == 1
log.warning(f"{status, error} = cli.push_tx({spend_bundle.name()})")
mempool_item = sim.mempool_manager.get_mempool_item(spend_bundle.name())
@ -132,7 +132,7 @@ async def test_mempoolitem_height_added(db_version: int) -> None:
assert mempool_item.name not in removal_ids
mempool_item2 = sim.mempool_manager.get_mempool_item(spend_bundle.name())
assert len(sim.mempool_manager.mempool.spends) == 1
assert sim.mempool_manager.mempool.size() == 1
assert mempool_item2
# This is the important check in this test: ensure height_added_to_mempool does not
@ -141,7 +141,7 @@ async def test_mempoolitem_height_added(db_version: int) -> None:
# Now farm it into the next block
additions, removals = await sim.farm_block(the_puzzle_hash)
assert len(sim.mempool_manager.mempool.spends) == 0
assert sim.mempool_manager.mempool.size() == 0
assert len(removals) == 1
log.warning(heights)

View File

@ -354,7 +354,7 @@ class TestPoolWalletRpc:
# Create some CAT wallets to increase wallet IDs
def mempool_empty() -> bool:
return len(full_node_api.full_node.mempool_manager.mempool.spends.keys()) == 0
return full_node_api.full_node.mempool_manager.mempool.size() == 0
await client.delete_unconfirmed_transactions(1)
await full_node_api.process_all_wallet_transactions(wallet=wallet)

View File

@ -32,7 +32,7 @@ logging.getLogger("aiosqlite").setLevel(logging.INFO) # Too much logging on deb
def mempool_not_empty(fnapi: FullNodeSimulator) -> bool:
return len(fnapi.full_node.mempool_manager.mempool.spends) > 0
return fnapi.full_node.mempool_manager.mempool.size() > 0
async def farm_blocks_until(
@ -720,9 +720,7 @@ async def test_nft_offer_sell_nft_for_cat(
cats_to_mint = 100000
cats_to_trade = uint64(10000)
async with wallet_node_maker.wallet_state_manager.lock:
full_node_api.full_node.log.warning(
f"Mempool size: {len(full_node_api.full_node.mempool_manager.mempool.spends)}"
)
full_node_api.full_node.log.warning(f"Mempool size: {full_node_api.full_node.mempool_manager.mempool.size()}")
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, uint64(cats_to_mint)
)

View File

@ -84,7 +84,7 @@ async def farm_transaction_block(full_node_api: FullNodeSimulator, wallet_node:
def check_mempool_spend_count(full_node_api: FullNodeSimulator, num_of_spends):
return len(full_node_api.full_node.mempool_manager.mempool.sorted_spends) == num_of_spends
return full_node_api.full_node.mempool_manager.mempool.size() == num_of_spends
async def farm_transaction(full_node_api: FullNodeSimulator, wallet_node: WalletNode, spend_bundle: SpendBundle):
@ -674,7 +674,7 @@ async def test_cat_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
assert name == next(iter(DEFAULT_CATS.items()))[1]["name"]
# make sure spend is in mempool before farming tx block
await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 2)
for i in range(5):
if check_mempool_spend_count(full_node_api, 0):
break

View File

@ -36,7 +36,8 @@ def assert_sb_not_in_pool(node: FullNodeAPI, sb: SpendBundle) -> None:
def evict_from_pool(node: FullNodeAPI, sb: SpendBundle) -> None:
mempool_item = node.full_node.mempool_manager.mempool.spends[sb.name()]
mempool_item = node.full_node.mempool_manager.mempool.get_spend_by_id(sb.name())
assert mempool_item is not None
node.full_node.mempool_manager.mempool.remove_from_pool([mempool_item.name], MempoolRemoveReason.CONFLICT)
node.full_node.mempool_manager.remove_seen(sb.name())