mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-11 10:56:14 +03:00
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:
parent
1a722be39b
commit
ed8cee2b4b
@ -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]]:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user