forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pytest: move wallet tests into new file tests/test_wallet.py
We're going to add some more. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
- Loading branch information
1 parent
3b91a6f
commit 0543149
Showing
2 changed files
with
186 additions
and
179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
from decimal import Decimal | ||
from fixtures import * # noqa: F401,F403 | ||
from flaky import flaky # noqa: F401 | ||
from lightning import RpcError | ||
from utils import only_one, wait_for | ||
|
||
import pytest | ||
import time | ||
|
||
|
||
def test_withdraw(node_factory, bitcoind): | ||
amount = 1000000 | ||
# Don't get any funds from previous runs. | ||
l1 = node_factory.get_node(random_hsm=True) | ||
l2 = node_factory.get_node(random_hsm=True) | ||
addr = l1.rpc.newaddr()['bech32'] | ||
|
||
# Add some funds to withdraw later | ||
for i in range(10): | ||
l1.bitcoin.rpc.sendtoaddress(addr, amount / 10**8 + 0.01) | ||
|
||
bitcoind.generate_block(1) | ||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 10) | ||
|
||
# Reach around into the db to check that outputs were added | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=0')[0]['c'] == 10 | ||
|
||
waddr = l1.bitcoin.rpc.getnewaddress() | ||
# Now attempt to withdraw some (making sure we collect multiple inputs) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('not an address', amount) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw(waddr, 'not an amount') | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw(waddr, -amount) | ||
with pytest.raises(RpcError, match=r'Cannot afford transaction'): | ||
l1.rpc.withdraw(waddr, amount * 100) | ||
|
||
out = l1.rpc.withdraw(waddr, 2 * amount) | ||
|
||
# Make sure bitcoind received the withdrawal | ||
unspent = l1.bitcoin.rpc.listunspent(0) | ||
withdrawal = [u for u in unspent if u['txid'] == out['txid']] | ||
|
||
assert(withdrawal[0]['amount'] == Decimal('0.02')) | ||
|
||
# Now make sure two of them were marked as spent | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 2 | ||
|
||
# Now send some money to l2. | ||
# lightningd uses P2SH-P2WPKH | ||
waddr = l2.rpc.newaddr('bech32')['bech32'] | ||
l1.rpc.withdraw(waddr, 2 * amount) | ||
bitcoind.generate_block(1) | ||
|
||
# Make sure l2 received the withdrawal. | ||
wait_for(lambda: len(l2.rpc.listfunds()['outputs']) == 1) | ||
outputs = l2.db_query('SELECT value FROM outputs WHERE status=0;') | ||
assert only_one(outputs)['value'] == 2 * amount | ||
|
||
# Now make sure an additional two of them were marked as spent | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 4 | ||
|
||
# Simple test for withdrawal to P2WPKH | ||
# Address from: https://bc-2.jp/tools/bech32demo/index.html | ||
waddr = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080' | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('xx1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx', 2 * amount) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('tb1pw508d6qejxtdg4y5r3zarvary0c5xw7kdl9fad', 2 * amount) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxxxxxx', 2 * amount) | ||
l1.rpc.withdraw(waddr, 2 * amount) | ||
bitcoind.generate_block(1) | ||
# Now make sure additional two of them were marked as spent | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 6 | ||
|
||
# Simple test for withdrawal to P2WSH | ||
# Address from: https://bc-2.jp/tools/bech32demo/index.html | ||
waddr = 'bcrt1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qzf4jry' | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('xx1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7', 2 * amount) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qsm03tq', 2 * amount) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qxxxxxx', 2 * amount) | ||
l1.rpc.withdraw(waddr, 2 * amount) | ||
bitcoind.generate_block(1) | ||
# Now make sure additional two of them were marked as spent | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=2')[0]['c'] == 8 | ||
|
||
# failure testing for invalid SegWit addresses, from BIP173 | ||
# HRP character out of range | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw(' 1nwldj5', 2 * amount) | ||
# overall max length exceeded | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx', 2 * amount) | ||
# No separator character | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('pzry9x0s0muk', 2 * amount) | ||
# Empty HRP | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('1pzry9x0s0muk', 2 * amount) | ||
# Invalid witness version | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2', 2 * amount) | ||
# Invalid program length for witness version 0 (per BIP141) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P', 2 * amount) | ||
# Mixed case | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7', 2 * amount) | ||
# Non-zero padding in 8-to-5 conversion | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv', 2 * amount) | ||
|
||
# Should have 6 outputs available. | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=0')[0]['c'] == 6 | ||
|
||
# Test withdrawal to self. | ||
l1.rpc.withdraw(l1.rpc.newaddr('bech32')['bech32'], 'all', minconf=0) | ||
bitcoind.generate_block(1) | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=0')[0]['c'] == 1 | ||
|
||
l1.rpc.withdraw(waddr, 'all', minconf=0) | ||
assert l1.db_query('SELECT COUNT(*) as c FROM outputs WHERE status=0')[0]['c'] == 0 | ||
|
||
# This should fail, can't even afford fee. | ||
with pytest.raises(RpcError, match=r'Cannot afford transaction'): | ||
l1.rpc.withdraw(waddr, 'all') | ||
|
||
|
||
def test_minconf_withdraw(node_factory, bitcoind): | ||
"""Issue 2518: ensure that ridiculous confirmation levels don't overflow | ||
The number of confirmations is used to compute a maximum height that is to | ||
be accepted. If the current height is smaller than the number of | ||
confirmations we wrap around and just select everything. The fix is to | ||
clamp the maxheight parameter to a positive small number. | ||
""" | ||
amount = 1000000 | ||
# Don't get any funds from previous runs. | ||
l1 = node_factory.get_node(random_hsm=True) | ||
addr = l1.rpc.newaddr()['bech32'] | ||
|
||
# Add some funds to withdraw later | ||
for i in range(10): | ||
l1.bitcoin.rpc.sendtoaddress(addr, amount / 10**8 + 0.01) | ||
|
||
bitcoind.generate_block(1) | ||
|
||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 10) | ||
with pytest.raises(RpcError): | ||
l1.rpc.withdraw(destination=addr, satoshi=10000, feerate='normal', minconf=9999999) | ||
|
||
|
||
def test_addfunds_from_block(node_factory, bitcoind): | ||
"""Send funds to the daemon without telling it explicitly | ||
""" | ||
# Previous runs with same bitcoind can leave funds! | ||
l1 = node_factory.get_node(random_hsm=True) | ||
|
||
addr = l1.rpc.newaddr()['bech32'] | ||
bitcoind.rpc.sendtoaddress(addr, 0.1) | ||
bitcoind.generate_block(1) | ||
|
||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 1) | ||
|
||
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;') | ||
assert only_one(outputs)['value'] == 10000000 | ||
|
||
# The address we detect must match what was paid to. | ||
output = only_one(l1.rpc.listfunds()['outputs']) | ||
assert output['address'] == addr | ||
|
||
# Send all our money to a P2WPKH address this time. | ||
addr = l1.rpc.newaddr("bech32")['bech32'] | ||
l1.rpc.withdraw(addr, "all") | ||
bitcoind.generate_block(1) | ||
time.sleep(1) | ||
|
||
# The address we detect must match what was paid to. | ||
output = only_one(l1.rpc.listfunds()['outputs']) | ||
assert output['address'] == addr |