Skip to content

Commit

Permalink
Port VC lifecycle tests to WalletTestFramework (#16292)
Browse files Browse the repository at this point in the history
  • Loading branch information
Quexington authored Nov 3, 2023
1 parent c2b3500 commit bf4cdf2
Show file tree
Hide file tree
Showing 7 changed files with 538 additions and 257 deletions.
28 changes: 28 additions & 0 deletions chia/simulator/full_node_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,34 @@ async def wait_transaction_records_entered_mempool(

await asyncio.sleep(backoff)

async def wait_transaction_records_marked_as_in_mempool(
self,
record_ids: Collection[bytes32],
wallet_node: WalletNode,
timeout: Union[None, float] = 10,
) -> None:
"""Wait until the transaction records have been marked that they have made it into the mempool. Transaction
records with no spend bundle are ignored.
Arguments:
records: The transaction records to wait for.
"""
with anyio.fail_after(delay=adjusted_timeout(timeout)):
ids_to_check: Set[bytes32] = set(record_ids)

for backoff in backoff_times():
found = set()
for txid in ids_to_check:
tx = await wallet_node.wallet_state_manager.tx_store.get_transaction_record(txid)
if tx is not None and (tx.is_in_mempool() or tx.spend_bundle is None):
found.add(txid)
ids_to_check = ids_to_check.difference(found)

if len(ids_to_check) == 0:
return

await asyncio.sleep(backoff)

async def process_transaction_records(
self,
records: Collection[TransactionRecord],
Expand Down
6 changes: 3 additions & 3 deletions chia/wallet/did_wallet/did_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ async def transfer_did(
sent_to=[],
trade_id=None,
type=uint32(TransactionType.OUTGOING_TX.value),
name=bytes32.secret(),
name=spend_bundle.name(),
memos=list(compute_memos(spend_bundle).items()),
valid_times=parse_timelock_info(extra_conditions),
)
Expand Down Expand Up @@ -1319,15 +1319,15 @@ async def generate_new_decentralised_id(
to_puzzle_hash=await self.standard_wallet.get_puzzle_hash(False),
fee_amount=fee,
confirmed=False,
sent=uint32(10),
sent=uint32(0),
spend_bundle=full_spend,
additions=full_spend.additions(),
removals=full_spend.removals(),
wallet_id=self.id(),
sent_to=[],
trade_id=None,
type=uint32(TransactionType.INCOMING_TX.value),
name=bytes32.secret(),
name=full_spend.name(),
memos=[],
valid_times=ConditionValidTimes(),
)
Expand Down
5 changes: 2 additions & 3 deletions chia/wallet/transaction_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,10 @@ class TransactionRecordOld(Streamable):
memos: List[Tuple[bytes32, List[bytes]]]

def is_in_mempool(self) -> bool:
# If one of the nodes we sent it to responded with success, we set it to success
# If one of the nodes we sent it to responded with success or pending, we return True
for _, mis, _ in self.sent_to:
if MempoolInclusionStatus(mis) == MempoolInclusionStatus.SUCCESS:
if MempoolInclusionStatus(mis) in (MempoolInclusionStatus.SUCCESS, MempoolInclusionStatus.PENDING):
return True
# Note, transactions pending inclusion (pending) return false
return False

def height_farmed(self, genesis_challenge: bytes32) -> Optional[uint32]:
Expand Down
19 changes: 13 additions & 6 deletions chia/wallet/vc_wallet/cr_cat_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,8 @@ async def generate_signed_transaction(
unsigned_spend_bundle.coin_spends
)

other_tx_removals: Set[Coin] = {removal for tx in other_txs for removal in tx.removals}
other_tx_additions: Set[Coin] = {removal for tx in other_txs for removal in tx.additions}
tx_list = [
TransactionRecord(
confirmed_at_height=uint32(0),
Expand All @@ -693,8 +695,8 @@ async def generate_signed_transaction(
confirmed=False,
sent=uint32(0),
spend_bundle=signed_spend_bundle if i == 0 else None,
additions=signed_spend_bundle.additions() if i == 0 else [],
removals=signed_spend_bundle.removals() if i == 0 else [],
additions=list(set(signed_spend_bundle.additions()) - other_tx_additions) if i == 0 else [],
removals=list(set(signed_spend_bundle.removals()) - other_tx_removals) if i == 0 else [],
wallet_id=self.id(),
sent_to=[],
trade_id=None,
Expand Down Expand Up @@ -814,6 +816,12 @@ async def claim_pending_approval_balance(
[claim_bundle, *(tx.spend_bundle for tx in vc_txs if tx.spend_bundle is not None)]
)

other_txs: List[TransactionRecord] = [
*(dataclasses.replace(tx, spend_bundle=None) for tx in vc_txs),
*((dataclasses.replace(chia_tx, spend_bundle=None),) if chia_tx is not None else []),
]
other_additions: Set[Coin] = {rem for tx in other_txs for rem in tx.additions}
other_removals: Set[Coin] = {rem for tx in other_txs for rem in tx.removals}
return [
TransactionRecord(
confirmed_at_height=uint32(0),
Expand All @@ -824,8 +832,8 @@ async def claim_pending_approval_balance(
confirmed=False,
sent=uint32(0),
spend_bundle=claim_bundle,
additions=claim_bundle.additions(),
removals=claim_bundle.removals(),
additions=list(set(claim_bundle.additions()) - other_additions),
removals=list(set(claim_bundle.removals()) - other_removals),
wallet_id=self.id(),
sent_to=[],
trade_id=None,
Expand All @@ -834,8 +842,7 @@ async def claim_pending_approval_balance(
memos=list(compute_memos(claim_bundle).items()),
valid_times=parse_timelock_info(extra_conditions),
),
*(dataclasses.replace(tx, spend_bundle=None) for tx in vc_txs),
*((dataclasses.replace(chia_tx, spend_bundle=None),) if chia_tx is not None else []),
*other_txs,
]

async def match_puzzle_info(self, puzzle_driver: PuzzleInfo) -> bool:
Expand Down
11 changes: 5 additions & 6 deletions chia/wallet/vc_wallet/vc_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,13 @@ async def generate_signed_transaction(
raise ValueError(
f"Cannot find the required DID {vc_record.vc.proof_provider.hex()}."
) # pragma: no cover
add_list: List[Coin] = list(spend_bundles[0].additions())
rem_list: List[Coin] = list(spend_bundles[0].removals())
if chia_tx is not None and chia_tx.spend_bundle is not None:
spend_bundles.append(chia_tx.spend_bundle)
tx_list.append(dataclasses.replace(chia_tx, spend_bundle=None))
spend_bundle = SpendBundle.aggregate(spend_bundles)
now = uint64(int(time.time()))
add_list: List[Coin] = list(spend_bundle.additions())
rem_list: List[Coin] = list(spend_bundle.removals())
tx_list.append(
TransactionRecord(
confirmed_at_height=uint32(0),
Expand Down Expand Up @@ -422,16 +422,15 @@ async def revoke_vc(
)
assert did_tx.spend_bundle is not None
final_bundle: SpendBundle = SpendBundle.aggregate([SpendBundle([vc_spend], G2Element()), did_tx.spend_bundle])
did_tx = dataclasses.replace(did_tx, spend_bundle=final_bundle)
did_tx = dataclasses.replace(did_tx, spend_bundle=final_bundle, name=final_bundle.name())
if fee > 0:
chia_tx: TransactionRecord = await self.wallet_state_manager.main_wallet.create_tandem_xch_tx(
fee, tx_config, vc_announcement
)
assert did_tx.spend_bundle is not None
assert chia_tx.spend_bundle is not None
did_tx = dataclasses.replace(
did_tx, spend_bundle=SpendBundle.aggregate([chia_tx.spend_bundle, did_tx.spend_bundle])
)
new_bundle = SpendBundle.aggregate([chia_tx.spend_bundle, did_tx.spend_bundle])
did_tx = dataclasses.replace(did_tx, spend_bundle=new_bundle, name=new_bundle.name())
chia_tx = dataclasses.replace(chia_tx, spend_bundle=None)
return [did_tx, chia_tx]
else:
Expand Down
23 changes: 16 additions & 7 deletions tests/wallet/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,19 +236,27 @@ async def process_pending_states(self, state_transitions: List[WalletStateTransi
puzzle_hash_indexes.append(ph_indexes)

# Gather all pending transactions and ensure they enter mempool
pending_txs: List[List[TransactionRecord]] = []
for env in self.environments:
pending_txs.append(await env.wallet_state_manager.tx_store.get_all_unconfirmed())
pending_txs: List[List[TransactionRecord]] = [
await env.wallet_state_manager.tx_store.get_all_unconfirmed() for env in self.environments
]
await self.full_node.wait_transaction_records_entered_mempool([tx for txs in pending_txs for tx in txs])
for local_pending_txs, (i, env) in zip(pending_txs, enumerate(self.environments)):
try:
await self.full_node.wait_transaction_records_marked_as_in_mempool(
[tx.name for tx in local_pending_txs], env.wallet_node
)
except TimeoutError: # pragma: no cover
raise ValueError(f"All tx records from env index {i} were not marked correctly with `.is_in_mempool()`")

# Check balances prior to block
try:
for env in self.environments:
await self.full_node.wait_for_wallet_synced(wallet_node=env.wallet_node, timeout=20)
for i, (env, transition) in enumerate(zip(self.environments, state_transitions)):
try:
await env.change_balances(transition.pre_block_balance_updates)
await env.check_balances(transition.pre_block_additional_balance_info)
async with env.wallet_state_manager.db_wrapper.reader_no_transaction():
await env.change_balances(transition.pre_block_balance_updates)
await env.check_balances(transition.pre_block_additional_balance_info)
except Exception:
raise ValueError(f"Error with env index {i}")
except Exception:
Expand All @@ -263,8 +271,9 @@ async def process_pending_states(self, state_transitions: List[WalletStateTransi
await self.full_node.wait_for_wallet_synced(wallet_node=env.wallet_node, timeout=20)
for i, (env, transition) in enumerate(zip(self.environments, state_transitions)):
try:
await env.change_balances(transition.post_block_balance_updates)
await env.check_balances(transition.post_block_additional_balance_info)
async with env.wallet_state_manager.db_wrapper.reader_no_transaction():
await env.change_balances(transition.post_block_balance_updates)
await env.check_balances(transition.post_block_additional_balance_info)
except Exception:
raise ValueError(f"Error with env {i}")
except Exception:
Expand Down
Loading

0 comments on commit bf4cdf2

Please sign in to comment.