|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +import logging |
3 | 4 | import sqlite3 |
4 | 5 | from dataclasses import dataclass |
5 | 6 | from datetime import datetime |
6 | 7 | from enum import Enum |
7 | | -from typing import Dict, Iterator, List, Optional |
| 8 | +from typing import Callable, Dict, Iterator, List, Optional, Tuple |
| 9 | + |
| 10 | +from chia_rs import Coin |
8 | 11 |
|
9 | 12 | from chia.consensus.cost_calculator import NPCResult |
| 13 | +from chia.consensus.default_constants import DEFAULT_CONSTANTS |
10 | 14 | from chia.full_node.fee_estimation import FeeMempoolInfo, MempoolInfo, MempoolItemInfo |
11 | 15 | from chia.full_node.fee_estimator_interface import FeeEstimatorInterface |
12 | 16 | from chia.types.blockchain_format.sized_bytes import bytes32 |
|
17 | 21 | from chia.util.db_wrapper import SQLITE_MAX_VARIABLE_NUMBER |
18 | 22 | from chia.util.ints import uint32, uint64 |
19 | 23 |
|
| 24 | +log = logging.getLogger(__name__) |
| 25 | + |
20 | 26 | # We impose a limit on the fee a single transaction can pay in order to have the |
21 | 27 | # sum of all fees in the mempool be less than 2^63. That's the limit of sqlite's |
22 | 28 | # integers, which we rely on for computing fee per cost as well as the fee sum |
@@ -312,3 +318,39 @@ def at_full_capacity(self, cost: int) -> bool: |
312 | 318 | """ |
313 | 319 |
|
314 | 320 | return self.total_mempool_cost() + cost > self.mempool_info.max_size_in_cost |
| 321 | + |
| 322 | + def create_bundle_from_mempool_items( |
| 323 | + self, item_inclusion_filter: Callable[[bytes32], bool] |
| 324 | + ) -> Optional[Tuple[SpendBundle, List[Coin], List[Coin]]]: |
| 325 | + cost_sum = 0 # Checks that total cost does not exceed block maximum |
| 326 | + fee_sum = 0 # Checks that total fees don't exceed 64 bits |
| 327 | + spend_bundles: List[SpendBundle] = [] |
| 328 | + removals: List[Coin] = [] |
| 329 | + additions: List[Coin] = [] |
| 330 | + log.info(f"Starting to make block, max cost: {self.mempool_info.max_block_clvm_cost}") |
| 331 | + for item in self.spends_by_feerate(): |
| 332 | + if not item_inclusion_filter(item.name): |
| 333 | + continue |
| 334 | + log.info("Cumulative cost: %d, fee per cost: %0.4f", cost_sum, item.fee_per_cost) |
| 335 | + if ( |
| 336 | + item.cost + cost_sum > self.mempool_info.max_block_clvm_cost |
| 337 | + or item.fee + fee_sum > DEFAULT_CONSTANTS.MAX_COIN_AMOUNT |
| 338 | + ): |
| 339 | + break |
| 340 | + spend_bundles.append(item.spend_bundle) |
| 341 | + cost_sum += item.cost |
| 342 | + fee_sum += item.fee |
| 343 | + removals.extend(item.removals) |
| 344 | + if item.npc_result.conds is not None: |
| 345 | + for spend in item.npc_result.conds.spends: |
| 346 | + for puzzle_hash, amount, _ in spend.create_coin: |
| 347 | + coin = Coin(spend.coin_id, puzzle_hash, amount) |
| 348 | + additions.append(coin) |
| 349 | + if len(spend_bundles) == 0: |
| 350 | + return None |
| 351 | + log.info( |
| 352 | + f"Cumulative cost of block (real cost should be less) {cost_sum}. Proportion " |
| 353 | + f"full: {cost_sum / self.mempool_info.max_block_clvm_cost}" |
| 354 | + ) |
| 355 | + agg = SpendBundle.aggregate(spend_bundles) |
| 356 | + return agg, additions, removals |
0 commit comments