mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
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>
This commit is contained in:
parent
3b91a6f7c3
commit
0543149b89
@ -1,4 +1,3 @@
|
||||
from decimal import Decimal
|
||||
from fixtures import * # noqa: F401,F403
|
||||
from flaky import flaky # noqa: F401
|
||||
from lightning import RpcError
|
||||
@ -360,184 +359,6 @@ def test_bech32_funding(node_factory):
|
||||
assert only_one(fundingtx['vin'])['txid'] == res['wallettxid']
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
def test_io_logging(node_factory, executor):
|
||||
l1 = node_factory.get_node(options={'log-level': 'io'})
|
||||
l2 = node_factory.get_node()
|
||||
|
186
tests/test_wallet.py
Normal file
186
tests/test_wallet.py
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user