-
Notifications
You must be signed in to change notification settings - Fork 11
/
test_main.py
122 lines (93 loc) · 3.72 KB
/
test_main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import json
from pathlib import Path
import pytest
from bitcoin.core import CTransaction, COIN
from rpc import JSONRPCError
from main import (
VaultScenario,
generateblocks,
get_standard_template_hash,
)
def test_functional():
"""Run functional test. Requires bitcoind -regtest running."""
_run_functional_test(ends_in_hot=True)
_run_functional_test(ends_in_hot=False)
def _run_functional_test(ends_in_hot=True):
"""
Exercise the full lifecycle of a vault.
Args:
ends_in_hot: if true, the to-hot unvault txn is ultimately confirmed. Otherwise
we preempt and sweep to cold.
"""
block_delay = 3
c = VaultScenario.from_network("regtest", seed=b"functest", block_delay=block_delay)
exec = c.exec
plan = c.plan
rpc = c.rpc
coin = c.coin_in
initial_amount = coin.amount
expected_amount_per_step = [
initial_amount, # before vaulting
initial_amount - (plan.fees_per_step * 1), # step 1: vaulted output
initial_amount - (plan.fees_per_step * 2), # step 2: unvaulted output
initial_amount - (plan.fees_per_step * 3), # step 3: spent to hot or cold
]
def check_amount(txid, n, expected_amount):
got_amt = (rpc.gettxout(txid, n) or {}).get('value', 0)
assert int(got_amt * COIN) == expected_amount
vaulted_txid = exec.send_to_vault(coin, c.from_wallet.privkey)
assert not exec.search_for_unvault()
check_amount(vaulted_txid, 0, expected_amount_per_step[1])
tocold_tx = exec.get_tocold_tx()
tocold_hex = tocold_tx.serialize().hex()
tohot_tx = exec.get_tohot_tx(c.hot_wallet.privkey)
tohot_hex = tohot_tx.serialize().hex()
# Shouldn't be able to send particular unvault txs yet.
with pytest.raises(JSONRPCError):
rpc.sendrawtransaction(tocold_hex)
with pytest.raises(JSONRPCError):
rpc.sendrawtransaction(tohot_hex)
unvaulted_txid = exec.start_unvault()
assert exec.search_for_unvault() == "mempool"
check_amount(unvaulted_txid, 0, expected_amount_per_step[2])
check_amount(vaulted_txid, 0, 0)
with pytest.raises(JSONRPCError):
# to-hot should fail due to OP_CSV
rpc.sendrawtransaction(tohot_hex)
# Unvault tx confirms
generateblocks(rpc, 1)
assert exec.search_for_unvault() == "chain"
with pytest.raises(JSONRPCError):
# to-hot should *still* fail due to OP_CSV
rpc.sendrawtransaction(tohot_hex)
if ends_in_hot:
# Mine enough blocks to allow the to-hot to be valid, send it.
generateblocks(rpc, block_delay - 1)
txid = rpc.sendrawtransaction(tohot_hex)
assert txid == tohot_tx.GetTxid()[::-1].hex()
else:
# "Sweep" the funds to the cold wallet because this is an unvaulting
# we didn't expect.
txid = rpc.sendrawtransaction(tocold_hex)
assert txid == tocold_tx.GetTxid()[::-1].hex()
generateblocks(rpc, 1)
txout = rpc.gettxout(txid, 0)
assert txout["confirmations"] == 1
check_amount(txid, 0, expected_amount_per_step[3])
check_amount(vaulted_txid, 0, 0)
check_amount(unvaulted_txid, 0, 0)
anchor_txout = rpc.gettxout(txid, 1)
print(anchor_txout)
fees_addr = plan.fees_pubkey.p2wpkh_address(rpc.net_name)
assert anchor_txout['value'] > 0
assert anchor_txout['scriptPubKey']['address'] == fees_addr
def test_ctv_hash():
data = json.loads(Path("ctvhash-test-vectors.json").read_bytes())[1:-1]
tests = 0
for case in data:
tx = CTransaction.deserialize(bytearray.fromhex(case["hex_tx"]))
for idx, res in zip(case["spend_index"], case["result"]):
assert get_standard_template_hash(tx, idx).hex() == res
tests += 1
print(tests)
assert tests > 0