Skip to content

Commit a1eb20a

Browse files
authored
Mempool fix - Merge pull request #200 from Chia-Network/mempool_fix
Mempool fix
2 parents c01338b + 5ce203e commit a1eb20a

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

src/full_node/mempool_manager.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ async def add_spendbundle(
155155
if v > 1:
156156
return None, MempoolInclusionStatus.FAILED, Err.DUPLICATE_OUTPUT
157157

158+
# Check for duplicate inputs
159+
removal_counter = collections.Counter(name for name in removal_names)
160+
for k, v in removal_counter.items():
161+
if v > 1:
162+
return None, MempoolInclusionStatus.FAILED, Err.DOUBLE_SPEND
163+
158164
# Spend might be valid for one pool but not for other
159165
added_count = 0
160166
errors: List[Err] = []
@@ -333,16 +339,10 @@ async def check_removals(
333339
This function checks for double spends, unknown spends and conflicting transactions in mempool.
334340
Returns Error (if any), dictionary of Unspents, list of coins with conflict errors (if any any).
335341
"""
336-
removals_counter: Dict[bytes32, int] = {}
337342
conflicts: List[Coin] = []
343+
338344
for record in removals.values():
339345
removal = record.coin
340-
# 0. Checks for double spend inside same spend_bundle
341-
if not removal.name() in removals_counter:
342-
removals_counter[removal.name()] = 1
343-
else:
344-
return Err.DOUBLE_SPEND, []
345-
346346
# 1. Checks if it's been spent already
347347
if record.spent == 1:
348348
return Err.DOUBLE_SPEND, []

tests/full_node/test_mempool.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,3 +844,47 @@ async def test_stealing_fee(self, two_nodes):
844844
)
845845

846846
assert mempool_bundle is None
847+
848+
@pytest.mark.asyncio
849+
async def test_double_spend_same_bundle(self, two_nodes):
850+
num_blocks = 2
851+
wallet_a = WalletTool()
852+
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
853+
wallet_receiver = WalletTool()
854+
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
855+
856+
blocks = bt.get_consecutive_blocks(
857+
test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash
858+
)
859+
full_node_1, full_node_2, server_1, server_2 = two_nodes
860+
861+
block = blocks[1]
862+
async for _ in full_node_1.respond_block(
863+
full_node_protocol.RespondBlock(block)
864+
):
865+
pass
866+
867+
spend_bundle1 = wallet_a.generate_signed_transaction(
868+
1000, receiver_puzzlehash, block.header.data.coinbase
869+
)
870+
871+
assert spend_bundle1 is not None
872+
873+
other_receiver = WalletTool()
874+
spend_bundle2 = wallet_a.generate_signed_transaction(
875+
1000, other_receiver.get_new_puzzlehash(), block.header.data.coinbase
876+
)
877+
878+
assert spend_bundle2 is not None
879+
880+
spend_bundle_combined = SpendBundle.aggregate([spend_bundle1, spend_bundle2])
881+
882+
tx: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
883+
spend_bundle_combined
884+
)
885+
messages = []
886+
async for outbound in full_node_1.respond_transaction(tx):
887+
messages.append(outbound)
888+
889+
sb = full_node_1.mempool_manager.get_spendbundle(spend_bundle_combined.name())
890+
assert sb is None

0 commit comments

Comments
 (0)