mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-08-16 22:30:52 +03:00
Merge commit '507899ff19b0d0bbe14bc7ed8a192f5ad0bc7aa2' into checkpoint/main_from_release_2.1.4_507899ff19b0d0bbe14bc7ed8a192f5ad0bc7aa2
This commit is contained in:
commit
c431c6675c
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
from time import monotonic
|
||||
from typing import Dict, Optional
|
||||
from typing import Collection, Dict, List, Optional
|
||||
|
||||
from chia_rs import G2Element
|
||||
from clvm.casts import int_to_bytes
|
||||
@ -81,8 +81,13 @@ def fake_block_record(block_height: uint32, timestamp: uint64) -> BenchBlockReco
|
||||
async def run_mempool_benchmark() -> None:
|
||||
coin_records: Dict[bytes32, CoinRecord] = {}
|
||||
|
||||
async def get_coin_record(coin_id: bytes32) -> Optional[CoinRecord]:
|
||||
return coin_records.get(coin_id)
|
||||
async def get_coin_record(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
ret: List[CoinRecord] = []
|
||||
for name in coin_ids:
|
||||
r = coin_records.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
timestamp = uint64(1631794488)
|
||||
|
||||
|
@ -6,7 +6,7 @@ from contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
from subprocess import check_call
|
||||
from time import monotonic
|
||||
from typing import Dict, Iterator, List, Optional, Tuple
|
||||
from typing import Collection, Dict, Iterator, List, Optional, Tuple
|
||||
|
||||
from chia.consensus.coinbase import create_farmer_coin, create_pool_coin
|
||||
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
||||
@ -78,8 +78,13 @@ def fake_block_record(block_height: uint32, timestamp: uint64) -> BenchBlockReco
|
||||
async def run_mempool_benchmark() -> None:
|
||||
all_coins: Dict[bytes32, CoinRecord] = {}
|
||||
|
||||
async def get_coin_record(coin_id: bytes32) -> Optional[CoinRecord]:
|
||||
return all_coins.get(coin_id)
|
||||
async def get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
ret: List[CoinRecord] = []
|
||||
for name in coin_ids:
|
||||
r = all_coins.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
wt = WalletTool(DEFAULT_CONSTANTS)
|
||||
|
||||
@ -156,7 +161,7 @@ async def run_mempool_benchmark() -> None:
|
||||
else:
|
||||
print("\n== Multi-threaded")
|
||||
|
||||
mempool = MempoolManager(get_coin_record, DEFAULT_CONSTANTS, single_threaded=single_threaded)
|
||||
mempool = MempoolManager(get_coin_records, DEFAULT_CONSTANTS, single_threaded=single_threaded)
|
||||
|
||||
height = start_height
|
||||
rec = fake_block_record(height, timestamp)
|
||||
@ -186,7 +191,7 @@ async def run_mempool_benchmark() -> None:
|
||||
print(f" time: {stop - start:0.4f}s")
|
||||
print(f" per call: {(stop - start) / total_bundles * 1000:0.2f}ms")
|
||||
|
||||
mempool = MempoolManager(get_coin_record, DEFAULT_CONSTANTS, single_threaded=single_threaded)
|
||||
mempool = MempoolManager(get_coin_records, DEFAULT_CONSTANTS, single_threaded=single_threaded)
|
||||
|
||||
height = start_height
|
||||
rec = fake_block_record(height, timestamp)
|
||||
|
@ -156,7 +156,7 @@ class SpendSim:
|
||||
|
||||
async with DBWrapper2.managed(database=uri, uri=True, reader_count=1, db_version=2) as self.db_wrapper:
|
||||
self.coin_store = await CoinStore.create(self.db_wrapper)
|
||||
self.mempool_manager = MempoolManager(self.coin_store.get_coin_record, defaults)
|
||||
self.mempool_manager = MempoolManager(self.coin_store.get_coin_records, defaults)
|
||||
self.defaults = defaults
|
||||
|
||||
# Load the next data if there is any
|
||||
|
@ -146,7 +146,7 @@ class CoinStore:
|
||||
return CoinRecord(coin, row[0], row[1], row[2], row[6])
|
||||
return None
|
||||
|
||||
async def get_coin_records(self, names: List[bytes32]) -> List[CoinRecord]:
|
||||
async def get_coin_records(self, names: Collection[bytes32]) -> List[CoinRecord]:
|
||||
if len(names) == 0:
|
||||
return []
|
||||
|
||||
|
@ -276,7 +276,7 @@ class FullNode:
|
||||
)
|
||||
|
||||
self._mempool_manager = MempoolManager(
|
||||
get_coin_record=self.coin_store.get_coin_record,
|
||||
get_coin_records=self.coin_store.get_coin_records,
|
||||
consensus_constants=self.constants,
|
||||
multiprocessing_context=self.multiprocessing_context,
|
||||
single_threaded=single_threaded,
|
||||
|
@ -7,7 +7,7 @@ from concurrent.futures import Executor
|
||||
from concurrent.futures.process import ProcessPoolExecutor
|
||||
from dataclasses import dataclass
|
||||
from multiprocessing.context import BaseContext
|
||||
from typing import Awaitable, Callable, Dict, List, Optional, Set, Tuple, TypeVar
|
||||
from typing import Awaitable, Callable, Collection, Dict, List, Optional, Set, Tuple, TypeVar
|
||||
|
||||
from chia_rs import ELIGIBLE_FOR_DEDUP, GTElement
|
||||
from chiabip158 import PyBIP158
|
||||
@ -152,7 +152,7 @@ class MempoolManager:
|
||||
pool: Executor
|
||||
constants: ConsensusConstants
|
||||
seen_bundle_hashes: Dict[bytes32, bytes32]
|
||||
get_coin_record: Callable[[bytes32], Awaitable[Optional[CoinRecord]]]
|
||||
get_coin_records: Callable[[Collection[bytes32]], Awaitable[List[CoinRecord]]]
|
||||
nonzero_fee_minimum_fpc: int
|
||||
mempool_max_total_cost: int
|
||||
# a cache of MempoolItems that conflict with existing items in the pool
|
||||
@ -165,7 +165,7 @@ class MempoolManager:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
get_coin_record: Callable[[bytes32], Awaitable[Optional[CoinRecord]]],
|
||||
get_coin_records: Callable[[Collection[bytes32]], Awaitable[List[CoinRecord]]],
|
||||
consensus_constants: ConsensusConstants,
|
||||
multiprocessing_context: Optional[BaseContext] = None,
|
||||
*,
|
||||
@ -176,7 +176,7 @@ class MempoolManager:
|
||||
# Keep track of seen spend_bundles
|
||||
self.seen_bundle_hashes: Dict[bytes32, bytes32] = {}
|
||||
|
||||
self.get_coin_record = get_coin_record
|
||||
self.get_coin_records = get_coin_records
|
||||
|
||||
# The fee per cost must be above this amount to consider the fee "nonzero", and thus able to kick out other
|
||||
# transactions. This prevents spam. This is equivalent to 0.055 XCH per block, or about 0.00005 XCH for two
|
||||
@ -310,7 +310,12 @@ class MempoolManager:
|
||||
return ret
|
||||
|
||||
async def add_spend_bundle(
|
||||
self, new_spend: SpendBundle, npc_result: NPCResult, spend_name: bytes32, first_added_height: uint32
|
||||
self,
|
||||
new_spend: SpendBundle,
|
||||
npc_result: NPCResult,
|
||||
spend_name: bytes32,
|
||||
first_added_height: uint32,
|
||||
get_coin_records: Optional[Callable[[Collection[bytes32]], Awaitable[List[CoinRecord]]]] = None,
|
||||
) -> Tuple[Optional[uint64], MempoolInclusionStatus, Optional[Err]]:
|
||||
"""
|
||||
Validates and adds to mempool a new_spend with the given NPCResult, and spend_name, and the current mempool.
|
||||
@ -334,8 +339,14 @@ class MempoolManager:
|
||||
if existing_item is not None:
|
||||
return existing_item.cost, MempoolInclusionStatus.SUCCESS, None
|
||||
|
||||
if get_coin_records is None:
|
||||
get_coin_records = self.get_coin_records
|
||||
err, item, remove_items = await self.validate_spend_bundle(
|
||||
new_spend, npc_result, spend_name, first_added_height
|
||||
new_spend,
|
||||
npc_result,
|
||||
spend_name,
|
||||
first_added_height,
|
||||
get_coin_records,
|
||||
)
|
||||
if err is None:
|
||||
# No error, immediately add to mempool, after removing conflicting TXs.
|
||||
@ -365,6 +376,7 @@ class MempoolManager:
|
||||
npc_result: NPCResult,
|
||||
spend_name: bytes32,
|
||||
first_added_height: uint32,
|
||||
get_coin_records: Callable[[Collection[bytes32]], Awaitable[List[CoinRecord]]],
|
||||
) -> Tuple[Optional[Err], Optional[MempoolItem], List[bytes32]]:
|
||||
"""
|
||||
Validates new_spend with the given NPCResult, and spend_name, and the current mempool. The mempool should
|
||||
@ -427,11 +439,14 @@ class MempoolManager:
|
||||
|
||||
removal_record_dict: Dict[bytes32, CoinRecord] = {}
|
||||
removal_amount: int = 0
|
||||
removal_records = await get_coin_records(removal_names)
|
||||
for record in removal_records:
|
||||
removal_record_dict[record.coin.name()] = record
|
||||
|
||||
for name in removal_names:
|
||||
removal_record = await self.get_coin_record(name)
|
||||
if removal_record is None and name not in additions_dict:
|
||||
if name not in removal_record_dict and name not in additions_dict:
|
||||
return Err.UNKNOWN_UNSPENT, None, []
|
||||
elif name in additions_dict:
|
||||
if name in additions_dict:
|
||||
removal_coin = additions_dict[name]
|
||||
# The timestamp and block-height of this coin being spent needs
|
||||
# to be consistent with what we use to check time-lock
|
||||
@ -447,10 +462,10 @@ class MempoolManager:
|
||||
False,
|
||||
self.peak.timestamp,
|
||||
)
|
||||
|
||||
assert removal_record is not None
|
||||
removal_record_dict[name] = removal_record
|
||||
else:
|
||||
removal_record = removal_record_dict[name]
|
||||
removal_amount = removal_amount + removal_record.coin.amount
|
||||
removal_record_dict[name] = removal_record
|
||||
|
||||
fees = uint64(removal_amount - addition_amount)
|
||||
|
||||
@ -641,9 +656,35 @@ class MempoolManager:
|
||||
old_pool = self.mempool
|
||||
self.mempool = Mempool(old_pool.mempool_info, old_pool.fee_estimator)
|
||||
self.seen_bundle_hashes = {}
|
||||
|
||||
# in order to make this a bit quicker, we look-up all the spends in
|
||||
# a single query, rather than one at a time.
|
||||
coin_records: Dict[bytes32, CoinRecord] = {}
|
||||
|
||||
removals: Set[bytes32] = set()
|
||||
for item in old_pool.all_items():
|
||||
for s in item.spend_bundle.coin_spends:
|
||||
removals.add(s.coin.name())
|
||||
|
||||
for record in await self.get_coin_records(removals):
|
||||
name = record.coin.name()
|
||||
coin_records[name] = record
|
||||
|
||||
async def local_get_coin_records(names: Collection[bytes32]) -> List[CoinRecord]:
|
||||
ret: List[CoinRecord] = []
|
||||
for name in names:
|
||||
r = coin_records.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
for item in old_pool.all_items():
|
||||
_, result, err = await self.add_spend_bundle(
|
||||
item.spend_bundle, item.npc_result, item.spend_bundle_name, item.height_added_to_mempool
|
||||
item.spend_bundle,
|
||||
item.npc_result,
|
||||
item.spend_bundle_name,
|
||||
item.height_added_to_mempool,
|
||||
local_get_coin_records,
|
||||
)
|
||||
# Only add to `seen` if inclusion worked, so it can be resubmitted in case of a reorg
|
||||
if result == MempoolInclusionStatus.SUCCESS:
|
||||
@ -660,7 +701,11 @@ class MempoolManager:
|
||||
txs_added = []
|
||||
for item in potential_txs.values():
|
||||
cost, status, error = await self.add_spend_bundle(
|
||||
item.spend_bundle, item.npc_result, item.spend_bundle_name, item.height_added_to_mempool
|
||||
item.spend_bundle,
|
||||
item.npc_result,
|
||||
item.spend_bundle_name,
|
||||
item.height_added_to_mempool,
|
||||
self.get_coin_records,
|
||||
)
|
||||
if status == MempoolInclusionStatus.SUCCESS:
|
||||
txs_added.append((item.spend_bundle, item.npc_result, item.spend_bundle_name))
|
||||
|
@ -63,7 +63,7 @@ async def test_basics() -> None:
|
||||
async def test_fee_increase() -> None:
|
||||
async with DBConnection(db_version=2) as db_wrapper:
|
||||
coin_store = await CoinStore.create(db_wrapper)
|
||||
mempool_manager = MempoolManager(coin_store.get_coin_record, test_constants)
|
||||
mempool_manager = MempoolManager(coin_store.get_coin_records, test_constants)
|
||||
assert test_constants.MAX_BLOCK_COST_CLVM == mempool_manager.constants.MAX_BLOCK_COST_CLVM
|
||||
btc_fee_estimator: BitcoinFeeEstimator = mempool_manager.mempool.fee_estimator # type: ignore
|
||||
fee_tracker = btc_fee_estimator.get_tracker()
|
||||
|
@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Awaitable, Callable, Dict, List, Optional, Set, Tuple
|
||||
from typing import Any, Awaitable, Callable, Collection, Dict, List, Optional, Set, Tuple
|
||||
|
||||
import pytest
|
||||
from chia_rs import ELIGIBLE_FOR_DEDUP, G1Element, G2Element
|
||||
@ -85,17 +85,24 @@ class TestBlockRecord:
|
||||
return self.timestamp is not None
|
||||
|
||||
|
||||
async def zero_calls_get_coin_record(_: bytes32) -> Optional[CoinRecord]:
|
||||
assert False
|
||||
async def zero_calls_get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
assert len(coin_ids) == 0
|
||||
return []
|
||||
|
||||
|
||||
async def get_coin_record_for_test_coins(coin_id: bytes32) -> Optional[CoinRecord]:
|
||||
async def get_coin_records_for_test_coins(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
test_coin_records = {
|
||||
TEST_COIN_ID: TEST_COIN_RECORD,
|
||||
TEST_COIN_ID2: TEST_COIN_RECORD2,
|
||||
TEST_COIN_ID3: TEST_COIN_RECORD3,
|
||||
}
|
||||
return test_coin_records.get(coin_id)
|
||||
|
||||
ret: List[CoinRecord] = []
|
||||
for name in coin_ids:
|
||||
r = test_coin_records.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
|
||||
def height_hash(height: int) -> bytes32:
|
||||
@ -113,13 +120,13 @@ def create_test_block_record(*, height: uint32 = TEST_HEIGHT, timestamp: uint64
|
||||
|
||||
|
||||
async def instantiate_mempool_manager(
|
||||
get_coin_record: Callable[[bytes32], Awaitable[Optional[CoinRecord]]],
|
||||
get_coin_records: Callable[[Collection[bytes32]], Awaitable[List[CoinRecord]]],
|
||||
*,
|
||||
block_height: uint32 = TEST_HEIGHT,
|
||||
block_timestamp: uint64 = TEST_TIMESTAMP,
|
||||
constants: ConsensusConstants = DEFAULT_CONSTANTS,
|
||||
) -> MempoolManager:
|
||||
mempool_manager = MempoolManager(get_coin_record, constants)
|
||||
mempool_manager = MempoolManager(get_coin_records, constants)
|
||||
test_block_record = create_test_block_record(height=block_height, timestamp=block_timestamp)
|
||||
await mempool_manager.new_peak(test_block_record, None)
|
||||
invariant_check_mempool(mempool_manager.mempool)
|
||||
@ -134,10 +141,15 @@ async def setup_mempool_with_coins(*, coin_amounts: List[int]) -> Tuple[MempoolM
|
||||
coins.append(coin)
|
||||
test_coin_records[coin.name()] = CoinRecord(coin, uint32(0), uint32(0), False, uint64(0))
|
||||
|
||||
async def get_coin_record(coin_id: bytes32) -> Optional[CoinRecord]:
|
||||
return test_coin_records.get(coin_id)
|
||||
async def get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
ret: List[CoinRecord] = []
|
||||
for name in coin_ids:
|
||||
r = test_coin_records.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_records)
|
||||
return (mempool_manager, coins)
|
||||
|
||||
|
||||
@ -408,7 +420,7 @@ def mempool_item_from_spendbundle(spend_bundle: SpendBundle) -> MempoolItem:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_empty_spend_bundle() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
sb = SpendBundle([], G2Element())
|
||||
with pytest.raises(ValidationError, match="INVALID_SPEND_BUNDLE"):
|
||||
await mempool_manager.pre_validate_spendbundle(sb, None, sb.name())
|
||||
@ -416,7 +428,7 @@ async def test_empty_spend_bundle() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_negative_addition_amount() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, -1]]
|
||||
sb = spend_bundle_from_conditions(conditions)
|
||||
with pytest.raises(ValidationError, match="COIN_AMOUNT_NEGATIVE"):
|
||||
@ -425,7 +437,7 @@ async def test_negative_addition_amount() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_valid_addition_amount() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
max_amount = mempool_manager.constants.MAX_COIN_AMOUNT
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, max_amount]]
|
||||
coin = Coin(IDENTITY_PUZZLE_HASH, IDENTITY_PUZZLE_HASH, max_amount)
|
||||
@ -436,7 +448,7 @@ async def test_valid_addition_amount() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_too_big_addition_amount() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
max_amount = mempool_manager.constants.MAX_COIN_AMOUNT
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, max_amount + 1]]
|
||||
sb = spend_bundle_from_conditions(conditions)
|
||||
@ -446,7 +458,7 @@ async def test_too_big_addition_amount() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_duplicate_output() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
conditions = [
|
||||
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
||||
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
||||
@ -458,7 +470,7 @@ async def test_duplicate_output() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_block_cost_exceeds_max() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
conditions = []
|
||||
for i in range(2400):
|
||||
conditions.append([ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, i])
|
||||
@ -469,7 +481,7 @@ async def test_block_cost_exceeds_max() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_double_spend_prevalidation() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1]]
|
||||
sb = spend_bundle_from_conditions(conditions)
|
||||
sb_twice: SpendBundle = SpendBundle.aggregate([sb, sb])
|
||||
@ -479,7 +491,7 @@ async def test_double_spend_prevalidation() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_minting_coin() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT]]
|
||||
sb = spend_bundle_from_conditions(conditions)
|
||||
npc_result = await mempool_manager.pre_validate_spendbundle(sb, None, sb.name())
|
||||
@ -492,7 +504,7 @@ async def test_minting_coin() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_reserve_fee_condition() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
conditions = [[ConditionOpcode.RESERVE_FEE, TEST_COIN_AMOUNT]]
|
||||
sb = spend_bundle_from_conditions(conditions)
|
||||
npc_result = await mempool_manager.pre_validate_spendbundle(sb, None, sb.name())
|
||||
@ -505,10 +517,10 @@ async def test_reserve_fee_condition() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_unknown_unspent() -> None:
|
||||
async def get_coin_record(_: bytes32) -> Optional[CoinRecord]:
|
||||
return None
|
||||
async def get_coin_records(_: Collection[bytes32]) -> List[CoinRecord]:
|
||||
return []
|
||||
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_records)
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1]]
|
||||
_, _, result = await generate_and_add_spendbundle(mempool_manager, conditions)
|
||||
assert result == (None, MempoolInclusionStatus.FAILED, Err.UNKNOWN_UNSPENT)
|
||||
@ -516,7 +528,7 @@ async def test_unknown_unspent() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_same_sb_twice_with_eligible_coin() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_record_for_test_coins)
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_records_for_test_coins)
|
||||
sb1_conditions = [
|
||||
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
||||
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 2],
|
||||
@ -540,7 +552,7 @@ async def test_same_sb_twice_with_eligible_coin() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_sb_twice_with_eligible_coin_and_different_spends_order() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_record_for_test_coins)
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_records_for_test_coins)
|
||||
sb1_conditions = [
|
||||
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
||||
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 2],
|
||||
@ -637,7 +649,7 @@ async def test_ephemeral_timelock(
|
||||
expected_error: Optional[Err],
|
||||
) -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(
|
||||
get_coin_record=get_coin_record_for_test_coins,
|
||||
get_coin_records=get_coin_records_for_test_coins,
|
||||
block_height=uint32(5),
|
||||
block_timestamp=uint64(10050),
|
||||
constants=DEFAULT_CONSTANTS,
|
||||
@ -650,7 +662,7 @@ async def test_ephemeral_timelock(
|
||||
# sb spends TEST_COIN and creates created_coin which gets spent too
|
||||
sb = SpendBundle.aggregate([sb1, sb2])
|
||||
# We shouldn't have a record of this ephemeral coin
|
||||
assert await get_coin_record_for_test_coins(created_coin.name()) is None
|
||||
assert await get_coin_records_for_test_coins([created_coin.name()]) == []
|
||||
try:
|
||||
_, status, error = await add_spendbundle(mempool_manager, sb, sb.name())
|
||||
assert (status, error) == (expected_status, expected_error)
|
||||
@ -848,7 +860,7 @@ def test_can_replace(existing_items: List[MempoolItem], new_item: MempoolItem, e
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_get_items_not_in_filter() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_record_for_test_coins)
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_records_for_test_coins)
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1]]
|
||||
sb1, sb1_name, _ = await generate_and_add_spendbundle(mempool_manager, conditions)
|
||||
conditions2 = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 2]]
|
||||
@ -895,10 +907,15 @@ async def test_get_items_not_in_filter() -> None:
|
||||
async def test_total_mempool_fees() -> None:
|
||||
coin_records: Dict[bytes32, CoinRecord] = {}
|
||||
|
||||
async def get_coin_record(coin_id: bytes32) -> Optional[CoinRecord]:
|
||||
return coin_records.get(coin_id)
|
||||
async def get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
ret: List[CoinRecord] = []
|
||||
for name in coin_ids:
|
||||
r = coin_records.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_records)
|
||||
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1]]
|
||||
|
||||
# the limit of total fees in the mempool is 2^63
|
||||
@ -1013,11 +1030,17 @@ async def test_create_bundle_from_mempool_on_max_cost() -> None:
|
||||
async def test_assert_before_expiration(
|
||||
opcode: ConditionOpcode, arg: int, expect_eviction: bool, expect_limit: Optional[int]
|
||||
) -> None:
|
||||
async def get_coin_record(coin_id: bytes32) -> Optional[CoinRecord]:
|
||||
return {TEST_COIN.name(): CoinRecord(TEST_COIN, uint32(5), uint32(0), False, uint64(9900))}.get(coin_id)
|
||||
async def get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
all_coins = {TEST_COIN.name(): CoinRecord(TEST_COIN, uint32(5), uint32(0), False, uint64(9900))}
|
||||
ret: List[CoinRecord] = []
|
||||
for name in coin_ids:
|
||||
r = all_coins.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
mempool_manager = await instantiate_mempool_manager(
|
||||
get_coin_record,
|
||||
get_coin_records,
|
||||
block_height=uint32(10),
|
||||
block_timestamp=uint64(10000),
|
||||
constants=DEFAULT_CONSTANTS,
|
||||
@ -1372,10 +1395,15 @@ async def test_coin_spending_different_ways_then_finding_it_spent_in_new_peak(ne
|
||||
coin_id = coin.name()
|
||||
test_coin_records = {coin_id: CoinRecord(coin, uint32(0), uint32(0), False, uint64(0))}
|
||||
|
||||
async def get_coin_record(coin_id: bytes32) -> Optional[CoinRecord]:
|
||||
return test_coin_records.get(coin_id)
|
||||
async def get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
|
||||
ret: List[CoinRecord] = []
|
||||
for name in coin_ids:
|
||||
r = test_coin_records.get(name)
|
||||
if r is not None:
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(get_coin_records)
|
||||
# Create a bunch of mempool items that spend the coin in different ways
|
||||
for i in range(3):
|
||||
_, _, result = await generate_and_add_spendbundle(
|
||||
|
@ -29,7 +29,7 @@ from chia.util.ints import uint32, uint64
|
||||
from tests.core.mempool.test_mempool_manager import (
|
||||
create_test_block_record,
|
||||
instantiate_mempool_manager,
|
||||
zero_calls_get_coin_record,
|
||||
zero_calls_get_coin_records,
|
||||
)
|
||||
|
||||
|
||||
@ -217,7 +217,7 @@ def test_current_block_height_new_block_then_new_height() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_mm_new_peak_changes_fee_estimator_block_height() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
block2 = create_test_block_record(height=uint32(2))
|
||||
await mempool_manager.new_peak(block2, None)
|
||||
assert mempool_manager.mempool.fee_estimator.block_height == uint32(2) # type: ignore[attr-defined]
|
||||
@ -225,7 +225,7 @@ async def test_mm_new_peak_changes_fee_estimator_block_height() -> None:
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_mm_calls_new_block_height() -> None:
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_record)
|
||||
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
|
||||
new_block_height_called = False
|
||||
|
||||
def test_new_block_height_called(self: FeeEstimatorInterface, height: uint32) -> None:
|
||||
|
Loading…
Reference in New Issue
Block a user