chia-blockchain 2.5.3rc2__py3-none-any.whl → 2.5.4rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chia/_tests/core/mempool/test_mempool_manager.py +332 -24
- chia/_tests/timelord/test_new_peak.py +58 -0
- chia/consensus/block_creation.py +3 -1
- chia/full_node/full_node.py +20 -6
- chia/full_node/mempool_manager.py +149 -35
- chia/harvester/harvester_api.py +3 -3
- chia/simulator/block_tools.py +4 -5
- chia/timelord/timelord_api.py +21 -5
- chia/types/blockchain_format/program.py +2 -2
- {chia_blockchain-2.5.3rc2.dist-info → chia_blockchain-2.5.4rc1.dist-info}/METADATA +1 -1
- {chia_blockchain-2.5.3rc2.dist-info → chia_blockchain-2.5.4rc1.dist-info}/RECORD +14 -14
- {chia_blockchain-2.5.3rc2.dist-info → chia_blockchain-2.5.4rc1.dist-info}/WHEEL +1 -1
- {chia_blockchain-2.5.3rc2.dist-info → chia_blockchain-2.5.4rc1.dist-info}/LICENSE +0 -0
- {chia_blockchain-2.5.3rc2.dist-info → chia_blockchain-2.5.4rc1.dist-info}/entry_points.txt +0 -0
|
@@ -19,7 +19,7 @@ from chia_rs.sized_ints import uint8, uint32, uint64
|
|
|
19
19
|
from chiabip158 import PyBIP158
|
|
20
20
|
|
|
21
21
|
from chia._tests.conftest import ConsensusMode
|
|
22
|
-
from chia._tests.util.misc import invariant_check_mempool
|
|
22
|
+
from chia._tests.util.misc import Marks, datacases, invariant_check_mempool
|
|
23
23
|
from chia._tests.util.setup_nodes import OldSimulatorsAndWallets, setup_simulators_and_wallets
|
|
24
24
|
from chia.consensus.condition_costs import ConditionCost
|
|
25
25
|
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
|
@@ -32,7 +32,10 @@ from chia.full_node.mempool_manager import (
|
|
|
32
32
|
MempoolManager,
|
|
33
33
|
TimelockConditions,
|
|
34
34
|
can_replace,
|
|
35
|
+
check_removals,
|
|
35
36
|
compute_assert_height,
|
|
37
|
+
is_atom_canonical,
|
|
38
|
+
is_clvm_canonical,
|
|
36
39
|
optional_max,
|
|
37
40
|
optional_min,
|
|
38
41
|
)
|
|
@@ -87,6 +90,74 @@ TEST_COIN_RECORD3 = CoinRecord(TEST_COIN3, uint32(0), uint32(0), False, TEST_TIM
|
|
|
87
90
|
TEST_HEIGHT = uint32(5)
|
|
88
91
|
|
|
89
92
|
|
|
93
|
+
@pytest.mark.parametrize("clvm_hex", ["80", "ff8080", "ff7f03", "ffff8080ff8080"])
|
|
94
|
+
def test_clvm_canonical(clvm_hex: str) -> None:
|
|
95
|
+
clvm_buf = bytes.fromhex(clvm_hex)
|
|
96
|
+
assert is_clvm_canonical(clvm_buf)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@pytest.mark.parametrize(
|
|
100
|
+
"clvm_hex",
|
|
101
|
+
[
|
|
102
|
+
"fffe80",
|
|
103
|
+
"c000",
|
|
104
|
+
"c03f",
|
|
105
|
+
"e00000",
|
|
106
|
+
"e01fff",
|
|
107
|
+
"f0000000",
|
|
108
|
+
"f00fffff",
|
|
109
|
+
"f800000000",
|
|
110
|
+
"f807ffffff",
|
|
111
|
+
"fc0000000000",
|
|
112
|
+
"fc03ffffffff",
|
|
113
|
+
"fe",
|
|
114
|
+
"ff808080",
|
|
115
|
+
],
|
|
116
|
+
)
|
|
117
|
+
def test_clvm_not_canonical(clvm_hex: str) -> None:
|
|
118
|
+
clvm_buf = bytes.fromhex(clvm_hex)
|
|
119
|
+
assert not is_clvm_canonical(clvm_buf)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@pytest.mark.parametrize(
|
|
123
|
+
"clvm_hex, expect",
|
|
124
|
+
[
|
|
125
|
+
("c000", 2 + 0),
|
|
126
|
+
("c03f", 2 + 0x3F),
|
|
127
|
+
("e00000", 3 + 0),
|
|
128
|
+
("e01fff", 3 + 0x1FFF),
|
|
129
|
+
("f0000000", 4 + 0),
|
|
130
|
+
("f00fffff", 4 + 0xFFFFF),
|
|
131
|
+
("f800000000", 5 + 0),
|
|
132
|
+
("f807ffffff", 5 + 0x7FFFFFF),
|
|
133
|
+
("fc0000000000", 6 + 0),
|
|
134
|
+
("fc03ffffffff", 6 + 0x3FFFFFFFF),
|
|
135
|
+
],
|
|
136
|
+
)
|
|
137
|
+
def test_atom_not_canonical(clvm_hex: str, expect: int) -> None:
|
|
138
|
+
clvm_buf = bytes.fromhex(clvm_hex)
|
|
139
|
+
atom_len, is_canonical = is_atom_canonical(clvm_buf, 0)
|
|
140
|
+
assert atom_len == expect
|
|
141
|
+
assert not is_canonical
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@pytest.mark.parametrize(
|
|
145
|
+
"clvm_hex, expect",
|
|
146
|
+
[
|
|
147
|
+
("c040", 2 + 0x40),
|
|
148
|
+
("e02000", 3 + 0x2000),
|
|
149
|
+
("f0100000", 4 + 0x100000),
|
|
150
|
+
("f808000000", 5 + 0x8000000),
|
|
151
|
+
("fc0400000000", 6 + 0x400000000),
|
|
152
|
+
],
|
|
153
|
+
)
|
|
154
|
+
def test_atom_canonical(clvm_hex: str, expect: int) -> None:
|
|
155
|
+
clvm_buf = bytes.fromhex(clvm_hex)
|
|
156
|
+
atom_len, is_canonical = is_atom_canonical(clvm_buf, 0)
|
|
157
|
+
assert atom_len == expect
|
|
158
|
+
assert is_canonical
|
|
159
|
+
|
|
160
|
+
|
|
90
161
|
@dataclasses.dataclass(frozen=True)
|
|
91
162
|
class TestBlockRecord:
|
|
92
163
|
"""
|
|
@@ -195,6 +266,9 @@ async def setup_mempool_with_coins(
|
|
|
195
266
|
return (mempool_manager, coins)
|
|
196
267
|
|
|
197
268
|
|
|
269
|
+
CreateCoin = tuple[bytes32, int, Optional[bytes]]
|
|
270
|
+
|
|
271
|
+
|
|
198
272
|
def make_test_conds(
|
|
199
273
|
*,
|
|
200
274
|
birth_height: Optional[int] = None,
|
|
@@ -209,13 +283,18 @@ def make_test_conds(
|
|
|
209
283
|
before_seconds_absolute: Optional[int] = None,
|
|
210
284
|
cost: int = 0,
|
|
211
285
|
spend_ids: Sequence[tuple[Union[bytes32, Coin], int]] = [(TEST_COIN_ID, 0)],
|
|
286
|
+
created_coins: Optional[list[list[CreateCoin]]] = None,
|
|
212
287
|
) -> SpendBundleConditions:
|
|
213
|
-
|
|
214
|
-
|
|
288
|
+
if created_coins is None:
|
|
289
|
+
created_coins = []
|
|
290
|
+
if len(created_coins) < len(spend_ids):
|
|
291
|
+
created_coins.extend([[] for _ in range(len(spend_ids) - len(created_coins))])
|
|
292
|
+
spend_info: list[tuple[bytes32, bytes32, bytes32, uint64, int, list[CreateCoin]]] = []
|
|
293
|
+
for (coin, flags), create_coin in zip(spend_ids, created_coins):
|
|
215
294
|
if isinstance(coin, Coin):
|
|
216
|
-
spend_info.append((coin.name(), coin.parent_coin_info, coin.puzzle_hash, coin.amount, flags))
|
|
295
|
+
spend_info.append((coin.name(), coin.parent_coin_info, coin.puzzle_hash, coin.amount, flags, create_coin))
|
|
217
296
|
else:
|
|
218
|
-
spend_info.append((coin, IDENTITY_PUZZLE_HASH, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT, flags))
|
|
297
|
+
spend_info.append((coin, IDENTITY_PUZZLE_HASH, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT, flags, create_coin))
|
|
219
298
|
|
|
220
299
|
return SpendBundleConditions(
|
|
221
300
|
[
|
|
@@ -230,7 +309,7 @@ def make_test_conds(
|
|
|
230
309
|
None if before_seconds_relative is None else uint64(before_seconds_relative),
|
|
231
310
|
None if birth_height is None else uint32(birth_height),
|
|
232
311
|
None if birth_seconds is None else uint64(birth_seconds),
|
|
233
|
-
|
|
312
|
+
create_coin,
|
|
234
313
|
[],
|
|
235
314
|
[],
|
|
236
315
|
[],
|
|
@@ -240,7 +319,7 @@ def make_test_conds(
|
|
|
240
319
|
[],
|
|
241
320
|
flags,
|
|
242
321
|
)
|
|
243
|
-
for coin_id, parent_id, puzzle_hash, amount, flags in spend_info
|
|
322
|
+
for coin_id, parent_id, puzzle_hash, amount, flags, create_coin in spend_info
|
|
244
323
|
],
|
|
245
324
|
0,
|
|
246
325
|
uint32(height_absolute),
|
|
@@ -751,6 +830,23 @@ def test_optional_max() -> None:
|
|
|
751
830
|
assert optional_max(uint32(123), uint32(234)) == uint32(234)
|
|
752
831
|
|
|
753
832
|
|
|
833
|
+
def mk_coin_spend(coin: Coin, solution: Optional[str] = None) -> CoinSpend:
|
|
834
|
+
return make_spend(
|
|
835
|
+
coin,
|
|
836
|
+
SerializedProgram.to(None),
|
|
837
|
+
SerializedProgram.fromhex(solution if solution is not None else "80"),
|
|
838
|
+
)
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def mk_bcs(coin_spend: CoinSpend, flags: int = 0) -> BundleCoinSpend:
|
|
842
|
+
return BundleCoinSpend(
|
|
843
|
+
coin_spend=coin_spend,
|
|
844
|
+
eligible_for_dedup=bool(flags & ELIGIBLE_FOR_DEDUP),
|
|
845
|
+
eligible_for_fast_forward=bool(flags & ELIGIBLE_FOR_FF),
|
|
846
|
+
additions=[],
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
|
|
754
850
|
def mk_item(
|
|
755
851
|
coins: list[Coin],
|
|
756
852
|
*,
|
|
@@ -759,6 +855,7 @@ def mk_item(
|
|
|
759
855
|
assert_height: Optional[int] = None,
|
|
760
856
|
assert_before_height: Optional[int] = None,
|
|
761
857
|
assert_before_seconds: Optional[int] = None,
|
|
858
|
+
solution: Optional[str] = None,
|
|
762
859
|
flags: list[int] = [],
|
|
763
860
|
) -> MempoolItem:
|
|
764
861
|
# we don't actually care about the puzzle and solutions for the purpose of
|
|
@@ -771,14 +868,10 @@ def mk_item(
|
|
|
771
868
|
for c, f in zip(coins, flags):
|
|
772
869
|
coin_id = c.name()
|
|
773
870
|
spend_ids.append((coin_id, f))
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
eligible_for_dedup=bool(f & ELIGIBLE_FOR_DEDUP),
|
|
779
|
-
eligible_for_fast_forward=bool(f & ELIGIBLE_FOR_FF),
|
|
780
|
-
additions=[],
|
|
781
|
-
)
|
|
871
|
+
coin_spend = mk_coin_spend(c, solution=solution)
|
|
872
|
+
solution = None
|
|
873
|
+
coin_spends.append(coin_spend)
|
|
874
|
+
bundle_coin_spends[coin_id] = mk_bcs(coin_spend, f)
|
|
782
875
|
spend_bundle = SpendBundle(coin_spends, G2Element())
|
|
783
876
|
conds = make_test_conds(cost=cost, spend_ids=spend_ids)
|
|
784
877
|
return MempoolItem(
|
|
@@ -1625,6 +1718,7 @@ async def test_coin_spending_different_ways_then_finding_it_spent_in_new_peak(ne
|
|
|
1625
1718
|
|
|
1626
1719
|
mempool_manager = await instantiate_mempool_manager(get_coin_records)
|
|
1627
1720
|
# Create a bunch of mempool items that spend the coin in different ways
|
|
1721
|
+
# only the first one will be accepted
|
|
1628
1722
|
for i in range(3):
|
|
1629
1723
|
_, _, result = await generate_and_add_spendbundle(
|
|
1630
1724
|
mempool_manager,
|
|
@@ -1634,10 +1728,13 @@ async def test_coin_spending_different_ways_then_finding_it_spent_in_new_peak(ne
|
|
|
1634
1728
|
],
|
|
1635
1729
|
coin,
|
|
1636
1730
|
)
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1731
|
+
if i == 0:
|
|
1732
|
+
assert result[1] == MempoolInclusionStatus.SUCCESS
|
|
1733
|
+
else:
|
|
1734
|
+
assert result[1] == MempoolInclusionStatus.PENDING
|
|
1735
|
+
assert len(list(mempool_manager.mempool.get_items_by_coin_id(coin_id))) == 1
|
|
1736
|
+
assert mempool_manager.mempool.size() == 1
|
|
1737
|
+
assert len(list(mempool_manager.mempool.items_by_feerate())) == 1
|
|
1641
1738
|
# Setup a new peak where the incoming block has spent the coin
|
|
1642
1739
|
# Mark this coin as spent
|
|
1643
1740
|
test_coin_records = {coin_id: CoinRecord(coin, uint32(0), TEST_HEIGHT, False, uint64(0))}
|
|
@@ -1816,7 +1913,7 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1816
1913
|
sb_ef_name = sb_ef.name()
|
|
1817
1914
|
await send_to_mempool(full_node_api, sb_ef)
|
|
1818
1915
|
# Send also a transaction EG that spends E differently from DE and EF,
|
|
1819
|
-
#
|
|
1916
|
+
# to ensure it's rejected by the mempool
|
|
1820
1917
|
conditions = [
|
|
1821
1918
|
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, e_coin.amount],
|
|
1822
1919
|
[ConditionOpcode.ASSERT_MY_COIN_ID, e_coin.name()],
|
|
@@ -1834,14 +1931,13 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1834
1931
|
[tx_g] = action_scope.side_effects.transactions
|
|
1835
1932
|
assert tx_g.spend_bundle is not None
|
|
1836
1933
|
sb_e2g = SpendBundle.aggregate([sb_e2, tx_g.spend_bundle])
|
|
1837
|
-
|
|
1838
|
-
await send_to_mempool(full_node_api, sb_e2g)
|
|
1934
|
+
await send_to_mempool(full_node_api, sb_e2g, expecting_conflict=True)
|
|
1839
1935
|
|
|
1840
1936
|
# Make sure our coin IDs to spend bundles mappings are correct
|
|
1841
1937
|
assert get_sb_names_by_coin_id(full_node_api, coins[4].coin.name()) == {sb_de_name}
|
|
1842
|
-
assert get_sb_names_by_coin_id(full_node_api, e_coin_id) == {sb_de_name, sb_ef_name
|
|
1938
|
+
assert get_sb_names_by_coin_id(full_node_api, e_coin_id) == {sb_de_name, sb_ef_name}
|
|
1843
1939
|
assert get_sb_names_by_coin_id(full_node_api, coins[5].coin.name()) == {sb_ef_name}
|
|
1844
|
-
assert get_sb_names_by_coin_id(full_node_api, g_coin_id) ==
|
|
1940
|
+
assert get_sb_names_by_coin_id(full_node_api, g_coin_id) == set()
|
|
1845
1941
|
|
|
1846
1942
|
await farm_a_block(full_node_api, wallet_node, ph)
|
|
1847
1943
|
|
|
@@ -2501,3 +2597,215 @@ async def test_advancing_ff(use_optimization: bool) -> None:
|
|
|
2501
2597
|
spend = item.bundle_coin_spends[spend_a.coin.name()]
|
|
2502
2598
|
assert spend.eligible_for_fast_forward
|
|
2503
2599
|
assert spend.latest_singleton_coin == spend_c.coin.name()
|
|
2600
|
+
|
|
2601
|
+
|
|
2602
|
+
@pytest.mark.parametrize("flags", [ELIGIBLE_FOR_DEDUP, ELIGIBLE_FOR_FF, ELIGIBLE_FOR_FF | ELIGIBLE_FOR_DEDUP])
|
|
2603
|
+
@pytest.mark.anyio
|
|
2604
|
+
async def test_check_removals_with_block_creation(flags: int) -> None:
|
|
2605
|
+
LAUNCHER_ID = bytes32([1] * 32)
|
|
2606
|
+
PARENT_PARENT = bytes32([2] * 32)
|
|
2607
|
+
singleton_spend = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT)
|
|
2608
|
+
coins = TestCoins(
|
|
2609
|
+
coins=[singleton_spend.coin, TEST_COIN], lineage={singleton_spend.coin.puzzle_hash: singleton_spend.coin}
|
|
2610
|
+
)
|
|
2611
|
+
mempool_manager = await setup_mempool(coins)
|
|
2612
|
+
sb1 = SpendBundle([singleton_spend], G2Element())
|
|
2613
|
+
sb1_conds = make_test_conds(
|
|
2614
|
+
spend_ids=[(singleton_spend.coin, 0)],
|
|
2615
|
+
created_coins=[[(singleton_spend.coin.puzzle_hash, 1, None)]],
|
|
2616
|
+
cost=100_000_000,
|
|
2617
|
+
)
|
|
2618
|
+
bundle_add_info1 = await mempool_manager.add_spend_bundle(sb1, sb1_conds, sb1.name(), uint32(1))
|
|
2619
|
+
assert bundle_add_info1.status == MempoolInclusionStatus.SUCCESS
|
|
2620
|
+
invariant_check_mempool(mempool_manager.mempool)
|
|
2621
|
+
extra_spend = make_spend(
|
|
2622
|
+
TEST_COIN, IDENTITY_PUZZLE, Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 42]])
|
|
2623
|
+
)
|
|
2624
|
+
sb2 = SpendBundle([singleton_spend, extra_spend], G2Element())
|
|
2625
|
+
sb2_conds = make_test_conds(
|
|
2626
|
+
spend_ids=[(singleton_spend.coin, flags), (TEST_COIN, 0)],
|
|
2627
|
+
created_coins=[[(singleton_spend.coin.puzzle_hash, 1, None)], []],
|
|
2628
|
+
cost=1337,
|
|
2629
|
+
)
|
|
2630
|
+
bundle_add_info2 = await mempool_manager.add_spend_bundle(sb2, sb2_conds, sb2.name(), uint32(1))
|
|
2631
|
+
assert bundle_add_info2.status == MempoolInclusionStatus.SUCCESS
|
|
2632
|
+
assert mempool_manager.peak is not None
|
|
2633
|
+
block_generator = await mempool_manager.create_block_generator(mempool_manager.peak.header_hash)
|
|
2634
|
+
assert block_generator is not None
|
|
2635
|
+
_, _, additions, removals = block_generator
|
|
2636
|
+
assert len(additions) == 1
|
|
2637
|
+
assert set(additions) == {Coin(singleton_spend.coin.name(), singleton_spend.coin.puzzle_hash, uint64(1))}
|
|
2638
|
+
assert len(removals) == 2
|
|
2639
|
+
assert set(removals) == {singleton_spend.coin, TEST_COIN}
|
|
2640
|
+
|
|
2641
|
+
|
|
2642
|
+
@pytest.mark.anyio
|
|
2643
|
+
async def test_dedup_not_canonical() -> None:
|
|
2644
|
+
# this is ((1)), but with a non-canonical encoding
|
|
2645
|
+
coin_spend = mk_coin_spend(TEST_COIN, solution="ffffc001018080")
|
|
2646
|
+
coins = TestCoins([TEST_COIN], lineage={})
|
|
2647
|
+
mempool_manager = await setup_mempool(coins)
|
|
2648
|
+
sb = SpendBundle([coin_spend], G2Element())
|
|
2649
|
+
sb_conds = make_test_conds(spend_ids=[(TEST_COIN, ELIGIBLE_FOR_DEDUP)])
|
|
2650
|
+
bundle_add_info = await mempool_manager.add_spend_bundle(sb, sb_conds, sb.name(), uint32(1))
|
|
2651
|
+
assert bundle_add_info.status == MempoolInclusionStatus.FAILED
|
|
2652
|
+
assert bundle_add_info.error == Err.INVALID_COIN_SOLUTION
|
|
2653
|
+
|
|
2654
|
+
|
|
2655
|
+
def make_coin_record(coin: Coin, spent_block_index: int = 0) -> CoinRecord:
|
|
2656
|
+
return CoinRecord(coin, uint32(0), uint32(spent_block_index), False, TEST_TIMESTAMP)
|
|
2657
|
+
|
|
2658
|
+
|
|
2659
|
+
@dataclasses.dataclass
|
|
2660
|
+
class CheckRemovalsCase:
|
|
2661
|
+
id: str
|
|
2662
|
+
removals: dict[bytes32, CoinRecord]
|
|
2663
|
+
bundle_coin_spends: dict[bytes32, BundleCoinSpend] = dataclasses.field(default_factory=dict)
|
|
2664
|
+
conflicting_mempool_items: dict[bytes32, list[MempoolItem]] = dataclasses.field(default_factory=dict)
|
|
2665
|
+
expected_result: tuple[Optional[Err], list[MempoolItem]] = dataclasses.field(default_factory=lambda: (None, []))
|
|
2666
|
+
marks: Marks = ()
|
|
2667
|
+
|
|
2668
|
+
|
|
2669
|
+
@datacases(
|
|
2670
|
+
CheckRemovalsCase(
|
|
2671
|
+
id="No removals",
|
|
2672
|
+
removals={},
|
|
2673
|
+
expected_result=(None, []),
|
|
2674
|
+
),
|
|
2675
|
+
CheckRemovalsCase(
|
|
2676
|
+
id="Unspent removal, no mempool conflicts",
|
|
2677
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD},
|
|
2678
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN))},
|
|
2679
|
+
expected_result=(None, []),
|
|
2680
|
+
),
|
|
2681
|
+
CheckRemovalsCase(
|
|
2682
|
+
id="Already spent non FF coin",
|
|
2683
|
+
removals={TEST_COIN_ID: make_coin_record(TEST_COIN, spent_block_index=1)},
|
|
2684
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN))},
|
|
2685
|
+
expected_result=(Err.DOUBLE_SPEND, []),
|
|
2686
|
+
),
|
|
2687
|
+
CheckRemovalsCase(
|
|
2688
|
+
id="Already spent FF coin, no mempool conflicts",
|
|
2689
|
+
removals={TEST_COIN_ID: make_coin_record(TEST_COIN, spent_block_index=1)},
|
|
2690
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN), ELIGIBLE_FOR_FF)},
|
|
2691
|
+
expected_result=(None, []),
|
|
2692
|
+
),
|
|
2693
|
+
CheckRemovalsCase(
|
|
2694
|
+
id="FF coin, non FF mempool conflict",
|
|
2695
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD},
|
|
2696
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN), ELIGIBLE_FOR_FF)},
|
|
2697
|
+
conflicting_mempool_items={TEST_COIN_ID: [mk_item([TEST_COIN])]},
|
|
2698
|
+
expected_result=(Err.MEMPOOL_CONFLICT, [mk_item([TEST_COIN])]),
|
|
2699
|
+
),
|
|
2700
|
+
CheckRemovalsCase(
|
|
2701
|
+
id="Dedup coin, non dedup mempool conflict",
|
|
2702
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD},
|
|
2703
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN), ELIGIBLE_FOR_DEDUP)},
|
|
2704
|
+
conflicting_mempool_items={TEST_COIN_ID: [mk_item([TEST_COIN])]},
|
|
2705
|
+
expected_result=(Err.MEMPOOL_CONFLICT, [mk_item([TEST_COIN])]),
|
|
2706
|
+
),
|
|
2707
|
+
CheckRemovalsCase(
|
|
2708
|
+
id="FF coin, FF mempool conflict",
|
|
2709
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD},
|
|
2710
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN), ELIGIBLE_FOR_FF)},
|
|
2711
|
+
conflicting_mempool_items={TEST_COIN_ID: [mk_item([TEST_COIN], flags=[ELIGIBLE_FOR_FF])]},
|
|
2712
|
+
expected_result=(None, []),
|
|
2713
|
+
),
|
|
2714
|
+
CheckRemovalsCase(
|
|
2715
|
+
id="Dedup coin, Dedup mempool conflict",
|
|
2716
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD},
|
|
2717
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN), ELIGIBLE_FOR_DEDUP)},
|
|
2718
|
+
conflicting_mempool_items={TEST_COIN_ID: [mk_item([TEST_COIN], flags=[ELIGIBLE_FOR_DEDUP])]},
|
|
2719
|
+
expected_result=(None, []),
|
|
2720
|
+
),
|
|
2721
|
+
CheckRemovalsCase(
|
|
2722
|
+
id="Dedup coin, Dedup mempool conflict with different solution",
|
|
2723
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD},
|
|
2724
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN, solution="ff8080"), ELIGIBLE_FOR_DEDUP)},
|
|
2725
|
+
conflicting_mempool_items={TEST_COIN_ID: [mk_item([TEST_COIN], flags=[ELIGIBLE_FOR_DEDUP])]},
|
|
2726
|
+
expected_result=(
|
|
2727
|
+
Err.MEMPOOL_CONFLICT,
|
|
2728
|
+
[
|
|
2729
|
+
mk_item(
|
|
2730
|
+
[TEST_COIN],
|
|
2731
|
+
flags=[ELIGIBLE_FOR_DEDUP],
|
|
2732
|
+
)
|
|
2733
|
+
],
|
|
2734
|
+
),
|
|
2735
|
+
),
|
|
2736
|
+
CheckRemovalsCase(
|
|
2737
|
+
id="Regular coin, mempool conflict",
|
|
2738
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD},
|
|
2739
|
+
bundle_coin_spends={TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN))},
|
|
2740
|
+
conflicting_mempool_items={TEST_COIN_ID: [mk_item([TEST_COIN])]},
|
|
2741
|
+
expected_result=(Err.MEMPOOL_CONFLICT, [mk_item([TEST_COIN])]),
|
|
2742
|
+
),
|
|
2743
|
+
CheckRemovalsCase(
|
|
2744
|
+
id="Both FF and non FF coins, FF one conflicts with existing non FF",
|
|
2745
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD, TEST_COIN_ID2: TEST_COIN_RECORD2},
|
|
2746
|
+
bundle_coin_spends={
|
|
2747
|
+
TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN)),
|
|
2748
|
+
TEST_COIN_ID2: mk_bcs(mk_coin_spend(TEST_COIN2), ELIGIBLE_FOR_FF),
|
|
2749
|
+
},
|
|
2750
|
+
conflicting_mempool_items={TEST_COIN_ID: [mk_item([TEST_COIN])], TEST_COIN_ID2: [mk_item([TEST_COIN2])]},
|
|
2751
|
+
expected_result=(Err.MEMPOOL_CONFLICT, [mk_item([TEST_COIN]), mk_item([TEST_COIN2])]),
|
|
2752
|
+
),
|
|
2753
|
+
CheckRemovalsCase(
|
|
2754
|
+
id="Both FF and non FF coins, FF one conflicts with existing FF",
|
|
2755
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD, TEST_COIN_ID2: TEST_COIN_RECORD2},
|
|
2756
|
+
bundle_coin_spends={
|
|
2757
|
+
TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN)),
|
|
2758
|
+
TEST_COIN_ID2: mk_bcs(mk_coin_spend(TEST_COIN2), ELIGIBLE_FOR_FF),
|
|
2759
|
+
},
|
|
2760
|
+
conflicting_mempool_items={
|
|
2761
|
+
TEST_COIN_ID: [mk_item([TEST_COIN])],
|
|
2762
|
+
TEST_COIN_ID2: [mk_item([TEST_COIN2], flags=[ELIGIBLE_FOR_FF])],
|
|
2763
|
+
},
|
|
2764
|
+
expected_result=(Err.MEMPOOL_CONFLICT, [mk_item([TEST_COIN])]),
|
|
2765
|
+
),
|
|
2766
|
+
CheckRemovalsCase(
|
|
2767
|
+
id="Two FF coins, only one with non FF conflict",
|
|
2768
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD, TEST_COIN_ID2: TEST_COIN_RECORD2},
|
|
2769
|
+
bundle_coin_spends={
|
|
2770
|
+
TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN), ELIGIBLE_FOR_FF),
|
|
2771
|
+
TEST_COIN_ID2: mk_bcs(mk_coin_spend(TEST_COIN2), ELIGIBLE_FOR_FF),
|
|
2772
|
+
},
|
|
2773
|
+
conflicting_mempool_items={
|
|
2774
|
+
TEST_COIN_ID: [mk_item([TEST_COIN], flags=[ELIGIBLE_FOR_FF])],
|
|
2775
|
+
TEST_COIN_ID2: [mk_item([TEST_COIN2])],
|
|
2776
|
+
},
|
|
2777
|
+
expected_result=(Err.MEMPOOL_CONFLICT, [mk_item([TEST_COIN2])]),
|
|
2778
|
+
),
|
|
2779
|
+
CheckRemovalsCase(
|
|
2780
|
+
id="Conflicting items are added to conflicts only once",
|
|
2781
|
+
removals={TEST_COIN_ID: TEST_COIN_RECORD, TEST_COIN_ID2: TEST_COIN_RECORD2},
|
|
2782
|
+
bundle_coin_spends={
|
|
2783
|
+
TEST_COIN_ID: mk_bcs(mk_coin_spend(TEST_COIN)),
|
|
2784
|
+
TEST_COIN_ID2: mk_bcs(mk_coin_spend(TEST_COIN2)),
|
|
2785
|
+
},
|
|
2786
|
+
# Same item spends both coins
|
|
2787
|
+
conflicting_mempool_items={
|
|
2788
|
+
TEST_COIN_ID: [mk_item([TEST_COIN, TEST_COIN2])],
|
|
2789
|
+
TEST_COIN_ID2: [mk_item([TEST_COIN, TEST_COIN2])],
|
|
2790
|
+
},
|
|
2791
|
+
# Item should be added only once in conflicts
|
|
2792
|
+
expected_result=(Err.MEMPOOL_CONFLICT, [mk_item([TEST_COIN, TEST_COIN2])]),
|
|
2793
|
+
),
|
|
2794
|
+
)
|
|
2795
|
+
def test_check_removals(case: CheckRemovalsCase) -> None:
|
|
2796
|
+
def test_get_items_by_coin_ids(coin_ids: list[bytes32]) -> list[MempoolItem]:
|
|
2797
|
+
items = set()
|
|
2798
|
+
for coin_id in coin_ids:
|
|
2799
|
+
items.update(case.conflicting_mempool_items.get(coin_id, []))
|
|
2800
|
+
return list(items)
|
|
2801
|
+
|
|
2802
|
+
result = check_removals(
|
|
2803
|
+
bundle_coin_spends=case.bundle_coin_spends,
|
|
2804
|
+
removals=case.removals,
|
|
2805
|
+
get_items_by_coin_ids=test_get_items_by_coin_ids,
|
|
2806
|
+
)
|
|
2807
|
+
expected_err, expected_conflicts = case.expected_result
|
|
2808
|
+
err, conflicts = result
|
|
2809
|
+
assert err == expected_err
|
|
2810
|
+
assert len(conflicts) == len(expected_conflicts)
|
|
2811
|
+
assert set(conflicts) == set(expected_conflicts)
|
|
@@ -348,6 +348,64 @@ class TestNewPeak:
|
|
|
348
348
|
== new_peak.reward_chain_block.get_hash()
|
|
349
349
|
)
|
|
350
350
|
|
|
351
|
+
@pytest.mark.anyio
|
|
352
|
+
async def test_timelord_new_peak_node_sync(
|
|
353
|
+
self,
|
|
354
|
+
one_node: tuple[list[FullNodeService], list[FullNodeSimulator], BlockTools],
|
|
355
|
+
timelord: tuple[TimelordAPI, ChiaServer],
|
|
356
|
+
default_1000_blocks: list[FullBlock],
|
|
357
|
+
) -> None:
|
|
358
|
+
[full_node_service], _, bt = one_node
|
|
359
|
+
full_node = full_node_service._node
|
|
360
|
+
async with create_blockchain(bt.constants, 2) as (b1, _):
|
|
361
|
+
async with create_blockchain(bt.constants, 2) as (b2, _):
|
|
362
|
+
timelord_api, _ = timelord
|
|
363
|
+
for block in default_1000_blocks:
|
|
364
|
+
await _validate_and_add_block(b1, block)
|
|
365
|
+
await _validate_and_add_block(b2, block)
|
|
366
|
+
await full_node.add_block(block)
|
|
367
|
+
|
|
368
|
+
peak = timelord_peak_from_block(b1, default_1000_blocks[-1])
|
|
369
|
+
assert peak is not None
|
|
370
|
+
assert timelord_api.timelord.new_peak is None
|
|
371
|
+
await timelord_api.new_peak_timelord(peak)
|
|
372
|
+
assert timelord_api.timelord.new_peak is not None
|
|
373
|
+
assert (
|
|
374
|
+
timelord_api.timelord.new_peak.reward_chain_block.get_hash() == peak.reward_chain_block.get_hash()
|
|
375
|
+
)
|
|
376
|
+
await time_out_assert(60, peak_new_peak_is_none, True, timelord_api)
|
|
377
|
+
# make two new blocks on tip, block_2 has higher total iterations
|
|
378
|
+
block_1 = bt.get_consecutive_blocks(1, default_1000_blocks)[-1]
|
|
379
|
+
block_2 = bt.get_consecutive_blocks(
|
|
380
|
+
1, default_1000_blocks, min_signage_point=block_1.reward_chain_block.signage_point_index
|
|
381
|
+
)[-1]
|
|
382
|
+
assert block_2.weight == block_1.weight
|
|
383
|
+
# make sure block_2 has higher iterations then block_1
|
|
384
|
+
assert block_2.total_iters > block_1.total_iters
|
|
385
|
+
# make sure block_1 and block_2 have higher iterations then peak
|
|
386
|
+
assert block_1.total_iters > default_1000_blocks[-1].total_iters
|
|
387
|
+
await full_node.add_block(block_2)
|
|
388
|
+
await _validate_and_add_block(b1, block_2)
|
|
389
|
+
peak_tl = timelord_peak_from_block(b1, block_2)
|
|
390
|
+
peak = await full_node.blockchain.get_full_peak()
|
|
391
|
+
assert peak is not None
|
|
392
|
+
assert timelord_api.timelord.new_peak is None
|
|
393
|
+
await timelord_api.new_peak_timelord(peak_tl)
|
|
394
|
+
assert timelord_api.timelord.new_peak is not None
|
|
395
|
+
assert peak.header_hash == block_2.header_hash
|
|
396
|
+
assert peak_tl.reward_chain_block.get_hash() == peak.reward_chain_block.get_hash()
|
|
397
|
+
await time_out_assert(60, peak_new_peak_is_none, True, timelord_api)
|
|
398
|
+
|
|
399
|
+
await full_node.add_block(block_1)
|
|
400
|
+
await _validate_and_add_block(b1, block_1)
|
|
401
|
+
peak = timelord_peak_from_block(b1, block_1)
|
|
402
|
+
assert peak is not None
|
|
403
|
+
await timelord_api.new_peak_timelord(peak)
|
|
404
|
+
peak = await full_node.blockchain.get_full_peak()
|
|
405
|
+
assert peak == block_1
|
|
406
|
+
peak_tl = timelord_api.timelord.new_peak
|
|
407
|
+
assert peak_tl.reward_chain_block.get_hash() == peak.reward_chain_block.get_hash()
|
|
408
|
+
|
|
351
409
|
|
|
352
410
|
async def get_rc_prev(blockchain: Blockchain, block: FullBlock) -> bytes32:
|
|
353
411
|
if block.reward_chain_block.signage_point_index == 0:
|
chia/consensus/block_creation.py
CHANGED
|
@@ -54,7 +54,7 @@ def compute_block_cost(generator: BlockGenerator, constants: ConsensusConstants,
|
|
|
54
54
|
else:
|
|
55
55
|
run_block = run_block_generator
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
err, conds = run_block(
|
|
58
58
|
bytes(generator.program),
|
|
59
59
|
generator.generator_refs,
|
|
60
60
|
constants.MAX_BLOCK_COST_CLVM,
|
|
@@ -63,6 +63,8 @@ def compute_block_cost(generator: BlockGenerator, constants: ConsensusConstants,
|
|
|
63
63
|
None,
|
|
64
64
|
constants,
|
|
65
65
|
)
|
|
66
|
+
if conds is None: # pragma: no cover
|
|
67
|
+
log.error(f"unexpected error while computing block cost: {err} height: {height} generator: {generator.program}")
|
|
66
68
|
return uint64(0 if conds is None else conds.cost)
|
|
67
69
|
|
|
68
70
|
|
chia/full_node/full_node.py
CHANGED
|
@@ -2134,7 +2134,8 @@ class FullNode:
|
|
|
2134
2134
|
)
|
|
2135
2135
|
pre_validation_result = await future
|
|
2136
2136
|
added: Optional[AddBlockResult] = None
|
|
2137
|
-
|
|
2137
|
+
add_block_start = time.monotonic()
|
|
2138
|
+
pre_validation_time = add_block_start - validation_start
|
|
2138
2139
|
try:
|
|
2139
2140
|
if pre_validation_result.error is not None:
|
|
2140
2141
|
if Err(pre_validation_result.error) == Err.INVALID_PREV_BLOCK_HASH:
|
|
@@ -2153,6 +2154,7 @@ class FullNode:
|
|
|
2153
2154
|
(added, error_code, state_change_summary) = await self.blockchain.add_block(
|
|
2154
2155
|
block, pre_validation_result, ssi, fork_info
|
|
2155
2156
|
)
|
|
2157
|
+
add_block_time = time.monotonic() - add_block_start
|
|
2156
2158
|
if added == AddBlockResult.ALREADY_HAVE_BLOCK:
|
|
2157
2159
|
return None
|
|
2158
2160
|
elif added == AddBlockResult.INVALID_BLOCK:
|
|
@@ -2181,7 +2183,7 @@ class FullNode:
|
|
|
2181
2183
|
self.log.info(
|
|
2182
2184
|
f"Received orphan block of height {block.height} rh {block.reward_chain_block.get_hash()}"
|
|
2183
2185
|
)
|
|
2184
|
-
post_process_time = 0
|
|
2186
|
+
post_process_time = 0.0
|
|
2185
2187
|
else:
|
|
2186
2188
|
# Should never reach here, all the cases are covered
|
|
2187
2189
|
raise RuntimeError(f"Invalid result from add_block {added}")
|
|
@@ -2197,7 +2199,11 @@ class FullNode:
|
|
|
2197
2199
|
|
|
2198
2200
|
if ppp_result is not None:
|
|
2199
2201
|
assert state_change_summary is not None
|
|
2202
|
+
post_process_time2 = time.monotonic()
|
|
2200
2203
|
await self.peak_post_processing_2(block, peer, state_change_summary, ppp_result)
|
|
2204
|
+
post_process_time2 = time.monotonic() - post_process_time2
|
|
2205
|
+
else:
|
|
2206
|
+
post_process_time2 = 0.0
|
|
2201
2207
|
|
|
2202
2208
|
percent_full_str = (
|
|
2203
2209
|
(
|
|
@@ -2213,7 +2219,9 @@ class FullNode:
|
|
|
2213
2219
|
f"Block validation: {validation_time:0.2f}s, "
|
|
2214
2220
|
f"pre_validation: {pre_validation_time:0.2f}s, "
|
|
2215
2221
|
f"CLVM: {pre_validation_result.timing / 1000.0:0.2f}s, "
|
|
2222
|
+
f"add-block: {add_block_time:0.2f}s, "
|
|
2216
2223
|
f"post-process: {post_process_time:0.2f}s, "
|
|
2224
|
+
f"post-process2: {post_process_time2:0.2f}s, "
|
|
2217
2225
|
f"cost: {block.transactions_info.cost if block.transactions_info is not None else 'None'}"
|
|
2218
2226
|
f"{percent_full_str} header_hash: {header_hash.hex()} height: {block.height}",
|
|
2219
2227
|
)
|
|
@@ -2847,10 +2855,16 @@ class FullNode:
|
|
|
2847
2855
|
|
|
2848
2856
|
total_time = time.monotonic() - start_time
|
|
2849
2857
|
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2858
|
+
if len(peer_ids) == 0:
|
|
2859
|
+
self.log.log(
|
|
2860
|
+
logging.DEBUG if total_time < 0.5 else logging.WARNING,
|
|
2861
|
+
f"Looking up hints for {len(conds.spends)} spends took {total_time:.4f}s",
|
|
2862
|
+
)
|
|
2863
|
+
else:
|
|
2864
|
+
self.log.log(
|
|
2865
|
+
logging.DEBUG if total_time < 0.5 else logging.WARNING,
|
|
2866
|
+
f"Broadcasting added transaction {mempool_item.name} to {len(peer_ids)} peers took {total_time:.4f}s",
|
|
2867
|
+
)
|
|
2854
2868
|
|
|
2855
2869
|
async def broadcast_removed_tx(self, mempool_removals: list[MempoolRemoveInfo]) -> None:
|
|
2856
2870
|
total_removals = sum(len(r.items) for r in mempool_removals)
|
|
@@ -150,6 +150,143 @@ QUOTE_BYTES = 2
|
|
|
150
150
|
QUOTE_EXECUTION_COST = 20
|
|
151
151
|
|
|
152
152
|
|
|
153
|
+
def is_atom_canonical(clvm_buffer: bytes, offset: int) -> tuple[int, bool]:
|
|
154
|
+
b = clvm_buffer[offset]
|
|
155
|
+
if (b & 0b11000000) == 0b10000000:
|
|
156
|
+
# 6 bits length prefix
|
|
157
|
+
mask = 0b00111111
|
|
158
|
+
prefix_len = 0
|
|
159
|
+
min_value = 1
|
|
160
|
+
elif (b & 0b11100000) == 0b11000000:
|
|
161
|
+
# 5 + 8 bits length prefix
|
|
162
|
+
mask = 0b00011111
|
|
163
|
+
prefix_len = 1
|
|
164
|
+
min_value = 1 << 6
|
|
165
|
+
elif (b & 0b11110000) == 0b11100000:
|
|
166
|
+
# 4 + 8 + 8 bits length prefix
|
|
167
|
+
mask = 0b00001111
|
|
168
|
+
prefix_len = 2
|
|
169
|
+
min_value = 1 << (5 + 8)
|
|
170
|
+
elif (b & 0b11111000) == 0b11110000:
|
|
171
|
+
# 3 + 8 + 8 + 8 bits length prefix
|
|
172
|
+
mask = 0b00000111
|
|
173
|
+
prefix_len = 3
|
|
174
|
+
min_value = 1 << (4 + 8 + 8)
|
|
175
|
+
elif (b & 0b11111100) == 0b11111000:
|
|
176
|
+
# 2 + 8 + 8 + 8 + 8 bits length prefix
|
|
177
|
+
mask = 0b00000011
|
|
178
|
+
prefix_len = 4
|
|
179
|
+
min_value = 1 << (3 + 8 + 8 + 8)
|
|
180
|
+
elif (b & 0b11111110) == 0b11111100:
|
|
181
|
+
# 1 + 8 + 8 + 8 + 8 + 8 bits length prefix
|
|
182
|
+
mask = 0b00000001
|
|
183
|
+
prefix_len = 5
|
|
184
|
+
min_value = 1 << (2 + 8 + 8 + 8 + 8)
|
|
185
|
+
|
|
186
|
+
atom_len = b & mask
|
|
187
|
+
for i in range(prefix_len):
|
|
188
|
+
atom_len <<= 8
|
|
189
|
+
offset += 1
|
|
190
|
+
atom_len |= clvm_buffer[offset]
|
|
191
|
+
|
|
192
|
+
return 1 + prefix_len + atom_len, atom_len >= min_value
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def is_clvm_canonical(clvm_buffer: bytes) -> bool:
|
|
196
|
+
"""
|
|
197
|
+
checks whether the CLVM serialization is all canonical representation.
|
|
198
|
+
atoms can be serialized in more than one way by using more bytes than
|
|
199
|
+
necessary to encode the length prefix. This functions ensures that all atoms are
|
|
200
|
+
encoded with the shortest representation. back-references are not allowed
|
|
201
|
+
and will make this function return false
|
|
202
|
+
"""
|
|
203
|
+
assert clvm_buffer != b""
|
|
204
|
+
|
|
205
|
+
offset = 0
|
|
206
|
+
tokens_left = 1
|
|
207
|
+
while True:
|
|
208
|
+
b = clvm_buffer[offset]
|
|
209
|
+
|
|
210
|
+
# pair
|
|
211
|
+
if b == 0xFF:
|
|
212
|
+
tokens_left += 1
|
|
213
|
+
offset += 1
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
# back references cannot be considered canonical, since they may be
|
|
217
|
+
# encoded in many different ways
|
|
218
|
+
if b == 0xFE:
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
# small atom or NIL
|
|
222
|
+
if b <= 0x80:
|
|
223
|
+
tokens_left -= 1
|
|
224
|
+
offset += 1
|
|
225
|
+
else:
|
|
226
|
+
atom_len, canonical = is_atom_canonical(clvm_buffer, offset)
|
|
227
|
+
if not canonical:
|
|
228
|
+
return False
|
|
229
|
+
tokens_left -= 1
|
|
230
|
+
offset += atom_len
|
|
231
|
+
|
|
232
|
+
if tokens_left == 0:
|
|
233
|
+
break
|
|
234
|
+
|
|
235
|
+
# if there's garbage at the end, it's not canonical
|
|
236
|
+
return offset == len(clvm_buffer)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def check_removals(
|
|
240
|
+
removals: dict[bytes32, CoinRecord],
|
|
241
|
+
bundle_coin_spends: dict[bytes32, BundleCoinSpend],
|
|
242
|
+
*,
|
|
243
|
+
get_items_by_coin_ids: Callable[[list[bytes32]], list[MempoolItem]],
|
|
244
|
+
) -> tuple[Optional[Err], list[MempoolItem]]:
|
|
245
|
+
"""
|
|
246
|
+
This function checks for double spends, unknown spends and conflicting transactions in mempool.
|
|
247
|
+
Returns Error (if any), the set of existing MempoolItems with conflicting spends (if any).
|
|
248
|
+
Note that additions are not checked for duplicates, because having duplicate additions requires also
|
|
249
|
+
having duplicate removals.
|
|
250
|
+
"""
|
|
251
|
+
conflicts = set()
|
|
252
|
+
for coin_id, coin_bcs in bundle_coin_spends.items():
|
|
253
|
+
# 1. Checks if it's been spent already
|
|
254
|
+
if removals[coin_id].spent and not coin_bcs.eligible_for_fast_forward:
|
|
255
|
+
return Err.DOUBLE_SPEND, []
|
|
256
|
+
|
|
257
|
+
# 2. Checks if there's a mempool conflict
|
|
258
|
+
conflicting_items = get_items_by_coin_ids([coin_id])
|
|
259
|
+
for item in conflicting_items:
|
|
260
|
+
if item in conflicts:
|
|
261
|
+
continue
|
|
262
|
+
conflict_bcs = item.bundle_coin_spends[coin_id]
|
|
263
|
+
# if the spend we're adding to the mempool is not DEDUP nor FF, it's
|
|
264
|
+
# just a regular conflict
|
|
265
|
+
if not coin_bcs.eligible_for_fast_forward and not coin_bcs.eligible_for_dedup:
|
|
266
|
+
conflicts.add(item)
|
|
267
|
+
|
|
268
|
+
# if the spend we're adding is FF, but there's a conflicting spend
|
|
269
|
+
# that isn't FF, they can't be chained, so that's a conflict
|
|
270
|
+
elif coin_bcs.eligible_for_fast_forward and not conflict_bcs.eligible_for_fast_forward:
|
|
271
|
+
conflicts.add(item)
|
|
272
|
+
|
|
273
|
+
# if the spend we're adding is DEDUP, but there's a conflicting spend
|
|
274
|
+
# that isn't DEDUP, we cannot merge them, so that's a conflict
|
|
275
|
+
elif coin_bcs.eligible_for_dedup and not conflict_bcs.eligible_for_dedup:
|
|
276
|
+
conflicts.add(item)
|
|
277
|
+
|
|
278
|
+
# if the spend we're adding is DEDUP but the existing spend has a
|
|
279
|
+
# different solution, we cannot merge them, so that's a conflict
|
|
280
|
+
elif coin_bcs.eligible_for_dedup and bytes(coin_bcs.coin_spend.solution) != bytes(
|
|
281
|
+
conflict_bcs.coin_spend.solution
|
|
282
|
+
):
|
|
283
|
+
conflicts.add(item)
|
|
284
|
+
|
|
285
|
+
if len(conflicts) > 0:
|
|
286
|
+
return Err.MEMPOOL_CONFLICT, list(conflicts)
|
|
287
|
+
return None, []
|
|
288
|
+
|
|
289
|
+
|
|
153
290
|
class MempoolManager:
|
|
154
291
|
pool: Executor
|
|
155
292
|
constants: ConsensusConstants
|
|
@@ -462,7 +599,6 @@ class MempoolManager:
|
|
|
462
599
|
addition_amount: int = 0
|
|
463
600
|
# Map of coin ID to eligibility information
|
|
464
601
|
eligibility_and_additions: dict[bytes32, EligibilityAndAdditions] = {}
|
|
465
|
-
non_eligible_coin_ids: list[bytes32] = []
|
|
466
602
|
for spend in conds.spends:
|
|
467
603
|
coin_id = bytes32(spend.coin_id)
|
|
468
604
|
removal_names.add(coin_id)
|
|
@@ -480,7 +616,6 @@ class MempoolManager:
|
|
|
480
616
|
ff_puzzle_hash=bytes32(spend.puzzle_hash) if is_eligible_for_ff else None,
|
|
481
617
|
)
|
|
482
618
|
removal_names_from_coin_spends: set[bytes32] = set()
|
|
483
|
-
fast_forward_coin_ids: set[bytes32] = set()
|
|
484
619
|
bundle_coin_spends: dict[bytes32, BundleCoinSpend] = {}
|
|
485
620
|
for coin_spend in new_spend.coin_spends:
|
|
486
621
|
coin_id = coin_spend.coin.name()
|
|
@@ -489,6 +624,11 @@ class MempoolManager:
|
|
|
489
624
|
coin_id,
|
|
490
625
|
EligibilityAndAdditions(is_eligible_for_dedup=False, spend_additions=[], ff_puzzle_hash=None),
|
|
491
626
|
)
|
|
627
|
+
|
|
628
|
+
supports_dedup = eligibility_info.is_eligible_for_dedup
|
|
629
|
+
if supports_dedup and not is_clvm_canonical(bytes(coin_spend.solution)):
|
|
630
|
+
return Err.INVALID_COIN_SOLUTION, None, []
|
|
631
|
+
|
|
492
632
|
mark_as_fast_forward = eligibility_info.ff_puzzle_hash is not None and supports_fast_forward(coin_spend)
|
|
493
633
|
latest_singleton_coin = None
|
|
494
634
|
if mark_as_fast_forward:
|
|
@@ -500,13 +640,9 @@ class MempoolManager:
|
|
|
500
640
|
if lineage_info is None:
|
|
501
641
|
return Err.DOUBLE_SPEND, None, []
|
|
502
642
|
latest_singleton_coin = lineage_info.coin_id
|
|
503
|
-
fast_forward_coin_ids.add(coin_id)
|
|
504
|
-
# We are now able to check eligibility of both dedup and fast forward
|
|
505
|
-
if not (eligibility_info.is_eligible_for_dedup or mark_as_fast_forward):
|
|
506
|
-
non_eligible_coin_ids.append(coin_id)
|
|
507
643
|
bundle_coin_spends[coin_id] = BundleCoinSpend(
|
|
508
644
|
coin_spend=coin_spend,
|
|
509
|
-
eligible_for_dedup=
|
|
645
|
+
eligible_for_dedup=supports_dedup,
|
|
510
646
|
eligible_for_fast_forward=mark_as_fast_forward,
|
|
511
647
|
additions=eligibility_info.spend_additions,
|
|
512
648
|
latest_singleton_coin=latest_singleton_coin,
|
|
@@ -580,7 +716,9 @@ class MempoolManager:
|
|
|
580
716
|
|
|
581
717
|
# Check removals against UnspentDB + DiffStore + Mempool + SpendBundle
|
|
582
718
|
# Use this information later when constructing a block
|
|
583
|
-
fail_reason, conflicts =
|
|
719
|
+
fail_reason, conflicts = check_removals(
|
|
720
|
+
removal_record_dict, bundle_coin_spends, get_items_by_coin_ids=self.mempool.get_items_by_coin_ids
|
|
721
|
+
)
|
|
584
722
|
|
|
585
723
|
# If we have a mempool conflict, continue, since we still want to keep around the TX in the pending pool.
|
|
586
724
|
if fail_reason is not None and fail_reason is not Err.MEMPOOL_CONFLICT:
|
|
@@ -650,33 +788,6 @@ class MempoolManager:
|
|
|
650
788
|
|
|
651
789
|
return None, potential, [item.name for item in conflicts]
|
|
652
790
|
|
|
653
|
-
def check_removals(
|
|
654
|
-
self,
|
|
655
|
-
non_eligible_coin_ids: list[bytes32],
|
|
656
|
-
removals: dict[bytes32, CoinRecord],
|
|
657
|
-
fast_forward_coin_ids: set[bytes32],
|
|
658
|
-
) -> tuple[Optional[Err], list[MempoolItem]]:
|
|
659
|
-
"""
|
|
660
|
-
This function checks for double spends, unknown spends and conflicting transactions in mempool.
|
|
661
|
-
Returns Error (if any), the set of existing MempoolItems with conflicting spends (if any).
|
|
662
|
-
Note that additions are not checked for duplicates, because having duplicate additions requires also
|
|
663
|
-
having duplicate removals.
|
|
664
|
-
"""
|
|
665
|
-
assert self.peak is not None
|
|
666
|
-
# 1. Checks if it's been spent already
|
|
667
|
-
for record in removals.values():
|
|
668
|
-
if record.spent:
|
|
669
|
-
# Only consider it a double spend if this is not a fast forward
|
|
670
|
-
if record.name not in fast_forward_coin_ids:
|
|
671
|
-
return Err.DOUBLE_SPEND, []
|
|
672
|
-
# 2. Checks if there's a mempool conflict
|
|
673
|
-
# Only consider conflicts if the coin is not eligible for deduplication
|
|
674
|
-
conflicts = self.mempool.get_items_by_coin_ids(non_eligible_coin_ids)
|
|
675
|
-
if len(conflicts) > 0:
|
|
676
|
-
return Err.MEMPOOL_CONFLICT, conflicts
|
|
677
|
-
# 5. If coins can be spent return list of unspents as we see them in local storage
|
|
678
|
-
return None, []
|
|
679
|
-
|
|
680
791
|
def get_spendbundle(self, bundle_hash: bytes32) -> Optional[SpendBundle]:
|
|
681
792
|
"""Returns a full SpendBundle if it's inside one the mempools"""
|
|
682
793
|
item: Optional[MempoolItem] = self.mempool.get_item_by_id(bundle_hash)
|
|
@@ -721,6 +832,7 @@ class MempoolManager:
|
|
|
721
832
|
assert new_peak.timestamp is not None
|
|
722
833
|
self.fee_estimator.new_block_height(new_peak.height)
|
|
723
834
|
included_items: list[MempoolItemInfo] = []
|
|
835
|
+
new_peak_start = time.monotonic()
|
|
724
836
|
|
|
725
837
|
expired = self.mempool.new_tx_block(new_peak.height, new_peak.timestamp)
|
|
726
838
|
mempool_item_removals: list[MempoolRemoveInfo] = [expired]
|
|
@@ -887,6 +999,8 @@ class MempoolManager:
|
|
|
887
999
|
f"minimum fee rate (in FPC) to get in for 5M cost tx: {self.mempool.get_min_fee_rate(5000000)}"
|
|
888
1000
|
)
|
|
889
1001
|
self.mempool.fee_estimator.new_block(FeeBlockInfo(new_peak.height, included_items))
|
|
1002
|
+
duration = time.monotonic() - new_peak_start
|
|
1003
|
+
log.log(logging.WARNING if duration > 1 else logging.INFO, f"new_peak() took {duration:0.2f} seconds")
|
|
890
1004
|
return NewPeakInfo(txs_added, mempool_item_removals)
|
|
891
1005
|
|
|
892
1006
|
def get_items_not_in_filter(self, mempool_filter: PyBIP158, limit: int = 100) -> list[SpendBundle]:
|
chia/harvester/harvester_api.py
CHANGED
|
@@ -88,7 +88,7 @@ class HarvesterAPI:
|
|
|
88
88
|
f"sp_hash: {new_challenge.sp_hash}, signage_point_index: {new_challenge.signage_point_index}"
|
|
89
89
|
)
|
|
90
90
|
|
|
91
|
-
start = time.
|
|
91
|
+
start = time.monotonic()
|
|
92
92
|
assert len(new_challenge.challenge_hash) == 32
|
|
93
93
|
|
|
94
94
|
loop = asyncio.get_running_loop()
|
|
@@ -254,11 +254,11 @@ class HarvesterAPI:
|
|
|
254
254
|
self.harvester.log.debug(f"new_signage_point_harvester {passed} plots passed the plot filter")
|
|
255
255
|
|
|
256
256
|
# Concurrently executes all lookups on disk, to take advantage of multiple disk parallelism
|
|
257
|
-
time_taken = time.
|
|
257
|
+
time_taken = time.monotonic() - start
|
|
258
258
|
total_proofs_found = 0
|
|
259
259
|
for filename_sublist_awaitable in asyncio.as_completed(awaitables):
|
|
260
260
|
filename, sublist = await filename_sublist_awaitable
|
|
261
|
-
time_taken = time.
|
|
261
|
+
time_taken = time.monotonic() - start
|
|
262
262
|
if time_taken > 8:
|
|
263
263
|
self.harvester.log.warning(
|
|
264
264
|
f"Looking up qualities on {filename} took: {time_taken}. This should be below 8 seconds"
|
chia/simulator/block_tools.py
CHANGED
|
@@ -19,7 +19,6 @@ from typing import Any, Callable, Optional
|
|
|
19
19
|
import anyio
|
|
20
20
|
from chia_puzzles_py.programs import CHIALISP_DESERIALISATION, ROM_BOOTSTRAP_GENERATOR
|
|
21
21
|
from chia_rs import (
|
|
22
|
-
MEMPOOL_MODE,
|
|
23
22
|
AugSchemeMPL,
|
|
24
23
|
ConsensusConstants,
|
|
25
24
|
G1Element,
|
|
@@ -75,7 +74,7 @@ from chia.simulator.wallet_tools import WalletTool
|
|
|
75
74
|
from chia.ssl.create_ssl import create_all_ssl
|
|
76
75
|
from chia.types.blockchain_format.classgroup import ClassgroupElement
|
|
77
76
|
from chia.types.blockchain_format.coin import Coin
|
|
78
|
-
from chia.types.blockchain_format.program import INFINITE_COST, Program
|
|
77
|
+
from chia.types.blockchain_format.program import DEFAULT_FLAGS, INFINITE_COST, Program
|
|
79
78
|
from chia.types.blockchain_format.proof_of_space import (
|
|
80
79
|
ProofOfSpace,
|
|
81
80
|
calculate_pos_challenge,
|
|
@@ -1951,7 +1950,7 @@ def compute_cost_test(generator: BlockGenerator, constants: ConsensusConstants,
|
|
|
1951
1950
|
|
|
1952
1951
|
if height >= constants.HARD_FORK_HEIGHT:
|
|
1953
1952
|
blocks = generator.generator_refs
|
|
1954
|
-
cost, result = generator.program._run(INFINITE_COST,
|
|
1953
|
+
cost, result = generator.program._run(INFINITE_COST, DEFAULT_FLAGS, [DESERIALIZE_MOD, blocks])
|
|
1955
1954
|
clvm_cost += cost
|
|
1956
1955
|
|
|
1957
1956
|
for spend in result.first().as_iter():
|
|
@@ -1960,13 +1959,13 @@ def compute_cost_test(generator: BlockGenerator, constants: ConsensusConstants,
|
|
|
1960
1959
|
puzzle = spend.at("rf")
|
|
1961
1960
|
solution = spend.at("rrrf")
|
|
1962
1961
|
|
|
1963
|
-
cost, result = puzzle._run(INFINITE_COST,
|
|
1962
|
+
cost, result = puzzle._run(INFINITE_COST, DEFAULT_FLAGS, solution)
|
|
1964
1963
|
clvm_cost += cost
|
|
1965
1964
|
condition_cost += conditions_cost(result)
|
|
1966
1965
|
|
|
1967
1966
|
else:
|
|
1968
1967
|
block_program_args = SerializedProgram.to([generator.generator_refs])
|
|
1969
|
-
clvm_cost, result = GENERATOR_MOD._run(INFINITE_COST,
|
|
1968
|
+
clvm_cost, result = GENERATOR_MOD._run(INFINITE_COST, DEFAULT_FLAGS, [generator.program, block_program_args])
|
|
1970
1969
|
|
|
1971
1970
|
for res in result.first().as_iter():
|
|
1972
1971
|
# each condition item is:
|
chia/timelord/timelord_api.py
CHANGED
|
@@ -53,6 +53,22 @@ class TimelordAPI:
|
|
|
53
53
|
self.timelord.state_changed("new_peak", {"height": new_peak.reward_chain_block.height})
|
|
54
54
|
return
|
|
55
55
|
|
|
56
|
+
# new peak has equal weight but lower iterations
|
|
57
|
+
if (
|
|
58
|
+
self.timelord.last_state.get_weight() == new_peak.reward_chain_block.weight
|
|
59
|
+
and self.timelord.last_state.peak.reward_chain_block.total_iters
|
|
60
|
+
> new_peak.reward_chain_block.total_iters
|
|
61
|
+
):
|
|
62
|
+
log.info(
|
|
63
|
+
"Not skipping peak, has equal weight but lower iterations,"
|
|
64
|
+
f"current peak:{self.timelord.last_state.total_iters} new peak "
|
|
65
|
+
f"{new_peak.reward_chain_block.total_iters}"
|
|
66
|
+
)
|
|
67
|
+
self.timelord.new_peak = new_peak
|
|
68
|
+
self.timelord.state_changed("new_peak", {"height": new_peak.reward_chain_block.height})
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
# new peak is heavier
|
|
56
72
|
if self.timelord.last_state.get_weight() < new_peak.reward_chain_block.weight:
|
|
57
73
|
# if there is an unfinished block with less iterations, skip so we dont orphan it
|
|
58
74
|
if (
|
|
@@ -63,9 +79,9 @@ class TimelordAPI:
|
|
|
63
79
|
self.timelord.state_changed("skipping_peak", {"height": new_peak.reward_chain_block.height})
|
|
64
80
|
return
|
|
65
81
|
|
|
66
|
-
log.info("Not skipping peak, don't have. Maybe we are not the fastest timelord")
|
|
67
82
|
log.info(
|
|
68
|
-
|
|
83
|
+
"Not skipping peak, don't have. Maybe we are not the fastest timelord "
|
|
84
|
+
f"height: {new_peak.reward_chain_block.height} weight:"
|
|
69
85
|
f"{new_peak.reward_chain_block.weight} "
|
|
70
86
|
)
|
|
71
87
|
self.timelord.new_peak = new_peak
|
|
@@ -75,9 +91,9 @@ class TimelordAPI:
|
|
|
75
91
|
if self.timelord.last_state.peak.reward_chain_block.get_hash() == new_peak.reward_chain_block.get_hash():
|
|
76
92
|
log.info("Skipping peak, already have.")
|
|
77
93
|
else:
|
|
78
|
-
log.info(
|
|
79
|
-
|
|
80
|
-
f"
|
|
94
|
+
log.info(
|
|
95
|
+
f"Skipping peak height {new_peak.reward_chain_block.height} "
|
|
96
|
+
f"weight {new_peak.reward_chain_block.weight}"
|
|
81
97
|
)
|
|
82
98
|
|
|
83
99
|
self.timelord.state_changed("skipping_peak", {"height": new_peak.reward_chain_block.height})
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import io
|
|
4
4
|
from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar
|
|
5
5
|
|
|
6
|
-
from chia_rs import MEMPOOL_MODE, run_chia_program, tree_hash
|
|
6
|
+
from chia_rs import ENABLE_KECCAK, MEMPOOL_MODE, run_chia_program, tree_hash
|
|
7
7
|
from chia_rs.sized_bytes import bytes32
|
|
8
8
|
from clvm.casts import int_from_bytes
|
|
9
9
|
from clvm.CLVMObject import CLVMStorage
|
|
@@ -17,7 +17,7 @@ from chia.util.hash import std_hash
|
|
|
17
17
|
|
|
18
18
|
INFINITE_COST = 11000000000
|
|
19
19
|
|
|
20
|
-
DEFAULT_FLAGS = MEMPOOL_MODE
|
|
20
|
+
DEFAULT_FLAGS = MEMPOOL_MODE | ENABLE_KECCAK
|
|
21
21
|
|
|
22
22
|
T_CLVMStorage = TypeVar("T_CLVMStorage", bound=CLVMStorage)
|
|
23
23
|
T_Program = TypeVar("T_Program", bound="Program")
|
|
@@ -122,7 +122,7 @@ chia/_tests/core/mempool/test_mempool.py,sha256=_3ydxbt-LfIiju-4PW6qgvRSpvaHL7Gq
|
|
|
122
122
|
chia/_tests/core/mempool/test_mempool_fee_estimator.py,sha256=lZZiTy-zOfrxuIWoQRnk_JLV9OJzuFqQwKwOgMwh3dQ,3714
|
|
123
123
|
chia/_tests/core/mempool/test_mempool_fee_protocol.py,sha256=XUTKqs82IOiiZMGPTPSRhB4Zp8clbus5GlOoUtPtL6A,2165
|
|
124
124
|
chia/_tests/core/mempool/test_mempool_item_queries.py,sha256=BESoQXx8XG2jSJiE12nslC3y_vPWrfCWPCrv4tGl3Js,7027
|
|
125
|
-
chia/_tests/core/mempool/test_mempool_manager.py,sha256=
|
|
125
|
+
chia/_tests/core/mempool/test_mempool_manager.py,sha256=KZCXRegcVxT6OUnXuOypJealnnLRZ6Dom4NxIWHH0lI,126728
|
|
126
126
|
chia/_tests/core/mempool/test_mempool_performance.py,sha256=guLnMgE37swiQuyEXYPmtmMOXSa7o_fwBlXGHsOM4rU,2808
|
|
127
127
|
chia/_tests/core/mempool/test_singleton_fast_forward.py,sha256=egp-7n5GCMlFebzwanQwPjOE24efhDBCvVrKEuEkQVU,38019
|
|
128
128
|
chia/_tests/core/node_height.py,sha256=yfkEmmYCsAb3cIe1ZhtE9J2SFB9lG_49SgjxsITdrZk,917
|
|
@@ -237,7 +237,7 @@ chia/_tests/simulation/test_start_simulator.py,sha256=geCu_RMFuFlu1oaurcvubzwENY
|
|
|
237
237
|
chia/_tests/testconfig.py,sha256=zLhG3F8aayQR34gLclQDmDfSsXu9GEaYpCuL4RteZpg,431
|
|
238
238
|
chia/_tests/timelord/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
239
239
|
chia/_tests/timelord/config.py,sha256=fTDhByaME5cEDbtyTKCWUf69F4kajs75aTQewZMjxak,69
|
|
240
|
-
chia/_tests/timelord/test_new_peak.py,sha256=
|
|
240
|
+
chia/_tests/timelord/test_new_peak.py,sha256=qvRlrJ6V6-DjSDmx_P6CUU6BByonHiWU97hJh_f17es,25238
|
|
241
241
|
chia/_tests/timelord/test_timelord.py,sha256=5v8AbvHMws2AsoWW-K6e2dS3oy3j4PW4SN4VJnjASMM,298
|
|
242
242
|
chia/_tests/tools/1315537.json,sha256=lT_jyWxuxw9B3Wc1Akr80l6y2RhVAtY8DW4zlfik-iE,19256
|
|
243
243
|
chia/_tests/tools/1315544.json,sha256=8_dMCtu8nPPvR2KK5iqRd-Vit-VCb5dmYsjOtFWtIXA,19163
|
|
@@ -448,7 +448,7 @@ chia/cmds/wallet.py,sha256=KQiT86fmZrycAopFMUCD_-PWy0Hzpv0FHh9bE944clM,60888
|
|
|
448
448
|
chia/cmds/wallet_funcs.py,sha256=A3LBfELVgdEKBFa1Z4ciVa4gRCVEvekKfCYPeJ9kbGQ,77227
|
|
449
449
|
chia/consensus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
450
450
|
chia/consensus/block_body_validation.py,sha256=OQ2w7beihGMDyocYNcRBrvtoqk6sAG29E4BhWOaJZPk,24230
|
|
451
|
-
chia/consensus/block_creation.py,sha256=
|
|
451
|
+
chia/consensus/block_creation.py,sha256=IZwnY6v3RkTdrUHXbBJXdVV1jFx9XsuI1i5LynqJJ38,21987
|
|
452
452
|
chia/consensus/block_header_validation.py,sha256=bM9R4z6Z4OLmViD4yYh2yFn-aNbFEtThjWkYq93EzUc,51035
|
|
453
453
|
chia/consensus/block_record.py,sha256=hL-UP7_Jnuebc4ano1daBMcZCB3mtcHfabOsso3hMRU,670
|
|
454
454
|
chia/consensus/block_rewards.py,sha256=vmdHKqYudVnKvzq-ALAsSpy4RsTPLhdw-giJkwecdkM,2250
|
|
@@ -513,14 +513,14 @@ chia/full_node/fee_estimator_constants.py,sha256=GsQfI9Z7YzPWGEe6ghJeYvzbG87C86K
|
|
|
513
513
|
chia/full_node/fee_estimator_interface.py,sha256=y6ICUB_69vkF2whcKFlN8lhmM3bR88yRTJb8e2ThG6M,1610
|
|
514
514
|
chia/full_node/fee_history.py,sha256=hcLmy3HLuuATidOQ94wD7MAtzZU9PadKaKt8q3m8fVI,591
|
|
515
515
|
chia/full_node/fee_tracker.py,sha256=vgJbP-zfaeL8tYToZxKm3JoBy5LWog6rD28FHycDBvQ,22626
|
|
516
|
-
chia/full_node/full_node.py,sha256=
|
|
516
|
+
chia/full_node/full_node.py,sha256=fQwPCTVSmnYD36KR85QP6O4HOrdlhYlRtArMLScfXD8,167030
|
|
517
517
|
chia/full_node/full_node_api.py,sha256=h9TbahfJ3P8tdSI76jfo683dV6Hwnkxj6C5Ckdo-Wgg,96840
|
|
518
518
|
chia/full_node/full_node_store.py,sha256=1YGBgdS1Kim5FHbv-IMIegKkRRj8Hbqj55X1se7Du_8,47369
|
|
519
519
|
chia/full_node/hint_management.py,sha256=8dVKguFPm-h32GEnMWxX2qyITo4WVO1YBKaPFKCeni0,2285
|
|
520
520
|
chia/full_node/hint_store.py,sha256=0m6y0_f0rhGIKqfAmhFSGEeyM3LCN-dv-bR1OfIr4Uo,3666
|
|
521
521
|
chia/full_node/mempool.py,sha256=VK323fsHtnbn_zQMqE7dcBAf37_4K7X_wfYLmjvLK6c,28150
|
|
522
522
|
chia/full_node/mempool_check_conditions.py,sha256=r_NXwXH5nLvO-YbhcZozrMIYOdHqyMRyDzBCVoIX1QA,5606
|
|
523
|
-
chia/full_node/mempool_manager.py,sha256=
|
|
523
|
+
chia/full_node/mempool_manager.py,sha256=YIqhNc-IuELYaODSuEeIGAgxuGGK1VepB98ehF-lBtM,50170
|
|
524
524
|
chia/full_node/pending_tx_cache.py,sha256=jEL004L7r1n7ppeSdLVe6nsVNfYw0jU86DHmRYe1rH4,3657
|
|
525
525
|
chia/full_node/signage_point.py,sha256=vtHQk3P0HLfOVpenGqmgqBoWnf_WCETHRplL_id9KyA,414
|
|
526
526
|
chia/full_node/subscriptions.py,sha256=ItPMnGTgrfdzoeyC5TBbamrVWKvYnpabSLYUDBI5bmI,8706
|
|
@@ -530,7 +530,7 @@ chia/full_node/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
530
530
|
chia/full_node/weight_proof.py,sha256=oa-xC0Pzt-VZlFCvFYwZ5ZqlHiWzmUe1id8eEiVv6oE,71403
|
|
531
531
|
chia/harvester/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
532
532
|
chia/harvester/harvester.py,sha256=u2_trZnVRdsXGmuqfivA05aD2qjJjv2DNOyejLh8KAw,11825
|
|
533
|
-
chia/harvester/harvester_api.py,sha256
|
|
533
|
+
chia/harvester/harvester_api.py,sha256=-lzphxuk28fag82kpqLHmzhVrc441ForV6dDOja-zLo,18726
|
|
534
534
|
chia/introducer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
535
535
|
chia/introducer/introducer.py,sha256=InaxWLt8EprM7409cg2y03Qwm_641nLbnv6-sAjBp1Q,5535
|
|
536
536
|
chia/introducer/introducer_api.py,sha256=VB1V0geTzVVi8UMdqUxqYt_fdFjUcATM8fjd-nMJnN8,2779
|
|
@@ -623,7 +623,7 @@ chia/server/upnp.py,sha256=o9zrYEBMFjnMq2-vUu7e5trPCP6JDPhn_5_jlQZX8f8,3746
|
|
|
623
623
|
chia/server/ws_connection.py,sha256=6OM8xd0zb8RPtTqF0RRQ_UKLJjLHbRUov7BlszZsLvk,33801
|
|
624
624
|
chia/simulator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
625
625
|
chia/simulator/add_blocks_in_batches.py,sha256=YrQDNKkdrR9gaO0BDN_uSfycZWYQ2wZjw0FTxmmscmY,2460
|
|
626
|
-
chia/simulator/block_tools.py,sha256=
|
|
626
|
+
chia/simulator/block_tools.py,sha256=w3HawvkcKcNLYKetFZIXxLAZHlN0lBDa7yvMfcBDQeM,90747
|
|
627
627
|
chia/simulator/full_node_simulator.py,sha256=W-n6DemccWw42yws2PBtpkAw6G5JQvtCJ9K_EnmK7fg,34758
|
|
628
628
|
chia/simulator/keyring.py,sha256=RcumEHJy51zKeK0MZr7iqlugF8vPNRJvXDzXUgQ3y2A,5067
|
|
629
629
|
chia/simulator/setup_services.py,sha256=16ivXZM2iUfo9-6F0l-E0JHuOP00b15vQ4F-NwurhyY,19255
|
|
@@ -653,7 +653,7 @@ chia/ssl/dst_root_ca.pem,sha256=E5peSk4PpQU3jHLF9wCTTOgzP05rG1CIhsSw6xT0vpk,1200
|
|
|
653
653
|
chia/timelord/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
654
654
|
chia/timelord/iters_from_block.py,sha256=cN9bSrcL5_4zO330o-MykOW3hqJpoALXeGa_YZqTku4,1721
|
|
655
655
|
chia/timelord/timelord.py,sha256=ChQidb48mV72XsNn-olApar-ME4Ma99Dqgf3biD_hiY,59990
|
|
656
|
-
chia/timelord/timelord_api.py,sha256=
|
|
656
|
+
chia/timelord/timelord_api.py,sha256=14iD1CZt0ltXa5GNigo7KB0Ac8cD_z7HAlOhhm2srgA,7475
|
|
657
657
|
chia/timelord/timelord_launcher.py,sha256=pgSYZd4-WxDJ7Mq92F7mUSuZfpGIzCpVJ4JdI9UTu04,6239
|
|
658
658
|
chia/timelord/timelord_state.py,sha256=XLk5ITk1_sKG0SMq4X2J9ejLWSJNmvVAdKhWucrIt90,12022
|
|
659
659
|
chia/timelord/types.py,sha256=FC5jywOnZvuWZmmM7Kr_O7UaZZLRSFI4WMZuzT-tZAg,354
|
|
@@ -663,7 +663,7 @@ chia/types/block_protocol.py,sha256=gXXp3tC8E-__sjC9ZkDzPxw085OifROeT7UuYBl3OcM,
|
|
|
663
663
|
chia/types/blockchain_format/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
664
664
|
chia/types/blockchain_format/classgroup.py,sha256=H4s9BO1lBroha6IAS96VUFPLKVy4dr8D8EXWhUFP0l8,107
|
|
665
665
|
chia/types/blockchain_format/coin.py,sha256=n5uynipkU-N0c7vIJAxsbkO2V_zSA2R1LiiNkOqtl0Q,672
|
|
666
|
-
chia/types/blockchain_format/program.py,sha256=
|
|
666
|
+
chia/types/blockchain_format/program.py,sha256=3JLAEzFg0EXj1vTuj4LqPXSzY1vnWbYwGAvQj2jMtjs,9559
|
|
667
667
|
chia/types/blockchain_format/proof_of_space.py,sha256=EyRb5dvFY4Uf4uIn03mOhoVfHmt9r_KdMu3xurSBPp8,4946
|
|
668
668
|
chia/types/blockchain_format/serialized_program.py,sha256=4pN6DiiLOx3CfXILguFbJCtDOkIKcRrTA8GWfuUU0pY,88
|
|
669
669
|
chia/types/blockchain_format/slots.py,sha256=te3s0DCBR9XnFJMgzz1e3KahR2zX95noKj0bei_-67g,308
|
|
@@ -884,8 +884,8 @@ chia/wallet/wallet_transaction_store.py,sha256=PoSJLKuNNx0X8KVSQ92C5zGKIbBBDtPVW
|
|
|
884
884
|
chia/wallet/wallet_user_store.py,sha256=rXiQpk5g8t1X0Chx0bValcQsHonjB1oQ_F_K16bphDA,4089
|
|
885
885
|
chia/wallet/wallet_weight_proof_handler.py,sha256=d3UvjSP5X2gVIephBR9grutvYRC58Vr-HnV1ezJXrJ8,4914
|
|
886
886
|
mozilla-ca/cacert.pem,sha256=UKYnfsaRE_AMX9RfCei5eks-MtqjXTqVqzATelU4bO8,233263
|
|
887
|
-
chia_blockchain-2.5.
|
|
888
|
-
chia_blockchain-2.5.
|
|
889
|
-
chia_blockchain-2.5.
|
|
890
|
-
chia_blockchain-2.5.
|
|
891
|
-
chia_blockchain-2.5.
|
|
887
|
+
chia_blockchain-2.5.4rc1.dist-info/LICENSE,sha256=0tuU-jTzeRDJJaxF2YCEpBwbywgpbrVSXq1i6fJq63U,11347
|
|
888
|
+
chia_blockchain-2.5.4rc1.dist-info/METADATA,sha256=qWftsOSNM2yhNHLtgjKRed9qbLgCvj2_nitjClANJBI,10673
|
|
889
|
+
chia_blockchain-2.5.4rc1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
890
|
+
chia_blockchain-2.5.4rc1.dist-info/entry_points.txt,sha256=GL2-UvicPVdKz72IP4shnmV3XImfoD5pMzoURfoAYk4,742
|
|
891
|
+
chia_blockchain-2.5.4rc1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|