94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Unit test: wasabi-0002 TransactionFactory AllowedInputs O(C*A) -> O(C) HashSet"""
|
|
|
|
import sys
|
|
|
|
class FakeOutPoint:
|
|
def __init__(self, hash_, n):
|
|
self.hash = hash_
|
|
self.n = n
|
|
def __eq__(self, other):
|
|
return self.hash == other.hash and self.n == other.n
|
|
def __hash__(self):
|
|
return hash((self.hash, self.n))
|
|
|
|
class FakeCoin:
|
|
def __init__(self, txid, index, script, confirmed=True):
|
|
self.txid = txid
|
|
self.index = index
|
|
self.script = script
|
|
self.confirmed = confirmed
|
|
self.outpoint = FakeOutPoint(txid, index)
|
|
|
|
def defective_filter(coins, allowed_inputs):
|
|
"""Defective: List.Any for AllowedInputs check"""
|
|
comps = 0
|
|
result = []
|
|
for x in coins:
|
|
found = False
|
|
for y in allowed_inputs:
|
|
comps += 1
|
|
if y.hash == x.txid and y.n == x.index:
|
|
found = True
|
|
break
|
|
if found:
|
|
result.append(x)
|
|
return result, comps
|
|
|
|
def patched_filter(coins, allowed_inputs):
|
|
"""Patched: HashSet for AllowedInputs check"""
|
|
comps = 0
|
|
allowed_set = set(allowed_inputs)
|
|
result = []
|
|
for x in coins:
|
|
comps += 1
|
|
if x.outpoint in allowed_set:
|
|
result.append(x)
|
|
return result, comps
|
|
|
|
passed = 0
|
|
failed = 0
|
|
|
|
# Test 1: Correctness
|
|
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(100)]
|
|
allowed = [FakeOutPoint(i * 2, 0) for i in range(50)]
|
|
d, _ = defective_filter(coins, allowed)
|
|
p, _ = patched_filter(coins, allowed)
|
|
if [c.txid for c in d] == [c.txid for c in p] and len(d) == 50:
|
|
print("PASS test1_correctness: identical filter results"); passed += 1
|
|
else:
|
|
print("FAIL test1_correctness"); failed += 1
|
|
|
|
# Test 2: Performance C=500, A=50
|
|
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(500)]
|
|
allowed = [FakeOutPoint(i * 10, 0) for i in range(50)]
|
|
_, dc = defective_filter(coins, allowed)
|
|
_, pc = patched_filter(coins, allowed)
|
|
ratio = dc / max(pc, 1)
|
|
print(f" C=500 A=50: defective={dc} patched={pc} ratio={ratio:.1f}x")
|
|
if ratio > 10.0:
|
|
print("PASS test2_perf: >10x fewer comparisons"); passed += 1
|
|
else:
|
|
print(f"FAIL test2_perf: ratio {ratio:.1f}x not >10x"); failed += 1
|
|
|
|
# Test 3: Empty allowed returns empty
|
|
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(10)]
|
|
d, _ = defective_filter(coins, [])
|
|
p, _ = patched_filter(coins, [])
|
|
if len(d) == 0 and len(p) == 0:
|
|
print("PASS test3_empty_allowed: returns empty"); passed += 1
|
|
else:
|
|
print("FAIL test3_empty_allowed"); failed += 1
|
|
|
|
# Test 4: All coins allowed
|
|
coins = [FakeCoin(i, 0, f"script_{i}") for i in range(20)]
|
|
allowed = [c.outpoint for c in coins]
|
|
d, _ = defective_filter(coins, allowed)
|
|
p, _ = patched_filter(coins, allowed)
|
|
if len(d) == 20 and len(p) == 20:
|
|
print("PASS test4_all_allowed: all coins pass"); passed += 1
|
|
else:
|
|
print("FAIL test4_all_allowed"); failed += 1
|
|
|
|
print(f"\n{passed}/{passed + failed} tests passed")
|
|
sys.exit(1 if failed > 0 else 0)
|